From 50b49c1b760489c3430fc382656d57c5fbbab07c Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期一, 29 四月 2024 16:07:24 +0800
Subject: [PATCH] 2024-04-29

---
 src/templates/zshare/modalform/index.jsx                                           |    9 
 src/tabviews/custom/components/iframe/index.scss                                   |    1 
 src/tabviews/custom/components/editor/braft-editor/index.jsx                       |   31 
 src/tabviews/zshare/actionList/tabbutton/index.scss                                |   18 
 src/tabviews/zshare/settingcomponent/index.jsx                                     |    8 
 src/templates/zshare/verifycard/customscript/index.jsx                             |   64 
 src/tabviews/custom/popview/index.jsx                                              |   52 
 src/views/systemfunc/header/index.jsx                                              |    9 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx  |    2 
 src/tabviews/zshare/actionList/shareLink/index.jsx                                 |   30 
 src/tabviews/zshare/mutilform/mkNumberInput/index.jsx                              |   10 
 src/tabviews/zshare/actionList/changeuserbutton/index.jsx                          |   27 
 src/menu/components/table/edit-table/columns/tableIn/index.scss                    |    4 
 src/menu/datasource/verifycard/index.jsx                                           |   51 
 src/assets/css/main.scss                                                           |   17 
 src/menu/components/card/table-card/index.scss                                     |    1 
 src/components/header/index.scss                                                   |   35 
 src/tabviews/custom/components/module/invoice/subTable/index.scss                  |    0 
 src/views/interface/header/index.jsx                                               |    4 
 src/menu/components/card/cardcellcomponent/index.jsx                               |   71 
 src/menu/components/form/tab-form/index.jsx                                        |    2 
 src/tabviews/custom/components/module/invoice/invoiceTable/index.jsx               |  420 ++
 src/menu/components/search/main-search/dragsearch/card.jsx                         |    4 
 src/tabviews/zshare/actionList/funcMegvii/index.jsx                                |   33 
 src/menu/components/card/cardcomponent/index.jsx                                   |  128 
 src/templates/sharecomponent/actioncomponent/verifymegvii/index.scss               |    5 
 src/tabviews/custom/components/chart/antv-X6/index.jsx                             |   92 
 src/menu/components/card/prop-card/index.jsx                                       |    7 
 src/templates/zshare/customscript/index.jsx                                        |    2 
 src/menu/components/module/voucher/voucherTable/index.scss                         |    3 
 src/menu/datasource/verifycard/utils.jsx                                           |    4 
 src/tabviews/custom/components/chart/antv-bar-line/index.jsx                       |   30 
 src/assets/css/viewstyle.scss                                                      |   10 
 src/tabviews/custom/components/chart/antv-dashboard/index.jsx                      |   30 
 src/views/login/loginform.jsx                                                      |    9 
 src/menu/components/module/invoice/verifycard/baseform/index.scss                  |    0 
 src/menu/datasource/verifycard/index.scss                                          |    5 
 src/tabviews/zshare/topSearch/index.jsx                                            |   68 
 src/menu/components/card/prop-card/index.scss                                      |    2 
 src/menu/components/card/doublecardcomponent/index.scss                            |   13 
 src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx                   |    4 
 src/menu/components/card/cardsimplecomponent/options.jsx                           |    8 
 src/menu/components/form/simple-form/index.jsx                                     |    2 
 src/tabviews/custom/components/table/edit-table/index.jsx                          |   35 
 src/api/index.js                                                                   |    4 
 src/tabviews/zshare/topSearch/index.scss                                           |    7 
 src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx                 |   17 
 src/tabviews/custom/components/iframe/index.jsx                                    |   29 
 src/menu/components/table/base-table/columns/editColumn/index.jsx                  |    2 
 src/menu/components/share/searchcomponent/index.scss                               |   11 
 src/tabviews/zshare/tablenodes/index.jsx                                           |    6 
 src/views/pcdesign/index.jsx                                                       |   12 
 src/menu/datasource/verifycard/settingform/index.jsx                               |   15 
 src/views/systemfunc/sidemenu/index.jsx                                            |    4 
 src/menu/components/share/actioncomponent/index.jsx                                |   17 
 src/menu/components/card/cardsimplecomponent/index.jsx                             |  107 
 src/tabviews/custom/components/module/account/index.scss                           |    3 
 src/tabviews/custom/components/form/step-form/index.jsx                            |   29 
 src/views/appmanage/header/index.jsx                                               |    7 
 src/tabviews/custom/components/tree/antd-tree/index.jsx                            |  124 
 src/tabviews/zshare/actionList/popupbutton/index.jsx                               |   36 
 src/tabviews/zshare/normalTable/index.jsx                                          |    7 
 src/menu/components/share/searchcomponent/index.jsx                                |   10 
 src/views/mkiframe/index.jsx                                                       |   28 
 src/tabviews/custom/components/group/normal-group/index.scss                       |  103 
 src/tabviews/zshare/automatic/index.jsx                                            |    6 
 src/menu/components/module/voucher/index.jsx                                       |   23 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx              |    6 
 src/menu/components/tree/antd-tree/index.jsx                                       |   24 
 src/views/billprint/index.jsx                                                      |   39 
 src/tabviews/subtabtable/index.jsx                                                 |   20 
 src/tabviews/zshare/actionList/normalbutton/index.jsx                              |   87 
 src/menu/header/index.jsx                                                          |    6 
 src/assets/img/wx-icon.png                                                         |    0 
 src/views/menudesign/index.jsx                                                     |   18 
 src/menu/modulesource/option.jsx                                                   |    2 
 src/tabviews/custom/components/card/data-card/index.jsx                            |   90 
 src/menu/components/module/invoice/options.jsx                                     |   81 
 src/tabviews/custom/components/module/voucher/index.jsx                            |  301 +
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx                  |    2 
 src/templates/zshare/pasteform/index.jsx                                           |    2 
 src/menu/components/card/doublecardcomponent/index.jsx                             |  128 
 src/menu/components/card/data-card/index.jsx                                       |   15 
 src/menu/components/card/cardcellcomponent/elementform/index.scss                  |    9 
 src/menu/components/carousel/data-card/index.scss                                  |    2 
 src/menu/components/search/main-search/options.jsx                                 |   15 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss             |    9 
 src/tabviews/zshare/actionList/index.scss                                          |   13 
 src/components/tabview/index.scss                                                  |   12 
 src/templates/sharecomponent/actioncomponent/formconfig.jsx                        |    2 
 src/menu/components/table/normal-table/options.jsx                                 |  110 
 src/menu/components/tree/antd-tree/index.scss                                      |   10 
 src/components/header/index.jsx                                                    |   35 
 src/tabviews/custom/components/card/double-data-card/index.jsx                     |   50 
 src/templates/zshare/verifycard/callbackcustomscript/index.jsx                     |    2 
 src/mob/components/topbar/normal-navbar/options.jsx                                |    2 
 src/tabviews/custom/components/carousel/data-card/index.jsx                        |   30 
 src/components/normalform/modalform/mkTable/index.jsx                              |    4 
 src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx       |  294 +
 src/tabviews/custom/components/tree/antd-tree/index.scss                           |   54 
 src/tabviews/custom/components/chart/custom-chart/index.jsx                        |   30 
 src/tabviews/zshare/actionList/tabbutton/index.jsx                                 |  157 
 src/components/normalform/modalform/index.jsx                                      |   11 
 src/menu/stylecontroller/index.jsx                                                 |   99 
 src/menu/components/table/base-table/options.jsx                                   |   61 
 src/tabviews/custom/components/module/voucher/voucherTable/index.scss              |    3 
 src/templates/zshare/verifycard/index.jsx                                          |    4 
 src/menu/modulecell/index.jsx                                                      |    1 
 src/tabviews/zshare/actionList/printbutton/index.jsx                               |   40 
 src/tabviews/custom/components/table/edit-table/normalTable/index.scss             |    8 
 src/menu/components/card/cardcellcomponent/formconfig.jsx                          |  133 
 src/tabviews/custom/components/module/invoice/subTable/index.jsx                   |  250 +
 src/tabviews/custom/components/module/voucher/index.scss                           |   71 
 src/components/normalform/modalform/mkTable/index.scss                             |   17 
 src/menu/components/module/voucher/index.scss                                      |   47 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx   |   18 
 src/mob/header/index.jsx                                                           |    7 
 src/menu/components/tree/antd-tree/options.jsx                                     |   25 
 src/tabviews/custom/components/module/voucher/resetRemark/index.jsx                |    4 
 src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx               |  170 
 src/menu/components/card/cardcellcomponent/index.scss                              |    7 
 src/menu/components/card/cardcellcomponent/dragaction/action.jsx                   |   14 
 src/menu/components/card/cardcellcomponent/elementform/index.jsx                   |  259 
 src/menu/components/table/edit-table/options.jsx                                   |   15 
 src/menu/stylecontroller/index.scss                                                |   16 
 src/templates/modalconfig/index.jsx                                                |    2 
 src/tabviews/zshare/actionList/newpagebutton/index.jsx                             |  107 
 src/menu/components/module/invoice/verifycard/index.scss                           |  124 
 src/tabviews/commontable/index.jsx                                                 |   24 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx               |   45 
 src/menu/components/form/formaction/formconfig.jsx                                 |   17 
 src/menu/components/card/cardsimplecomponent/index.scss                            |   13 
 src/menu/components/share/normalheader/index.scss                                  |    5 
 src/tabviews/custom/components/card/cardcellList/index.jsx                         |  227 
 src/tabviews/custom/components/card/prop-card/index.jsx                            |   48 
 src/tabviews/zshare/actionList/funczip/index.jsx                                   |   43 
 src/menu/components/card/data-card/options.jsx                                     |  125 
 src/tabviews/custom/components/table/normal-table/index.jsx                        |  119 
 src/tabviews/custom/components/chart/antv-pie/index.jsx                            |   30 
 src/tabviews/custom/components/timeline/normal-timeline/index.jsx                  |   29 
 src/tabviews/custom/components/table/edit-table/normalTable/index.jsx              |    4 
 src/components/breadview/index.jsx                                                 |  112 
 src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss                 |   28 
 src/tabviews/custom/components/module/invoice/index.scss                           |  292 +
 src/tabviews/zshare/mutilform/index.jsx                                            |    5 
 src/menu/components/share/actioncomponent/actionform/index.jsx                     |  168 
 src/tabviews/custom/index.jsx                                                      |   99 
 src/menu/components/card/cardcomponent/index.scss                                  |   13 
 src/menu/components/module/invoice/verifycard/index.jsx                            |  690 +++
 src/menu/components/module/invoice/index.scss                                      |  258 +
 src/assets/img/invoice.png                                                         |    0 
 src/tabviews/zshare/mutilform/mkDatePicker/index.jsx                               |   13 
 src/tabviews/treepage/index.jsx                                                    |    2 
 src/tabviews/custom/components/chart/antv-scatter/index.jsx                        |   30 
 src/menu/components/card/cardcellcomponent/dragaction/index.scss                   |    7 
 src/views/design/header/index.jsx                                                  |    5 
 src/tabviews/custom/components/module/account/index.jsx                            |    3 
 src/menu/components/form/formaction/actionform/index.jsx                           |    2 
 src/tabviews/custom/components/chart/antv-G6/index.jsx                             |   30 
 src/menu/components/card/cardcellcomponent/dragaction/index.jsx                    |   12 
 src/tabviews/zshare/actionList/exceloutbutton/index.jsx                            |  255 
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx                     |   18 
 src/menu/components/card/balcony/index.scss                                        |    2 
 src/views/tabledesign/index.jsx                                                    |   18 
 src/tabviews/custom/components/form/simple-form/index.jsx                          |   29 
 src/tabviews/subtable/index.jsx                                                    |   20 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.scss   |    0 
 src/views/rolemanage/header/index.jsx                                              |    7 
 src/menu/components/group/normal-group/index.scss                                  |    2 
 src/tabviews/custom/components/card/table-card/index.jsx                           |  100 
 src/menu/components/module/invoice/verifycard/customscript/index.scss              |    0 
 src/menu/components/module/voucher/options.jsx                                     |   22 
 src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx                 |   44 
 src/menu/components/share/actioncomponent/actionform/mkPrintTemps/index.jsx        |    1 
 src/menu/components/form/step-form/index.jsx                                       |    2 
 public/manifest.json                                                               |    2 
 src/menu/components/share/normalheader/index.jsx                                   |   25 
 src/templates/modalconfig/settingform/index.jsx                                    |   23 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.jsx    |  132 
 src/menu/components/search/main-search/index.jsx                                   |    4 
 src/tabviews/custom/components/module/voucher/voucherTable/index.jsx               |  100 
 src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx        |    2 
 src/tabviews/zshare/topSearch/mkDatePicker/index.jsx                               |   15 
 src/views/login/index.jsx                                                          |   20 
 src/utils/utils-datamanage.js                                                      |   51 
 src/tabviews/custom/components/code/sand-box/index.jsx                             |   30 
 src/tabviews/zshare/actionList/editLine/index.jsx                                  |   27 
 src/menu/components/card/table-card/index.jsx                                      |    9 
 src/utils/utils-custom.js                                                          |   63 
 src/tabviews/custom/components/share/normalTable/index.scss                        |   16 
 src/tabviews/zshare/actionList/excelInbutton/index.jsx                             |   30 
 src/menu/components/share/searchcomponent/dragsearch/card.jsx                      |   14 
 src/menu/components/table/normal-table/columns/editColumn/index.jsx                |   19 
 src/tabviews/basetable/index.jsx                                                   |   35 
 src/menu/components/card/data-card/index.scss                                      |    2 
 src/tabviews/custom/components/module/invoice/index.jsx                            |  757 +++
 src/menu/menushell/card.jsx                                                        |    3 
 src/views/mobdesign/index.jsx                                                      |   12 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss              |    4 
 src/menu/components/module/invoice/verifycard/customscript/index.jsx               |  284 +
 src/menu/components/card/double-data-card/options.jsx                              |   12 
 src/menu/components/module/invoice/verifycard/baseform/index.jsx                   |  110 
 src/menu/components/module/invoice/index.jsx                                       |  479 ++
 src/menu/components/share/actioncomponent/actionform/index.scss                    |   11 
 src/menu/components/share/actioncomponent/formconfig.jsx                           |  402 +
 src/tabviews/custom/components/group/normal-group/index.jsx                        |   30 
 src/menu/components/group/normal-group/options.jsx                                 |   28 
 src/views/appcheck/header/index.jsx                                                |    7 
 src/tabviews/custom/components/carousel/prop-card/index.jsx                        |   30 
 src/menu/debug/index.jsx                                                           |   62 
 src/tabviews/zshare/topSearch/advanceform/index.scss                               |    7 
 src/menu/components/table/normal-table/index.jsx                                   |   22 
 src/tabviews/zshare/normalTable/index.scss                                         |    5 
 src/components/tabview/index.jsx                                                   |   77 
 src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx           |   92 
 src/tabviews/custom/components/table/base-table/index.jsx                          |   37 
 src/menu/components/timeline/normal-timeline/index.scss                            |    2 
 src/tabviews/custom/components/card/double-data-card/index.scss                    |    6 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx |    8 
 src/menu/components/carousel/prop-card/index.scss                                  |    2 
 src/menu/components/module/invoice/verifycard/callbackcustomscript/index.scss      |    0 
 src/menu/datasource/verifycard/customscript/index.jsx                              |    2 
 src/templates/sharecomponent/searchcomponent/index.jsx                             |    5 
 src/tabviews/custom/components/module/invoice/invoiceTable/index.scss              |  131 
 src/tabviews/custom/components/calendar/index.jsx                                  |   29 
 src/tabviews/custom/components/share/normalheader/index.scss                       |    4 
 src/tabviews/custom/components/share/normalTable/index.jsx                         |  115 
 src/components/breadview/index.scss                                                |   12 
 src/tabviews/custom/components/card/data-card/index.scss                           |    9 
 src/tabviews/zshare/actionList/exportPdf/index.jsx                                 |   30 
 src/utils/utils.js                                                                 |  211 
 src/tabviews/custom/components/card/table-card/index.scss                          |   21 
 src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx                  |   26 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx              |  300 
 src/index.js                                                                       |   18 
 src/tabviews/custom/components/form/tab-form/index.jsx                             |   29 
 src/tabviews/custom/components/share/tabtransfer/index.jsx                         |    4 
 src/tabviews/debugtable/index.jsx                                                  |    2 
 src/templates/zshare/formconfig.jsx                                                |   17 
 src/tabviews/custom/components/interfaces/interItem/index.jsx                      |   30 
 src/tabviews/custom/components/module/voucher/resetAttach/index.jsx                |    7 
 src/tabviews/zshare/flowFloat/index.jsx                                            |    6 
 src/tabviews/custom/components/chart/antv-X6/index.scss                            |   32 
 src/menu/modalconfig/index.scss                                                    |   12 
 src/menu/modalconfig/index.jsx                                                     |    2 
 src/tabviews/custom/components/card/balcony/index.jsx                              |   29 
 src/tabviews/custom/components/card/cardcellList/index.scss                        |   15 
 src/menu/components/card/double-data-card/index.scss                               |    2 
 248 files changed, 9,837 insertions(+), 2,530 deletions(-)

diff --git a/public/manifest.json b/public/manifest.json
index f3adf88..590c25c 100644
--- a/public/manifest.json
+++ b/public/manifest.json
@@ -6,5 +6,5 @@
   "display": "standalone",
   "theme_color": "#000000",
   "background_color": "#ffffff",
-  "mk_version": "20240302"
+  "mk_version": "20240401"
 }
diff --git a/src/api/index.js b/src/api/index.js
index b340607..a743d4d 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -436,7 +436,7 @@
 
         this.getSystemConfig(param).then(res => {
           if (!res.status) {
-            reject()
+            reject(res.message)
             return
           }
 
@@ -476,7 +476,7 @@
 
           CacheUtils.updateIndexDBversion({version: res.app_version || '1.00', createDate: curTime})
 
-          resolve()
+          resolve(list)
         })
       }, () => {
         reject()
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 545d3c2..41db689 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -100,9 +100,15 @@
   color: unset;
 }
 
-// 閲嶇疆鎸夐挳涓枃瀛椾笌鍥炬爣璺濈
-.ant-btn > .anticon + span, .ant-btn > span + .anticon {
-  margin-left: 5px;
+// 閲嶇疆鎸夐挳鍔犺浇涓牱寮�
+.ant-btn.ant-btn-loading .anticon:not(.anticon-loading) {
+  transition: all 0.3s;
+}
+.ant-btn.ant-btn-loading >.anticon-loading + span .anticon, .ant-btn.ant-btn-loading >.anticon-loading + .anticon {
+  width: 0;
+  opacity: 0;
+  margin-left: 0px!important;
+  margin-right: 0px!important;
 }
 
 // 璁剧疆涓嬫媺鎼滅储婊氬姩鏉℃牱寮�
@@ -762,4 +768,9 @@
   .ant-radio-button-wrapper:not(.ant-radio-button-wrapper-checked):not(.ant-radio-button-wrapper-disabled):hover {
     color: var(--mk-sys-color);
   }
+}
+
+// 榧犳爣鎮诞澧炲姞涓嬪垝绾�
+.mk-hover-underline:hover {
+  text-decoration: underline!important;
 }
\ No newline at end of file
diff --git a/src/assets/css/viewstyle.scss b/src/assets/css/viewstyle.scss
index d924c51..ceedbf9 100644
--- a/src/assets/css/viewstyle.scss
+++ b/src/assets/css/viewstyle.scss
@@ -175,8 +175,10 @@
     border-color: $color6;
   }
   // 涓嬫媺妗�
-  .ant-select-selection:hover {
-    border-color: $color5;
+  .ant-select:not(.ant-select-disabled) {
+    .ant-select-selection:hover {
+      border-color: $color5;
+    }
   }
   .ant-select-focused .ant-select-selection, .ant-select-selection:focus, .ant-select-selection:active {
     border-color: $color5;
@@ -187,7 +189,7 @@
     background-color: $color6;
   }
   // 杈撳叆妗�
-  .ant-input:hover {
+  .ant-input:not([disabled]):hover {
     border-color: $color5;
   }
   .ant-input:focus, .ant-input:active {
@@ -198,7 +200,7 @@
     border-color: $color5;
     box-shadow: 0 0 0 2px $color2;
   }
-  .ant-input-number:hover, .ant-input-number:focus, .ant-input-number:active, .ant-input-number-input:hover, .ant-input-number-input:focus, .ant-input-number-input:active, .ant-input-number-focused:hover, .ant-input-number-focused:focus, .ant-input-number-focused:active {
+  .ant-input-number:not(.ant-input-number-disabled):hover, .ant-input-number:focus, .ant-input-number:active, .ant-input-number-input:hover, .ant-input-number-input:focus, .ant-input-number-input:active, .ant-input-number-focused:hover, .ant-input-number-focused:focus, .ant-input-number-focused:active {
     border-color: $color5;
   }
   .ant-input-number:focus, .ant-input-number:active {
diff --git a/src/assets/img/invoice.png b/src/assets/img/invoice.png
new file mode 100644
index 0000000..3a5185d
--- /dev/null
+++ b/src/assets/img/invoice.png
Binary files differ
diff --git a/src/assets/img/wx-icon.png b/src/assets/img/wx-icon.png
new file mode 100644
index 0000000..e344540
--- /dev/null
+++ b/src/assets/img/wx-icon.png
Binary files differ
diff --git a/src/components/breadview/index.jsx b/src/components/breadview/index.jsx
index 3a44900..44494c8 100644
--- a/src/components/breadview/index.jsx
+++ b/src/components/breadview/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
-import { BackTop, Breadcrumb, notification} from 'antd'
-import { HomeOutlined, RightOutlined, RedoOutlined } from '@ant-design/icons'
+import { BackTop, Breadcrumb, notification, Modal } from 'antd'
+import { HomeOutlined, RightOutlined, RedoOutlined, LoadingOutlined } from '@ant-design/icons'
 import moment from 'moment'
 import 'moment/locale/zh-cn'
 
@@ -22,8 +22,38 @@
 
 class BreadView extends Component {
   state = {
-    tabview: null, // 鏍囩
-    hasNavBar: window.GLOB.navBar === 'linkage_navigation'
+    tabview: null,
+    hasNavBar: window.GLOB.navBar === 'linkage_navigation',
+    visible: false
+  }
+
+  reloading = false
+
+  UNSAFE_componentWillMount () {
+    let home = {
+      MenuID: 'home_page_id',
+      MenuName: '棣栭〉',
+      type: 'Home'
+    }
+    this.setState({tabview: home})
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('modifyTabs', this.modifyTabs)
+    if (window.GLOB.forcedUpdate) {
+      MKEmitter.addListener('reloadTabs', this.reloadTabs)
+    }
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadTabs', this.reloadTabs)
+    MKEmitter.removeListener('modifyTabs', this.modifyTabs)
   }
 
   refreshTabview = () => {
@@ -105,15 +135,6 @@
     }
   }
 
-  UNSAFE_componentWillMount () {
-    let home = {
-      MenuID: 'home_page_id',
-      MenuName: '棣栭〉',
-      type: 'Home'
-    }
-    this.setState({tabview: home})
-  }
-
   gotoHome = () => {
     let home = {
       MenuID: 'home_page_id',
@@ -134,22 +155,48 @@
     }
   }
 
-  componentDidMount () {
-    MKEmitter.addListener('modifyTabs', this.modifyTabs)
-  }
+  reloadTabs = () => {
+    if (this.reloading) return
 
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-    MKEmitter.removeListener('modifyTabs', this.modifyTabs)
+    this.reloading = true
+    let time = new Date().getTime()
+
+    this.setState({visible: true})
+
+    Api.getAppVersion(true).then((list) => {
+      let _time = new Date().getTime()
+      let delay = _time - time
+      delay = delay < 3000 ? 3000 - delay : 0
+
+      setTimeout(() => {
+        this.setState({visible: false})
+        this.reloading = false
+  
+        Modal.success({
+          title: '鏇存柊鎴愬姛銆�',
+        })
+  
+        if (list && list.length && list.includes(this.state.tabview.MenuID)) {
+          MKEmitter.emit('reloadMenuView', this.state.tabview.MenuID)
+        }
+      }, delay)
+    }, (message) => {
+      let _time = new Date().getTime()
+      let delay = _time - time
+      delay = delay < 3000 ? 3000 - delay : 0
+
+      setTimeout(() => {
+        this.setState({visible: false})
+        this.reloading = false
+        Modal.error({
+          title: message || '绯荤粺閰嶇疆鏇存柊澶辫触锛�',
+        })
+      }, delay)
+    })
   }
 
   render () {
-    const { tabview, hasNavBar } = this.state
+    const { tabview, hasNavBar, visible } = this.state
 
     return (
       <section id="mk-tabgroup-wrap" className="mk-breadview-wrap">
@@ -175,6 +222,21 @@
             </div>
           </div>
         </BackTop>
+        <Modal
+          visible={visible}
+          width={400}
+          closable={false}
+          centered={true}
+          footer={null}
+          destroyOnClose
+        >
+          <div className="mk-menus-update">
+            <div className="tip">
+              绯荤粺鏇存柊涓紝璇风◢鍚�
+            </div>
+            <LoadingOutlined />
+          </div>
+        </Modal>
       </section>
     )
   }
diff --git a/src/components/breadview/index.scss b/src/components/breadview/index.scss
index bf7a267..d178db3 100644
--- a/src/components/breadview/index.scss
+++ b/src/components/breadview/index.scss
@@ -46,4 +46,16 @@
 .ant-message {
   top: 50px;
   z-index: 1080;
+}
+
+.mk-menus-update {
+  text-align: center;
+  font-size: 20px;
+  color: #131313;
+  .tip {
+    margin-bottom: 10px;
+  }
+  .anticon {
+    color: var(--mk-sys-color);
+  }
 }
\ No newline at end of file
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 80a849c..6151dc5 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -10,6 +10,7 @@
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import avatar from '@/assets/img/avatar.jpg'
+import wxicon from '@/assets/img/wx-icon.png'
 import './index.scss'
 
 const { confirm } = Modal
@@ -24,6 +25,7 @@
     userName: '',
     fullName: '',
     logourl: window.GLOB.mainlogo,
+    wxVisible: false,
     loginVisible: false,
     loginLoading: false,
     avatar: Utils.getrealurl(sessionStorage.getItem('avatar')),
@@ -336,6 +338,7 @@
                   trdItem.OpenType = PageParam.OpenType || 'newtab'
                   trdItem.hidden = PageParam.hidden || 'false'
                   trdItem.menuColor = PageParam.menuColor || ''
+                  trdItem.urlFields = PageParam.urlFields || ''
 
                   if (trdItem.type === 'NewPage') {
                     trdItem.OpenType = 'newpage'
@@ -435,6 +438,8 @@
           sessionStorage.setItem('CloudAvatar', res.icon)
           sessionStorage.setItem('cloudDataM', res.dataM ? 'true' : '')
           sessionStorage.setItem('cloudRole_id', res.role_id || '')
+
+          sessionStorage.setItem('CloudLogo', res.open_logo || '')
 
           let _url = window.location.href.split('#')[0] + 'cloud'
           if (param.remember) {
@@ -594,14 +599,6 @@
     })
   }
 
-  wxnotice = () => {
-    Modal.success({
-      className: 'mk-wx-notice',
-      title: <QrCode card={{qrWidth: 320, color: '#000000'}} value={window.GLOB.baseurl + 'mob/wxnotice.html?userid=' + sessionStorage.getItem('UserID') + '&loginuid=' + sessionStorage.getItem('LoginUID')}/>,
-      okText: '鍏抽棴'
-    })
-  }
-
   changeToHome = () => {
     if (!['linkage', 'menu_board'].includes(window.GLOB.navBar)) return
 
@@ -628,7 +625,7 @@
         <Menu.Item key="verup" onClick={this.verup}>
           椤甸潰鏇存柊
         </Menu.Item>
-        {window.GLOB.WXNotice ? <Menu.Item key="wxnotice" onClick={this.wxnotice}>
+        {window.GLOB.WXNotice ? <Menu.Item key="wxnotice" onClick={() => this.setState({wxVisible: true})}>
           寰俊娑堟伅
         </Menu.Item> : null}
         {window.GLOB.appVersion ? <Menu.Item key="version" onClick={this.about}>
@@ -801,6 +798,26 @@
         </Modal>
         {/* 淇敼瀵嗙爜 */}
         <Resetpwd />
+        {/* 寰俊娑堟伅 */}
+        <Modal
+          wrapClassName="mk-wx-sms-modal"
+          visible={this.state.wxVisible}
+          title="鎵爜鍏虫敞  鎺ユ敹娑堟伅"
+          width={400}
+          centered={true}
+          onCancel={() => this.setState({wxVisible: false})}
+          footer={null}
+          destroyOnClose
+        >
+          <div className="wx-sms-wrap">
+            <QrCode card={{qrWidth: 200, color: '#000000'}} value={window.GLOB.baseurl + 'mob/wxnotice.html?userid=' + sessionStorage.getItem('UserID') + '&loginuid=' + sessionStorage.getItem('LoginUID')}/>
+            <div className="tip">
+              <img src={wxicon} alt=""/>
+              <span>寰俊鎵爜</span>
+              <span>鍏虫敞鍏紬鍙�</span>
+            </div>
+          </div>
+        </Modal>
       </header>
     )
   }
diff --git a/src/components/header/index.scss b/src/components/header/index.scss
index dc9c47d..751fa9a 100644
--- a/src/components/header/index.scss
+++ b/src/components/header/index.scss
@@ -276,17 +276,34 @@
   }
 }
 
-.mk-wx-notice {
-  top: 100px!important;
-  .anticon-check-circle {
-    display: none;
-  }
-  .ant-modal-confirm-title {
+.mk-wx-sms-modal {
+  .ant-modal-title {
     text-align: center;
-    min-height: 320px;
+    font-size: 22px;
+    font-weight: 500;
+    color: #151515;
+    margin-top: 15px;
+    letter-spacing: 2px;
   }
-  .ant-modal-confirm-btns {
-    float: none!important;
+  .wx-sms-wrap {
     text-align: center;
+  
+    .tip {
+      margin: 15px;
+      img {
+        width: 24px;
+        margin-right: 10px;
+      }
+      span {
+        font-size: 16px;
+        letter-spacing: 2px;
+        font-weight: 500;
+        color: #333;
+      }
+      span + span {
+        color: #45B449;
+        font-weight: bold;
+      }
+    }
   }
 }
\ No newline at end of file
diff --git a/src/components/normalform/modalform/index.jsx b/src/components/normalform/modalform/index.jsx
index 776c225..1623373 100644
--- a/src/components/normalform/modalform/index.jsx
+++ b/src/components/normalform/modalform/index.jsx
@@ -18,6 +18,7 @@
 const MKCheckbox = asyncComponent(() => import('./mkCheckbox'))
 const StyleInput = asyncComponent(() => import('./styleInput'))
 const MKFileUpload = asyncComponent(() => import('@/tabviews/zshare/fileupload'))
+const MkPrintTemps = asyncComponent(() => import('@/menu/components/share/actioncomponent/actionform/mkPrintTemps'))
 const MKColor = asyncComponent(() => import('@/mob/colorsketch'))
 // const MKColor = asyncComponent(() => import('@/tabviews/zshare/mutilform/mkColor'))
 const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
@@ -314,14 +315,22 @@
           </Col>
         )
         return
+      } else if (item.type === 'printTemps') {
+        content = <MkPrintTemps onChange={(val) => this.recordChange({[item.field]: val})}/>
       }
 
       if (!content) return
 
       if (item.help) {
+        let help = null
+        if (typeof(item.help) === 'function') {
+          help = item.help(this.record)
+        } else {
+          help = <span style={{fontSize: '12px'}}>{item.help}</span>
+        }
         fields.push(
           <Col span={item.span || 12} key={index}>
-            <Form.Item label={label} help={<span style={{fontSize: '12px'}}>{item.help}</span>}>
+            <Form.Item label={label} help={help}>
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
                 rules: item.rules
diff --git a/src/components/normalform/modalform/mkTable/index.jsx b/src/components/normalform/modalform/mkTable/index.jsx
index 341e32a..0ae8cfa 100644
--- a/src/components/normalform/modalform/mkTable/index.jsx
+++ b/src/components/normalform/modalform/mkTable/index.jsx
@@ -352,6 +352,10 @@
         if (_options.length) {
           col.extends.forEach(n => {
             record[n.value] = _options.map(o => o[n.key]).join(' / ')
+
+            if (n.mutilLabel && !record[n.mutilLabel]) {
+              record[n.mutilLabel] = _options[_options.length - 1][n.key]
+            }
           })
         }
       } else {
diff --git a/src/components/normalform/modalform/mkTable/index.scss b/src/components/normalform/modalform/mkTable/index.scss
index a5620f0..97e3e85 100644
--- a/src/components/normalform/modalform/mkTable/index.scss
+++ b/src/components/normalform/modalform/mkTable/index.scss
@@ -23,6 +23,23 @@
       top: 4px;
       white-space: nowrap;
     }
+    .mini-color {
+      .color-sketch-block {
+        width: 80%;
+        .color-sketch-block-box {
+          width: 100%;
+        }
+        .color-sketch-value {
+          display: none;
+        }
+      }
+    }
+    .mk-color-value {
+      display: inline-block;
+      width: 80%;
+      height: 24px;
+      box-shadow: 0 0 2px #b8b8b8;
+    }
     .ant-select {
       width: 100%;
     }
diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx
index 06635eb..51f9743 100644
--- a/src/components/tabview/index.jsx
+++ b/src/components/tabview/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import { fromJS } from 'immutable'
-import {Tabs, BackTop, notification} from 'antd'
-import { RedoOutlined, CloseOutlined } from '@ant-design/icons'
+import { Tabs, BackTop, notification, Modal } from 'antd'
+import { RedoOutlined, CloseOutlined, LoadingOutlined } from '@ant-design/icons'
 import moment from 'moment'
 import 'moment/locale/zh-cn'
 
@@ -25,8 +25,10 @@
   state = {
     activeId: '',
     tabviews: [],
-    iFrameHeight: 0,
+    visible: false
   }
+
+  reloading = false
 
   UNSAFE_componentWillMount () {
     if (!window.GLOB.mkHS) {
@@ -44,6 +46,10 @@
   componentDidMount () {
     MKEmitter.addListener('modifyTabs', this.modifyTabs)
     MKEmitter.addListener('closeTabView', this.closeTabView)
+
+    if (window.GLOB.forcedUpdate) {
+      MKEmitter.addListener('reloadTabs', this.reloadTabs)
+    }
   }
 
   /**
@@ -54,6 +60,7 @@
       return
     }
     MKEmitter.removeListener('modifyTabs', this.modifyTabs)
+    MKEmitter.removeListener('reloadTabs', this.reloadTabs)
     MKEmitter.removeListener('closeTabView', this.closeTabView)
   }
 
@@ -143,6 +150,53 @@
     } else {
       MKEmitter.emit('reloadMenuView', menu.MenuID)
     }
+  }
+
+  reloadTabs = () => {
+    if (this.reloading) return
+
+    this.reloading = true
+    let time = new Date().getTime()
+
+    this.setState({visible: true})
+
+    Api.getAppVersion(true).then((list) => {
+      let _time = new Date().getTime()
+      let delay = _time - time
+      delay = delay < 3000 ? 3000 - delay : 0
+
+      setTimeout(() => {
+        this.setState({visible: false})
+        this.reloading = false
+  
+        Modal.success({
+          title: '鏇存柊鎴愬姛銆�',
+        })
+  
+        if (list && list.length) {
+          let _tabIds = this.state.tabviews.map(item => item.MenuID)
+          list.forEach((m, i) => {
+            if (_tabIds.includes(m)) {
+              setTimeout(() => {
+                MKEmitter.emit('reloadMenuView', m)
+              }, i * 20)
+            }
+          })
+        }
+      }, delay)
+    }, (message) => {
+      let _time = new Date().getTime()
+      let delay = _time - time
+      delay = delay < 3000 ? 3000 - delay : 0
+
+      setTimeout(() => {
+        this.setState({visible: false})
+        this.reloading = false
+        Modal.error({
+          title: message || '绯荤粺閰嶇疆鏇存柊澶辫触锛�',
+        })
+      }, delay)
+    })
   }
 
   modifyTabs = (tab, fixed) => {
@@ -236,7 +290,7 @@
   }
 
   render () {
-    const { tabviews, activeId } = this.state
+    const { tabviews, activeId, visible } = this.state
 
     return (
       <section id="mk-tabgroup-wrap" className="mk-tabview-wrap">
@@ -273,6 +327,21 @@
             </Tabs>
           }
         </div>
+        <Modal
+          visible={visible}
+          width={400}
+          closable={false}
+          centered={true}
+          footer={null}
+          destroyOnClose
+        >
+          <div className="mk-menus-update">
+            <div className="tip">
+              绯荤粺鏇存柊涓紝璇风◢鍚�
+            </div>
+            <LoadingOutlined />
+          </div>
+        </Modal>
       </section>
     )
   }
diff --git a/src/components/tabview/index.scss b/src/components/tabview/index.scss
index 040e6bf..130fc12 100644
--- a/src/components/tabview/index.scss
+++ b/src/components/tabview/index.scss
@@ -110,4 +110,16 @@
 .ant-message {
   top: 50px;
   z-index: 1080;
+}
+
+.mk-menus-update {
+  text-align: center;
+  font-size: 20px;
+  color: #131313;
+  .tip {
+    margin-bottom: 10px;
+  }
+  .anticon {
+    color: var(--mk-sys-color);
+  }
 }
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index 11134f7..d52fccb 100644
--- a/src/index.js
+++ b/src/index.js
@@ -75,6 +75,13 @@
       GLOB.externalDatabase = null
     }
 
+    if (config.probation && /^20\d{2}-\d{2}-\d{2}$/.test(config.probation) && new Date(config.probation).getTime() > new Date().getTime()) {
+      GLOB.probation = true
+    }
+    if (config.forcedUpdate && /^20\d{2}-\d{2}-\d{2}$/.test(config.forcedUpdate) && new Date(config.forcedUpdate).getTime() > new Date().getTime()) {
+      GLOB.forcedUpdate = true
+    }
+
     // 鍙湁涓氬姟绯荤粺鎵嶅彲浠ヨ缃负姝e紡绯荤粺
     if (GLOB.sysType === 'local' && (config.systemType === 'official' || config.systemType === 'production')) {
       if (!config.mainSystemApi) {
@@ -89,12 +96,6 @@
       }
 
       GLOB.systemType = 'production'
-      if (config.probation && /^20\d{2}-\d{2}-\d{2}$/.test(config.probation) && new Date(config.probation).getTime() > new Date().getTime()) {
-        GLOB.probation = true
-      }
-      if (config.forcedUpdate && /^20\d{2}-\d{2}-\d{2}$/.test(config.forcedUpdate) && new Date(config.forcedUpdate).getTime() > new Date().getTime()) {
-        GLOB.forcedUpdate = true
-      }
     } else if (GLOB.sysType === 'local') {
       GLOB.probation = true
       GLOB.debugger = true
@@ -245,6 +246,11 @@
       sessionStorage.setItem('system_mark', _mark)
     }
 
+    if (config.mainkey && GLOB.sysType !== 'cloud' && config.mainkey !== options.cakey) {
+      GLOB.localkey = GLOB.appkey
+      GLOB.appkey = config.mainkey
+    }
+
     let lang = localStorage.getItem(_href + 'lang') || (config.defaultLang !== 'en-US' ? 'zh-CN' : 'en-US')
     sessionStorage.setItem('lang', lang)
 
diff --git a/src/menu/components/card/balcony/index.scss b/src/menu/components/card/balcony/index.scss
index 418b226..efe4ce6 100644
--- a/src/menu/components/card/balcony/index.scss
+++ b/src/menu/components/card/balcony/index.scss
@@ -32,7 +32,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-color: #ffffff;
     background-position: center center;
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
index 47cdb5d..4db573b 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -66,17 +66,17 @@
   } else if (card.show === 'icon') {
     btnElement = (<Button style={_style} type="link"><MkIcon type={card.icon}/>{warning}</Button>)
   } else if (card.show === 'link') {
-    btnElement = (<Button style={_style} type="link">{card.label}{card.icon ? <MkIcon type={card.icon}/> : null}{warning}</Button>)
+    btnElement = (<Button style={_style} type="link">{card.showName || card.label}{card.icon ? <MkIcon type={card.icon}/> : null}{warning}</Button>)
   } else {
-    btnElement = (<Button style={_style}>{card.icon ? <MkIcon type={card.icon}/> : null}{card.label}{warning}</Button>)
+    btnElement = (<Button style={_style}>{card.icon ? <MkIcon type={card.icon}/> : null}{card.showName || card.label}{warning}</Button>)
   }
 
-  let _style_ = null
+  let _style_ = {opacity: isDragging ? 0.3 : 1, ...card.wrapStyle}
 
   if (card.style && card.style.clear === 'left') {
-    _style_ = {clear: 'left'}
+    _style_.clear = 'left'
   } else if (card.style && card.style.clear === 'right') {
-    _style_ = {float: 'right'}
+    _style_.float = 'right'
   }
 
   let className = card.width || 0
@@ -105,9 +105,7 @@
       </div>
     } trigger="hover">
       <div ref={node => drag(drop(node))} style={_style_} className={'ant-col card-button-cell ant-col-' + className} onDoubleClick={(e) => {e.stopPropagation(); doubleClickCard(id)}}>
-        <div style={{opacity: isDragging ? 0.3 : 1, ...card.wrapStyle}}>
-          {btnElement}
-        </div>
+        {btnElement}
       </div>
     </Popover>
   )
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 7395d2a..abe02a7 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -59,7 +59,7 @@
 
   let _style = {opacity: isDragging ? 0.3 : 1}
   
-  if (card.style) {
+  if (card.style && card.eleType !== 'tag') {
     _style = {...card.style, opacity: isDragging ? 0.3 : 1}
     _style = resetStyle(_style)
   }
@@ -184,11 +184,27 @@
         let _s = {fontSize: card.fixSize, color: card.fixColor, marginLeft: card.fixLeft, marginRight: card.fixRight}
         val = <><span style={_s}>{card.prefix || ''}</span>{card.formula}<span style={_s}>{card.postfix || ''}</span></>
       }
+
       return (
         <div className="ant-mk-text" style={{height: card.innerHeight || 'auto'}}>
           {val}
         </div>
       )
+    } else if (card.eleType === 'tag') {
+      let vals = []
+      if (card.datatype === 'static') {
+        vals = card.value.split(',').filter(Boolean)
+      } else {
+        vals = [card.field || '']
+      }
+
+      let _style = resetStyle(card.style)
+
+      return (
+        <div className="ant-mk-tag">
+          {vals.map((val, index) => <span key={index} className="tag-item" style={_style}>{val}</span>)}
+        </div>
+      )
     } else if (card.eleType === 'color') {
       _style.overflow = 'hidden'
       let _bgstyle = {backgroundColor: card.value || '#1890ff'}
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
index 41c2326..207e436 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -140,6 +140,18 @@
           if (item.value === 'splitline') {
             newcard.width = 24
             newcard.color = '#EBE9E9'
+          } else if (item.value === 'tag') {
+            newcard.style = {
+              backgroundColor: 'var(--mk-sys-color1)',
+              color: 'var(--mk-sys-color)',
+              borderColor: 'var(--mk-sys-color)',
+              borderWidth: '1px',
+              borderRadius: '4px',
+              paddingLeft: '7px',
+              paddingRight: '7px',
+              marginRight: '8px',
+              marginBottom: '8px',
+            }
           } else if (item.value === 'slider') {
             newcard.width = 24
             newcard.color = '#1890ff'
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.scss b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
index a492bac..289da39 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.scss
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -4,6 +4,7 @@
     font-style: inherit;
     font-weight: inherit;
     text-decoration: inherit;
+    font-family: inherit;
   }
   .ant-mk-text:not(.line1):not(.line) {
     word-break: break-word;
@@ -93,6 +94,12 @@
     border-left: 0;
     border-right: 0;
   }
+  .ant-mk-tag {
+    .tag-item {
+      display: inline-block;
+      vertical-align: top;
+    }
+  }
   .ant-mk-check {
     white-space: nowrap;
     overflow: hidden;
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index 8488fd1..efc66b8 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Form, Row, Col, Input, Select, Radio, Tooltip, InputNumber, Cascader, Popover } from 'antd'
+import { Form, Row, Col, Input, Select, Radio, Tooltip, InputNumber, Cascader, Popover, message, AutoComplete } from 'antd'
 import { QuestionCircleOutlined } from '@ant-design/icons'
 
 import { formRule } from '@/utils/option.js'
@@ -10,7 +10,9 @@
 
 const { TextArea } = Input
 const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
+const CodeMirror = asyncComponent(() => import('@/templates/zshare/codemirror'))
 const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
+const MKTable = asyncComponent(() => import('@/components/normalform/modalform/mkTable'))
 const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
 
 const cardTypeOptions = {
@@ -25,8 +27,9 @@
   barcode: ['eleType', 'datatype', 'width', 'barHeight', 'displayValue', 'interval', 'noValue'],
   qrcode: ['eleType', 'datatype', 'width', 'qrWidth', 'color', 'url', 'noValue'],
   currentDate: ['eleType', 'width', 'dateFormat', 'prefix', 'postfix', 'fixStyle'],
-  formula: ['eleType', 'width', 'height', 'prefix', 'postfix', 'eval', 'formula', 'noValue', 'fixStyle', 'alignItems'],
+  formula: ['eleType', 'width', 'height', 'eval', 'formula', 'noValue'],
   color: ['eleType', 'datatype', 'width', 'lenWidRadio', 'noValue', 'copyable'],
+  tag: ['eleType', 'datatype', 'width', 'noValue', 'signs'],
 }
 
 class ElementEditForm extends Component {
@@ -58,7 +61,7 @@
       formlist: formlist.map(item => {
         item.hidden = !_options.includes(item.key)
 
-        if (item.key === 'field' || item.key === 'linkurl' || item.key === 'bgImage' || item.key === 'posterField') {
+        if ((item.key === 'field' || item.key === 'linkurl' || item.key === 'bgImage' || item.key === 'posterField') && item.type === 'select') {
           item.options = []
           
           if (side === 'sub') {
@@ -112,26 +115,39 @@
               })
             })
           }
-        } else if (item.key === 'value' && card.eleType === 'slider') {
-          item.type = 'number'
-          item.label = '鍊�'
         } else if (item.key === 'formula') {
           item.fields = []
 
-          config.columns.forEach(col => {
-            item.fields.push(col.field)
-          })
-          
-          if (config.subColumns) {
-            config.subColumns.forEach(col => {
+          if (side === 'sub') {
+            if (config.subColumns) {
+              config.subColumns.forEach(col => {
+                item.fields.push(col.field)
+              })
+            }
+          } else {
+            config.columns.forEach(col => {
               item.fields.push(col.field)
             })
           }
 
           item.fields = item.fields.join(', ')
-        } else if (item.key === 'value' && card.eleType === 'text') {
-          item.type = 'textarea'
-          item.label = '鍐呭'
+        } else if (item.key === 'value') {
+          item.tooltip = ''
+          if (card.eleType === 'slider') {
+            item.type = 'number'
+            item.label = '鍊�'
+          } else if (card.eleType === 'text') {
+            item.type = 'textarea'
+            item.label = '鍐呭'
+            item.tooltip = '鏂囨湰绫诲瀷锛屼細鏇挎崲鍐呭涓殑@username@銆丂fullName@銆丂mk_city@銆丂appname@銆丂bid@銆丂month@銆丂week@銆丂day@'
+          } else if (card.eleType === 'tag') {
+            item.type = 'textarea'
+            item.label = '鍐呭'
+            item.tooltip = '澶氫釜鍊艰浣跨敤閫楀彿锛堣嫳鏂囷級鍒嗛殧銆�'
+          } else {
+            item.type = 'text'
+            item.label = '鍐呭'
+          }
         } else if (item.key === 'format') {
           if (card.eleType === 'text') {
             item.options = item.oriOptions.filter(op => !['percent', 'thdSeparator', 'abs'].includes(op.value))
@@ -142,7 +158,7 @@
           item.required = card.eleType !== 'qrcode'
         }
         if (item.key === 'linkurl') {
-          item.type = card.link === 'dynamic' ? 'select' : 'textarea'
+          item.type = card.link === 'dynamic' ? item.defType : 'textarea'
         }
 
         return item
@@ -153,7 +169,7 @@
   getOptions = () => {
     let _options = fromJS(cardTypeOptions[this.record.eleType]).toJS() // 閫夐」鍒楄〃
     
-    if (['text', 'number', 'picture', 'slider', 'barcode', 'qrcode', 'video', 'color'].includes(this.record.eleType)) {
+    if (['text', 'number', 'picture', 'slider', 'barcode', 'qrcode', 'video', 'color', 'tag'].includes(this.record.eleType)) {
       if (this.record.datatype === 'dynamic') {
         _options.push('field')
         if (this.record.eleType === 'number') {
@@ -210,8 +226,13 @@
       if (this.record.tipType === 'text') {
         _options.push('height')
       }
-    } else if (this.record.eleType === 'formula' && this.record.eval === 'true') {
-      _options.push('decimal')
+    } else if (this.record.eleType === 'formula') {
+      if (this.record.eval !== 'func') {
+        _options.push('prefix', 'postfix', 'fixStyle', 'alignItems')
+      }
+      if (this.record.eval === 'true') {
+        _options.push('decimal')
+      }
     }
     if (_options.includes('fixStyle') && this.record.fixStyle === 'alone') {
       _options.push('fixSize', 'fixColor', 'fixLeft', 'fixRight')
@@ -245,7 +266,7 @@
         item.initVal = this.record[item.key]
         item.hidden = !_options.includes(item.key)
 
-        if (item.key === 'field') {
+        if (item.key === 'field' && item.type === 'select') {
           item.options = []
 
           if (side === 'sub') {
@@ -281,12 +302,18 @@
             })
           }
         } else if (item.key === 'value') {
+          item.tooltip = ''
           if (value === 'slider') {
             item.type = 'number'
             item.label = '鍊�'
           } else if (value === 'text') {
             item.type = 'textarea'
             item.label = '鍐呭'
+            item.tooltip = '鏂囨湰绫诲瀷锛屼細鏇挎崲鍐呭涓殑@username@銆丂fullName@銆丂mk_city@銆丂appname@銆丂bid@銆丂month@銆丂week@銆丂day@'
+          } else if (value === 'tag') {
+            item.type = 'textarea'
+            item.label = '鍐呭'
+            item.tooltip = '澶氫釜鍊艰浣跨敤閫楀彿锛堣嫳鏂囷級鍒嗛殧銆�'
           } else {
             item.type = 'text'
             item.label = '鍐呭'
@@ -339,7 +366,7 @@
           item.hidden = !_options.includes(item.key)
 
           if (item.key === 'linkurl') {
-            item.type = value === 'dynamic' ? 'select' : 'textarea'
+            item.type = value === 'dynamic' ? item.defType : 'textarea'
           }
           return item
         })
@@ -374,8 +401,68 @@
       if (item.hidden || item.forbid) return
 
       if (item.type === 'text') {
+        if (item.options && item.options.length > 0) {
+          fields.push(
+            <Col span={12} key={index}>
+              <Form.Item label={item.label}>
+                {getFieldDecorator(item.key, {
+                  initialValue: item.initVal || '',
+                  rules: [
+                    {
+                      required: !!item.required,
+                      message: '璇疯緭鍏�' + item.label + '!'
+                    },
+                    {
+                      pattern: formRule.field.pattern,
+                      message: formRule.field.message
+                    },
+                    {
+                      max: formRule.input.max,
+                      message: formRule.input.message
+                    }
+                  ]
+                })(
+                  <AutoComplete
+                    dataSource={item.options.map((cell, i) => <AutoComplete.Option value={cell.value} key={i}>
+                      {cell.value}
+                    </AutoComplete.Option>)}
+                    filterOption={(input, option) => option.props.children.indexOf(input) > -1}
+                  >
+                    <Input autoComplete="off" onPressEnter={this.handleSubmit} />
+                  </AutoComplete>
+                )}
+              </Form.Item>
+            </Col>
+          )
+        } else {
+          fields.push(
+            <Col span={12} key={index}>
+              <Form.Item label={item.tooltip ?
+                <Tooltip placement="topLeft" title={item.tooltip}>
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  {item.label}
+                </Tooltip> : item.label
+              }>
+                {getFieldDecorator(item.key, {
+                  initialValue: item.initVal || '',
+                  rules: [
+                    {
+                      required: item.readonly ? false : !!item.required,
+                      message: '璇疯緭鍏�' + item.label + '!'
+                    },
+                    {
+                      max: formRule.input.max,
+                      message: formRule.input.message
+                    }
+                  ]
+                })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+          )
+        }
+      } else if (item.type === 'textarea') {
         fields.push(
-          <Col span={12} key={index}>
+          <Col span={24} className="textarea" key={index}>
             <Form.Item label={item.tooltip ?
               <Tooltip placement="topLeft" title={item.tooltip}>
                 <QuestionCircleOutlined className="mk-form-tip" />
@@ -388,44 +475,35 @@
                   {
                     required: item.readonly ? false : !!item.required,
                     message: '璇疯緭鍏�' + item.label + '!'
-                  },
-                  {
-                    max: formRule.input.max,
-                    message: formRule.input.message
                   }
                 ]
-              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.handleSubmit} />)}
+              })(<TextArea autoSize={{minRows: 2}} disabled={item.readonly} placeholder={item.placeholder || ''} />)}
             </Form.Item>
           </Col>
         )
-      } else if (item.type === 'textarea') {
-        if (item.key === 'formula') {
+      } else if (item.type === 'number') {
+        if (item.help) {
           fields.push(
-            <Col span={24} className="textarea" key={index}>
-              <Form.Item label={item.tooltip ?
+            <Col span={12} key={index}>
+              <Form.Item help={item.help} label={item.tooltip ?
                 <Tooltip placement="topLeft" title={item.tooltip}>
                   <QuestionCircleOutlined className="mk-form-tip" />
                   {item.label}
                 </Tooltip> : item.label
               }>
                 {getFieldDecorator(item.key, {
-                  initialValue: item.initVal || '',
-                  rules: [
-                    {
-                      required: item.readonly ? false : !!item.required,
-                      message: '璇疯緭鍏�' + item.label + '!'
-                    }
-                  ]
-                })(<TextArea autoSize={{minRows: 2}} disabled={item.readonly} placeholder={item.placeholder || ''} />)}
+                  initialValue: item.initVal,
+                  rules: [{
+                    required: item.readonly ? false : !!item.required,
+                    message: '璇疯緭鍏�' + item.label + '!'
+                  }]
+                })(<InputNumber min={item.min || 0} max={item.max || 10000} precision={item.precision || 0} onPressEnter={this.handleSubmit} />)}
               </Form.Item>
-              <Popover overlayClassName="formula-fields" placement="topLeft" title="" content={<div>{item.fields}</div>} trigger="click">
-                <span className="formula-icon">瀛楁闆�</span>
-              </Popover>
             </Col>
           )
         } else {
           fields.push(
-            <Col span={24} className="textarea" key={index}>
+            <Col span={12} key={index}>
               <Form.Item label={item.tooltip ?
                 <Tooltip placement="topLeft" title={item.tooltip}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -433,37 +511,16 @@
                 </Tooltip> : item.label
               }>
                 {getFieldDecorator(item.key, {
-                  initialValue: item.initVal || '',
-                  rules: [
-                    {
-                      required: item.readonly ? false : !!item.required,
-                      message: '璇疯緭鍏�' + item.label + '!'
-                    }
-                  ]
-                })(<TextArea autoSize={{minRows: 2}} disabled={item.readonly} placeholder={item.placeholder || ''} />)}
+                  initialValue: item.initVal,
+                  rules: [{
+                    required: item.readonly ? false : !!item.required,
+                    message: '璇疯緭鍏�' + item.label + '!'
+                  }]
+                })(<InputNumber min={item.min || 0} max={item.max || 10000} precision={item.precision || 0} onPressEnter={this.handleSubmit} />)}
               </Form.Item>
             </Col>
           )
         }
-      } else if (item.type === 'number') {
-        fields.push(
-          <Col span={12} key={index}>
-            <Form.Item help={item.help || null} label={item.tooltip ?
-              <Tooltip placement="topLeft" title={item.tooltip}>
-                <QuestionCircleOutlined className="mk-form-tip" />
-                {item.label}
-              </Tooltip> : item.label
-            }>
-              {getFieldDecorator(item.key, {
-                initialValue: item.initVal,
-                rules: [{
-                  required: item.readonly ? false : !!item.required,
-                  message: '璇疯緭鍏�' + item.label + '!'
-                }]
-              })(<InputNumber min={item.min || 0} max={item.max || 10000} precision={item.precision || 0} onPressEnter={this.handleSubmit} />)}
-            </Form.Item>
-          </Col>
-        )
       } else if (item.type === 'select') { // 涓嬫媺鎼滅储
         fields.push(
           <Col span={12} key={index}>
@@ -614,6 +671,55 @@
             </Form.Item>
           </Col>
         )
+      } else if (item.type === 'table') {
+        fields.push(
+          <Col span={24} key={index} className="textarea">
+            <Form.Item label={
+              item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}>
+                <QuestionCircleOutlined className="mk-form-tip" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: '璇疯緭鍏�' + item.label + '!'
+                  }
+                ]
+              })(
+                <MKTable columns={item.columns || []} actions={item.actions}/>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'codemirror') {
+        fields.push(
+          <Col span={24} key={index} className="textarea">
+            <Form.Item label={
+              <Tooltip placement="topLeft" overlayStyle={{width: 500, maxWidth: 500}} title={item.tooltip}>
+                <QuestionCircleOutlined className="mk-form-tip" />
+                {item.label}
+              </Tooltip>
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal || '',
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: '璇疯緭鍏�' + item.label + '!'
+                  }
+                ]
+              })(
+                <CodeMirror mode="text/javascript"/>
+              )}
+            </Form.Item>
+            <Popover overlayClassName="formula-fields" placement="topLeft" title="" content={<div>{item.fields}</div>} trigger="click">
+              <span className="formula-icon">瀛楁闆�</span>
+            </Popover>
+          </Col>
+        )
       }
     })
     return fields
@@ -648,6 +754,19 @@
             })
           }
 
+          if (values.width === 0) {
+            let utype = {picture: '鍥剧墖', video: '瑙嗛', slider: '杩涘害鏉�', splitline: '鍒嗗壊绾�', barcode: '鏉″舰鐮�', qrcode: '浜岀淮鐮�'}
+            
+            if (utype[values.eleType]) {
+              message.warning(utype[values.eleType] + '鍏冪礌瀹藉害涓嶅彲涓�0锛�')
+              return
+            }
+          }
+          
+          if (values.eleType === 'tag' && values.signs && values.signs.length === 0) {
+            values.signs = null
+          }
+
           resolve(values)
         } else {
           reject(err)
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.scss b/src/menu/components/card/cardcellcomponent/elementform/index.scss
index aaa2c39..e2aa807 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.scss
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.scss
@@ -14,10 +14,13 @@
       .ant-form-item-control-wrapper {
         width: 85.8%;
       }
+      .CodeMirror {
+        height: 200px;
+      }
 
       .formula-icon {
         position: absolute;
-        bottom: 5px;
+        top: -18px;
         right: 15px;
         cursor: pointer;
         font-size: 12px;
@@ -36,6 +39,10 @@
   .ant-form-explain, .ant-form-extra {
     font-size: 13px;
   }
+  .ant-select-search__field__mirror {
+    max-width: 100%;
+    overflow: hidden;
+  }
 }
 .formula-fields {
   z-index: 1200!important;
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index f0464b2..61c27e7 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -1,3 +1,4 @@
+import React from 'react'
 import MenuUtils from '@/utils/utils-custom.js'
 
 /**
@@ -20,6 +21,7 @@
     { value: 'qrcode', text: '浜岀淮鐮�'},
     { value: 'currentDate', text: '褰撳墠鏃堕棿'},
     { value: 'formula', text: '鍏紡'},
+    { value: 'tag', text: '鏍囩'},
     { value: 'color', text: '棰滆壊'},
   ]
 
@@ -52,7 +54,7 @@
     _options = [{ value: 'text', text: '鏂囨湰'}]
   }
 
-  let width = card.width || 12
+  let width = card.width === undefined ? 12 : card.width
   if (/x/.test(card.width)) {
     width = +width.replace(/x/, '.5')
   }
@@ -60,6 +62,7 @@
   let linkTypes = [
     { value: 'tel', text: '鐢佃瘽' },
     { value: 'email', text: '閭' },
+    { value: 'linkmenu', text: '鍏宠仈鑿滃崟' },
     { value: 'download', text: '涓嬭浇' },
     { value: 'other', text: '鍏朵粬' }
   ]
@@ -89,13 +92,25 @@
       card.linkType = ''
       card.linkurl = ''
     }
-  } else if (card.linkType === 'linkmenu') {
-    if (appType !== 'mob' && appType !== 'pc') {
-      card.link = ''
-      card.linkType = ''
-      card.linkurl = ''
-      card.linkmenu = ''
+  // } else if (card.linkType === 'linkmenu') {
+  //   if (appType !== 'mob' && appType !== 'pc') {
+  //     card.link = ''
+  //     card.linkType = ''
+  //     card.linkurl = ''
+  //     card.linkmenu = ''
+  //   }
+  }
+
+  let menulist = sessionStorage.getItem('fstMenuList')
+
+  if (appType === '' && menulist) {
+    try {
+      menulist = JSON.parse(menulist)
+    } catch (e) {
+      menulist = []
     }
+  } else {
+    menulist = []
   }
 
   let appMenus = sessionStorage.getItem('appMenus')
@@ -110,6 +125,18 @@
       appMenus = []
     }
     appMenus.push({value: 'goback', text: '杩斿洖锛堜笂涓�椤碉級'})
+  }
+
+  let fields = []
+  if (cards.subtype === 'propcard' && cards.wrap.datatype === 'static') {
+    if (cards.wrap.supModule && cards.wrap.supModule.length) {
+      let cell = MenuUtils.getComponent(cards.wrap.supModule[cards.wrap.supModule.length - 1])
+      if (cell && cell.columns) {
+        fields = cell.columns.map(col => ({ value: col.field }))
+      }
+    } else {
+      fields = cards.columns.map(col => ({ value: col.field }))
+    }
   }
 
   let forms = [
@@ -145,12 +172,12 @@
       ]
     },
     {
-      type: 'select',
+      type: cards.subtype === 'propcard' && cards.wrap.datatype === 'static' ? 'text' : 'select',
       key: 'field',
       label: '瀛楁',
       initVal: card.field || '',
       required: true,
-      options: []
+      options: fields
     },
     {
       type: 'icon',
@@ -165,7 +192,7 @@
       min: 0,
       label: '鍐呭',
       initVal: card.value || '',
-      tooltip: '鏂囨湰绫诲瀷锛屼細鏇挎崲鍐呭涓殑@username@銆丂fullName@銆丂mk_city@銆丂appname@銆丂bid@銆丂month@銆丂week@銆丂day@',
+      // tooltip: '鏂囨湰绫诲瀷锛屼細鏇挎崲鍐呭涓殑@username@銆丂fullName@銆丂mk_city@銆丂appname@銆丂bid@銆丂month@銆丂week@銆丂day@',
       required: true
     },
     {
@@ -229,11 +256,12 @@
       required: true
     },
     {
-      type: 'select',
+      type: cards.subtype === 'propcard' && cards.wrap.datatype === 'static' ? 'text' : 'select',
       key: 'posterField',
       label: '棰勮鍦板潃',
       initVal: card.posterField || '',
-      required: true
+      required: true,
+      options: fields
     },
     {
       type: 'radio',
@@ -301,6 +329,7 @@
         { value: 'YYYY-MM', text: 'YYYY-MM' },
         { value: 'YYYY-MM-DD HH:mm', text: 'YYYY-MM-DD HH:mm' },
         { value: 'YYYY-MM-DD HH:mm:ss', text: 'YYYY-MM-DD HH:mm:ss' },
+        { value: 'YYYY骞碝M鏈圖D鏃�', text: 'YYYY骞碝M鏈圖D鏃�' },
       ]
     },
     {
@@ -427,12 +456,12 @@
     {
       type: 'number',
       key: 'width',
-      min: 0.5,
+      min: 0,
       max: 24,
       precision: 1,
       label: '鍏冪礌瀹藉害',
       initVal: width,
-      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒楋紝鍙缃崐鍒楀嵆.5銆�',
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒楋紝鍙缃崐鍒楀嵆.5銆傛敞锛氫负0鏃跺搴︿緷鎹唴瀹硅嚜閫傚簲锛堟枃鏈�佹暟鍊笺�佹彁绀猴紙鍥炬爣锛夈�佸綋鍓嶆椂闂淬�佸叕寮忥級銆�',
       required: true
     },
     {
@@ -446,14 +475,14 @@
       required: false
     },
     {
-      type: 'select',
+      type: cards.subtype === 'propcard' && cards.wrap.datatype === 'static' ? 'text' : 'select',
       key: 'bgImage',
       label: '鍔ㄦ�佽儗鏅�',
       initVal: card.bgImage || '',
       tooltip: '缁戝畾鏁版嵁婧愬瓧娈碉紝鍙牴鎹繑鍥炲�兼敼鍙樿儗鏅浘銆�',
       required: false,
       allowClear: true,
-      options: [],
+      options: fields,
       forbid: isHeader
     },
     {
@@ -579,7 +608,7 @@
       key: 'link',
       label: '閾炬帴',
       initVal: card.link || '',
-      tooltip: '鍔ㄦ�佸湴鍧�涓虹粦瀹氬瓧娈靛�笺��',
+      tooltip: '鍔ㄦ�佸湴鍧�涓虹粦瀹氬瓧娈靛�笺�備娇鐢� 鍔ㄦ��-鍏宠仈鑿滃崟 鏃讹紝璇峰湪鈥滈摼鎺ュ湴鍧�鈥濆瓧娈佃繑鍥炶彍鍗旾D銆�',
       required: false,
       options: [
         { value: '', text: '鏃�' },
@@ -589,7 +618,7 @@
       forbid: isHeader
     },
     {
-      type: linkTypes.length > 4 ? 'select' : 'radio',
+      type: 'select',
       key: 'linkType',
       label: '閾炬帴绫诲瀷',
       initVal: card.linkType || 'other',
@@ -617,13 +646,23 @@
       forbid: !['pc', 'mob'].includes(appType)
     },
     {
-      type: 'select',
+      type: 'cascader',
+      key: 'linkmenu',
+      label: '鍏宠仈鑿滃崟',
+      initVal: card.linkmenu || [],
+      required: true,
+      options: menulist,
+      forbid: ['pc', 'mob'].includes(appType)
+    },
+    {
+      type: cards.subtype === 'propcard' && cards.wrap.datatype === 'static' ? 'text' : 'select',
+      defType: cards.subtype === 'propcard' && cards.wrap.datatype === 'static' ? 'text' : 'select',
       key: 'linkurl',
       label: '閾炬帴鍦板潃',
       initVal: card.linkurl || '',
       tooltip: ['pc', 'mob'].includes(appType) ? '褰撻摼鎺ョ被鍨嬩负鈥滃叾浠栤�濓紝涓旈摼鎺ュ湴鍧�浠menuid@寮�澶存椂锛屽叾鍚庡唴瀹瑰皢琚涓鸿彍鍗旾D銆�' : '',
       required: true,
-      options: []
+      options: fields
     },
     {
       type: 'radio',
@@ -653,11 +692,11 @@
       }]
     },
     {
-      type: 'textarea',
+      type: 'codemirror',
       key: 'formula',
       label: '鍏紡',
       initVal: card.formula || '',
-      tooltip: '鎵ц鏃朵細浣跨敤鏌ヨ鍒扮殑鏁版嵁鏇挎崲鐩稿簲鐨勫瓧娈碉紝灞曠ず鑾峰緱鐨勭粨鏋滐紝鍦ㄤ笉浣跨敤瑙f瀽鏃舵崲琛岀鎴栫┖鏍间細鏇挎崲涓洪〉闈㈠厓绱犮�傚彲浣跨敤JS鐨勪竴浜涜娉曪紝濡傦細涓夊厓琛ㄨ揪寮� @field1@ > @field2@ ? 0 : 1锛汳ath瀵硅薄锛屽彇缁濆鍊� Math.abs(@field@)銆佸洓鑸嶄簲鍏� Math.round(@field@)绛�',
+      tooltip: '鎵ц鏃朵細浣跨敤鏌ヨ鍒扮殑鏁版嵁鏇挎崲鐩稿簲鐨勫瓧娈碉紝灞曠ず鑾峰緱鐨勭粨鏋滐紝鍦ㄤ笉浣跨敤瑙f瀽鏃舵崲琛岀鎴栫┖鏍间細鏇挎崲涓洪〉闈㈠厓绱犮�傚彲浣跨敤JS鐨勪竴浜涜娉曪紝濡傦細涓夊厓琛ㄨ揪寮� @field1@ > @field2@ ? 0 : 1锛汳ath瀵硅薄锛屽彇缁濆鍊� Math.abs(@field@)銆佸洓鑸嶄簲鍏� Math.round(@field@)绛夈�傛敞锛氫細鏇挎崲鍏紡涓殑@username@銆丂fullName@銆丂bid@銆�',
       placeholder: '渚嬪锛欯price@ * @number@',
       required: true
     },
@@ -773,6 +812,56 @@
       options: [],
       forbid: !isHeader
     },
+    {
+      type: 'table',
+      key: 'signs',
+      label: '鏍囪',
+      initVal: card.signs || [],
+      tooltip: '鍙緷鎹爣绛惧唴瀹硅缃笉鍚屾牱寮忋��',
+      required: false,
+      actions: ['edit', 'del', 'add', 'move'],
+      columns: [
+        {
+          title: '鍊�',
+          dataIndex: 'value',
+          inputType: 'text',
+          editable: true,
+          required: true,
+          unique: true,
+          width: '20%'
+        },
+        {
+          title: '鑳屾櫙',
+          dataIndex: 'background',
+          inputType: 'color',
+          className: 'mini-color',
+          editable: true,
+          required: true,
+          width: '20%',
+          render: (text) => <span className="mk-color-value" style={{background: text}}></span>,
+        },
+        {
+          title: '鏂囧瓧',
+          dataIndex: 'color',
+          inputType: 'color',
+          className: 'mini-color',
+          editable: true,
+          required: true,
+          width: '20%',
+          render: (text) => <span className="mk-color-value" style={{background: text}}></span>,
+        },
+        {
+          title: '杈规',
+          dataIndex: 'border',
+          inputType: 'color',
+          className: 'mini-color',
+          editable: true,
+          required: true,
+          width: '20%',
+          render: (text) => <span className="mk-color-value" style={{background: text}}></span>,
+        },
+      ]
+    },
   ]
 
   return forms
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index b58ca78..50386cc 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -24,11 +24,12 @@
 
 class CardCellComponent extends Component {
   static propTpyes = {
-    cards: PropTypes.object,         // 鑿滃崟閰嶇疆淇℃伅
+    cards: PropTypes.object,
     cardCell: PropTypes.object,
     side: PropTypes.string,
-    elements: PropTypes.array,       // 鍏冪礌闆�
-    updateElement: PropTypes.func    // 鑿滃崟閰嶇疆鏇存柊
+    timestamp: PropTypes.any,
+    elements: PropTypes.array,
+    updateElement: PropTypes.func
   }
 
   state = {
@@ -74,7 +75,7 @@
   }
 
   UNSAFE_componentWillReceiveProps(nextProps) {
-    if (this.props.side !== nextProps.side && nextProps.side) {
+    if (this.props.timestamp !== nextProps.timestamp && nextProps.timestamp) {
       this.setState({
         elements: fromJS(nextProps.elements).toJS()
       })
@@ -150,9 +151,13 @@
       } else {
         options.push('width', 'minHeight', 'float')
         _style.minHeight = _style.minHeight || '28px'
+        _style.textAlign = _style.textAlign || 'center'
       }
+
       if (element.wrapStyle) {
         _style.float = element.wrapStyle.textAlign || 'left'
+      } else {
+        _style.float = _style.float || 'center'
       }
     } else if (element.eleType === 'picture') {
       options = ['background', 'border', 'margin']
@@ -168,8 +173,12 @@
     } else if (element.eleType === 'splitline') {
       options = ['padding', 'margin']
     }
+    if (['text', 'number', 'formula', 'currentDate'].includes(element.eleType)) {
+      options.push('fontFamily')
+      _style.fontFamily = _style.fontFamily ? _style.fontFamily.split(',') : []
+    }
 
-    if (element.eleType !== 'button') {
+    if (element.eleType !== 'button' && element.eleType !== 'tag') {
       options.push('position')
     }
 
@@ -203,8 +212,16 @@
     let _card = fromJS(card).toJS()
 
     if (['text', 'number', 'formula', 'currentDate', 'sequence', 'icon'].includes(_card.eleType)) {
-      _card.style = style
+      _card.style = fromJS(style).toJS()
       let line = _card.height || null
+
+      if (style.fontFamily) {
+        if (style.fontFamily.length === 0) {
+          delete _card.style.fontFamily
+        } else {
+          _card.style.fontFamily = style.fontFamily.join(',')
+        }
+      }
 
       if (['currentDate', 'sequence'].includes(_card.eleType) || (_card.eleType === 'icon' && _card.tipType !== 'text')) {
         line = 1
@@ -238,9 +255,17 @@
     } else if (_card.eleType === 'button') { // 鎷嗗垎style
       _card.style = fromJS(style).toJS()
 
-      if (style.float) {
+      if (style.float === 'center') {
+        delete _card.style.float
+      } else if (style.float) {
         _card.wrapStyle = {textAlign: style.float}
         delete _card.style.float
+      }
+      if (style.textAlign === 'center') {
+        delete _card.style.textAlign
+      }
+      if (style.minHeight === '28px') {
+        delete _card.style.minHeight
       }
     } else if (_card.eleType === 'picture') {
       _card.style = style
@@ -322,7 +347,7 @@
       this.setState({
         actvisible: true,
         card: card,
-        formlist: getBaseTableActionForm(card, functip, cards, usefulFields, modules)
+        formlist: getBaseTableActionForm(card, functip, cards, usefulFields, modules, 'line')
       })
     } else {
       let anchors = MenuUtils.getAnchors(menu.components, cards.uuid) || []
@@ -330,7 +355,7 @@
       this.setState({
         actvisible: true,
         card: card,
-        formlist: getActionForm(card, functip, cards, usefulFields, modules, anchors, side)
+        formlist: getActionForm(card, functip, cards, usefulFields, modules, anchors, side, 'line')
       })
     }
   }
@@ -379,6 +404,9 @@
           if (!['text', 'number', 'icon'].includes(res.eleType)) {
             delete res.style.display
           }
+          if (!['text', 'number', 'formula', 'currentDate'].includes(res.eleType)) {
+            delete res.style.fontFamily
+          }
           
           if (res.eleType === 'splitline' && (cell.eleType !== 'splitline' || cell.focus)) {
             res.style.paddingTop = '5px'
@@ -423,6 +451,21 @@
             delete res.style.paddingBottom
             delete res.style.paddingLeft
             delete res.style.paddingRight
+          } else if (res.eleType === 'tag') {
+            delete res.style.position
+            if (cell.eleType !== 'tag') {
+              res.style = {
+                backgroundColor: 'var(--mk-sys-color1)',
+                color: 'var(--mk-sys-color)',
+                borderColor: 'var(--mk-sys-color)',
+                borderWidth: '1px',
+                borderRadius: '4px',
+                paddingLeft: '7px',
+                paddingRight: '7px',
+                marginRight: '8px',
+                marginBottom: '8px',
+              }
+            }
           }
           
           return res
@@ -447,6 +490,13 @@
     let color = { primary: '#1890ff', yellow: '#c49f47', orange: 'orange', danger: '#ff4d4f', green: '#26C281', dgreen: '#32c5d2', purple: '#8E44AD', cyan: '#13c2c2', gray: '#666666', default: 'rgba(0, 0, 0, 0.65)' }
 
     this.actionFormRef.handleConfirm().then(res => {
+      if (res.width % 0.5) {
+        res.width = parseInt(res.width / 0.5) * 0.5
+      }
+      if (res.width % 1) {
+        res.width = (res.width + '').replace(/.5/, 'x')
+      }
+      
       let _elements = elements.map(cell => {
         if (cell.uuid === res.uuid) {
           res.eleType = cell.eleType || null
@@ -457,7 +507,8 @@
             if (cell.OpenType !== 'form') {
               res.style = {}
             }
-          } else if (res.class !== cell.class || res.show !== cell.show || !res.style) {
+          // } else if (res.class !== cell.class || res.show !== cell.show || !res.style) {
+          } else if (res.class !== cell.class || !res.style) {
             if (res.class) {
               let cl = res.class.replace('border-', '')
               let style = {}
diff --git a/src/menu/components/card/cardcellcomponent/index.scss b/src/menu/components/card/cardcellcomponent/index.scss
index c8d9688..7006456 100644
--- a/src/menu/components/card/cardcellcomponent/index.scss
+++ b/src/menu/components/card/cardcellcomponent/index.scss
@@ -9,6 +9,7 @@
 
   .card-button-cell {
     float: left;
+    text-align: center;
     button {
       box-shadow: none;
     }
@@ -18,7 +19,7 @@
       background-position: center center;
       height: auto;
       min-height: 28px;
-      text-align: center;
+      text-align: inherit;
       border-width: 0;
       padding: 0;
       overflow: hidden;
@@ -40,6 +41,10 @@
       border-radius: 15px;
     }
   }
+  .card-cell.ant-col-0 {
+    display: block;
+    float: left;
+  }
   .card-cell:hover, .card-button-cell:hover {
     box-shadow: 0px 0px 2px #1890ff;
   }
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index fec3526..823a4b6 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -33,6 +33,7 @@
     formlist: null,        // 璁剧疆琛ㄥ崟淇℃伅
     elements: null,        // 缂栬緫缁�
     side: 'front',
+    timestamp: '',
     appType: sessionStorage.getItem('appType'),
     visible: false
   }
@@ -44,6 +45,7 @@
     const { card } = this.props
 
     this.setState({
+      timestamp: new Date().getTime() + '',
       card: fromJS(card).toJS(),
       elements: fromJS(card.elements).toJS(),
     })
@@ -117,7 +119,7 @@
       _elements = fromJS(card.backElements).toJS()
     }
 
-    this.setState({side: _side, elements: _elements})
+    this.setState({side: _side, elements: _elements, timestamp: new Date().getTime() + ''})
   }
   
   addElement = () => {
@@ -215,9 +217,7 @@
           okText: '纭畾',
           cancelText: '鍙栨秷',
           onOk() {
-            that.setState({ card: _card, side: '', elements: fromJS(_card.elements).toJS() }, () => {
-              that.setState({ side: 'front' })
-            })
+            that.setState({ card: _card, side: 'front', timestamp: new Date().getTime() + '', elements: fromJS(_card.elements).toJS() })
             that.props.updateElement(_card)
           },
           onCancel() {}
@@ -267,6 +267,7 @@
     if (side === 'back' && res.type === 'simple') {
       this.setState({
         side: 'front',
+        timestamp: new Date().getTime() + '',
         elements: fromJS(_card.elements).toJS()
       })
     }
@@ -274,8 +275,121 @@
     this.props.updateElement(_card)
   }
 
+  updateFields = (elements, resolve, type) => {
+    const { card, side } = this.state
+
+    let items = elements
+
+    if (type === 'form') {
+      items = []
+
+      elements.forEach(item => {
+        let cell = {
+          uuid: Utils.getuuid(),
+          eleType: 'text',
+          height: 1,
+          innerHeight: 21,
+          prefix: item.label ? item.label + ': ' : '',
+          datatype: item.field ? 'dynamic' : 'static',
+          field: item.field || '',
+          width: item.span || 12,
+          value: '',
+          style: {marginBottom: '15px'}
+        }
+
+        if (item.type === 'number') {
+          cell.eleType = 'number'
+          cell.decimal = typeof(item.decimal) === 'number' ? item.decimal : ''
+        }
+
+        items.push(cell)
+      })
+    }
+
+    if (items.length === 0) {
+      resolve({status: false, message: '鍏冪礌涓嶅彲涓虹┖锛�'})
+      return
+    }
+
+    let _card = { ...card }
+    let _card2 = { ...card }
+    let pass = false
+
+    if (side === 'back') {
+      if (!_card.backElements || _card.backElements.length === 0) {
+        _card.backElements = items
+        pass = true
+      } else {
+        _card.backElements = items
+        _card2.backElements = [...card.backElements, ...items]
+      }
+    } else {
+      if (!_card.elements || _card.elements.length === 0) {
+        _card.elements = items
+        pass = true
+      } else {
+        _card.elements = items
+        _card2.elements = [...card.elements, ...items]
+      }
+    }
+
+    if (pass) {
+      this.setState({
+        card: _card,
+        timestamp: new Date().getTime() + '',
+        elements: side === 'back' ? fromJS(_card.backElements).toJS() : fromJS(_card.elements).toJS()
+      })
+
+      this.props.updateElement(_card)
+    } else {
+      const that = this
+      const _modal = confirm({
+        title: '鍗$墖涓凡瀛樺湪鍏冪礌锛岃閫夋嫨瑕佽繘琛岀殑鎿嶄綔銆�',
+        className: 'mk-confirm-modal',
+        content: <div className="footer">
+          <Button key="cancel" onClick={() => _modal.destroy()}>鍙栨秷</Button>
+          <Button key="replace" className="mk-border-purple" onClick={() => {
+            that.setState({
+              card: _card,
+              timestamp: new Date().getTime() + '',
+              elements: side === 'back' ? fromJS(_card.backElements).toJS() : fromJS(_card.elements).toJS()
+            })
+      
+            that.props.updateElement(_card)
+            _modal.destroy()
+          }}>鏇挎崲</Button>
+          <Button key="confirm" className="mk-border-green" onClick={() => {
+            that.setState({
+              card: _card2,
+              timestamp: new Date().getTime() + '',
+              elements: side === 'back' ? fromJS(_card2.backElements).toJS() : fromJS(_card2.elements).toJS()
+            })
+      
+            that.props.updateElement(_card2)
+            _modal.destroy()
+          }}>娣诲姞</Button>
+        </div>
+      })
+    }
+
+    resolve({status: true})
+  }
+
   paste = (element, resolve) => {
     const { card } = this.state
+
+    if (['simpleform', 'forms', 'formgroup', 'cardcell'].includes(element.copyType)) {
+      if (element.copyType === 'simpleform') {
+        this.updateFields(element.subcards[0].fields, resolve, 'form')
+      } else if (element.copyType === 'forms') {
+        this.updateFields(element.fields, resolve, 'form')
+      } else if (element.copyType === 'formgroup') {
+        this.updateFields(element.fields, resolve, 'form')
+      } else {
+        this.updateFields(element.elements, resolve)
+      }
+      return
+    }
 
     let _uuid = Utils.getuuid()
     
@@ -343,7 +457,7 @@
 
   render() {
     const { cards } = this.props
-    const { card, elements, side, visible } = this.state
+    const { card, elements, side, visible, timestamp } = this.state
 
     let _style = {...card.style}
 
@@ -390,7 +504,7 @@
       <Col span={card.setting.width || 6} style={_style_}>
         <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}/>
+          <CardCellComponent cards={cards} cardCell={card} side={side} timestamp={timestamp} 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">
@@ -400,7 +514,7 @@
                   <EditOutlined className="edit" title="缂栬緫"/>
                 </NormalForm>
                 <CopyComponent type="cardcell" card={card}/>
-                <PasteController options={['action', 'customCardElement']} updateConfig={this.paste} />
+                <PasteController options={['action', 'customCardElement', 'simpleform', 'forms', 'formgroup', 'cardcell']} updateConfig={this.paste} />
                 <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} />
                 <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                   <div className="mk-popover-control">
diff --git a/src/menu/components/card/cardcomponent/index.scss b/src/menu/components/card/cardcomponent/index.scss
index 35933f8..fd413e5 100644
--- a/src/menu/components/card/cardcomponent/index.scss
+++ b/src/menu/components/card/cardcomponent/index.scss
@@ -99,3 +99,16 @@
     display: inline;
   }
 }
+
+.mk-confirm-modal {
+  .ant-modal-confirm-btns {
+    display: none;
+  }
+  .footer {
+    margin-top: 24px;
+    text-align: right;
+    .ant-btn {
+      margin-left: 8px;
+    }
+  }
+}
diff --git a/src/menu/components/card/cardsimplecomponent/index.jsx b/src/menu/components/card/cardsimplecomponent/index.jsx
index 2eb816e..d7d2fe6 100644
--- a/src/menu/components/card/cardsimplecomponent/index.jsx
+++ b/src/menu/components/card/cardsimplecomponent/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, Modal, Button } from 'antd'
 import { PlusOutlined, PlusSquareOutlined, EditOutlined, ArrowLeftOutlined, ArrowRightOutlined, SwapOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -11,6 +11,8 @@
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
+
+const { confirm } = Modal
 
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
 const NodesWrap = asyncComponent(() => import('./node-wrap'))
@@ -30,7 +32,8 @@
   state = {
     card: null,            // 鍗$墖淇℃伅
     formlist: null,        // 璁剧疆琛ㄥ崟淇℃伅
-    appType: sessionStorage.getItem('appType')
+    appType: sessionStorage.getItem('appType'),
+    timestamp: ''
   }
 
   /**
@@ -40,7 +43,8 @@
     const { card } = this.props
 
     this.setState({
-      card: fromJS(card).toJS()
+      card: fromJS(card).toJS(),
+      timestamp: new Date().getTime() + ''
     })
   }
 
@@ -187,8 +191,99 @@
     this.props.updateElement(_card)
   }
 
+  updateFields = (elements, resolve, type) => {
+    const { card } = this.state
+
+    let items = elements
+
+    if (type === 'form') {
+      items = []
+
+      elements.forEach(item => {
+        let cell = {
+          uuid: Utils.getuuid(),
+          eleType: 'text',
+          height: 1,
+          innerHeight: 21,
+          prefix: item.label ? item.label + ': ' : '',
+          datatype: item.field ? 'dynamic' : 'static',
+          field: item.field || '',
+          width: item.span || 12,
+          value: '',
+          style: {marginBottom: '15px'}
+        }
+
+        if (item.type === 'number') {
+          cell.eleType = 'number'
+          cell.decimal = typeof(item.decimal) === 'number' ? item.decimal : ''
+        }
+
+        items.push(cell)
+      })
+    }
+
+    if (items.length === 0) {
+      resolve({status: false, message: '鍏冪礌涓嶅彲涓虹┖锛�'})
+      return
+    }
+
+    let _card = { ...card, elements: items }
+    let _card2 = { ...card, elements: [...card.elements, ...items] }
+
+    if (card.elements.length === 0) {
+      this.setState({
+        card: _card,
+        timestamp: new Date().getTime() + ''
+      })
+
+      this.props.updateElement(_card)
+    } else {
+      const that = this
+      const _modal = confirm({
+        title: '鍗$墖涓凡瀛樺湪鍏冪礌锛岃閫夋嫨瑕佽繘琛岀殑鎿嶄綔銆�',
+        className: 'mk-confirm-modal',
+        content: <div className="footer">
+          <Button key="cancel" onClick={() => _modal.destroy()}>鍙栨秷</Button>
+          <Button key="replace" className="mk-border-purple" onClick={() => {
+            that.setState({
+              card: _card,
+              timestamp: new Date().getTime() + ''
+            })
+      
+            that.props.updateElement(_card)
+            _modal.destroy()
+          }}>鏇挎崲</Button>
+          <Button key="confirm" className="mk-border-green" onClick={() => {
+            that.setState({
+              card: _card2,
+              timestamp: new Date().getTime() + ''
+            })
+      
+            that.props.updateElement(_card2)
+            _modal.destroy()
+          }}>娣诲姞</Button>
+        </div>
+      })
+    }
+
+    resolve({status: true})
+  }
+
   paste = (element, resolve) => {
     const { card } = this.state
+
+    if (['simpleform', 'forms', 'formgroup', 'cardcell'].includes(element.copyType)) {
+      if (element.copyType === 'simpleform') {
+        this.updateFields(element.subcards[0].fields, resolve, 'form')
+      } else if (element.copyType === 'forms') {
+        this.updateFields(element.fields, resolve, 'form')
+      } else if (element.copyType === 'formgroup') {
+        this.updateFields(element.fields, resolve, 'form')
+      } else {
+        this.updateFields(element.elements, resolve)
+      }
+      return
+    }
 
     let _uuid = Utils.getuuid()
     
@@ -208,7 +303,7 @@
 
   render() {
     const { cards } = this.props
-    const { card } = this.state
+    const { card, timestamp } = this.state
 
     let _style = {...card.style}
 
@@ -225,7 +320,7 @@
 
     return (
       <div className="card-item" style={_style}>
-        <CardCellComponent cards={cards} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
+        <CardCellComponent cards={cards} cardCell={card} timestamp={timestamp} elements={card.elements} updateElement={this.updateCard}/>
         <div className="card-control">
           <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
             <div className="mk-popover-control">
@@ -235,7 +330,7 @@
                 <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
               </NormalForm> : <NodesWrap card={card} updateMenus={this.updateNodes}/>}
               {cards.type !== 'timeline' ? <CopyComponent type="cardcell" card={card}/> : null}
-              <PasteController options={['action', 'customCardElement']} updateConfig={this.paste} />
+              <PasteController options={['action', 'customCardElement', 'simpleform', 'forms', 'formgroup', 'cardcell']} updateConfig={this.paste} />
               <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
               {control ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                 <div className="mk-popover-control">
diff --git a/src/menu/components/card/cardsimplecomponent/index.scss b/src/menu/components/card/cardsimplecomponent/index.scss
index 0f6054d..a41bcf9 100644
--- a/src/menu/components/card/cardsimplecomponent/index.scss
+++ b/src/menu/components/card/cardsimplecomponent/index.scss
@@ -12,4 +12,17 @@
     cursor: pointer;
     background: rgba(255, 255, 255, 0.55);
   }
+}
+
+.mk-confirm-modal {
+  .ant-modal-confirm-btns {
+    display: none;
+  }
+  .footer {
+    margin-top: 24px;
+    text-align: right;
+    .ant-btn {
+      margin-left: 8px;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/menu/components/card/cardsimplecomponent/options.jsx b/src/menu/components/card/cardsimplecomponent/options.jsx
index f6ca23b..9e177e7 100644
--- a/src/menu/components/card/cardsimplecomponent/options.jsx
+++ b/src/menu/components/card/cardsimplecomponent/options.jsx
@@ -38,16 +38,18 @@
       field: 'condition',
       label: '鏄剧ず鏉′欢',
       initval: setting.condition || 'false',
-      tooltip: '褰撻�夋嫨鈥滄湁鈥濇椂锛屽彧鏈夌鍚堟潯浠剁殑鏁版嵁鎵嶄細灞曠ず銆�',
+      tooltip: '褰撻�夋嫨鈥滆嚜瀹氫箟鈥濇椂锛屽彧鏈夌鍚堟潯浠剁殑鏁版嵁鎵嶄細灞曠ず銆傚綋閫夋嫨鈥滄爣棰樷�濇椂锛屽彧鏈夐琛屾墠浼氬睍绀�',
       required: false,
       options: [
-        {value: 'true', label: '鏈�'},
-        {value: 'false', label: '鏃�'},
+        {value: 'false', label: '濮嬬粓鏄剧ず'},
+        {value: 'true', label: '鑷畾涔�'},
+        {value: 'title', label: '鏍囬'},
       ],
       controlFields: [
         {field: 'controlField', values: ['true']},
         {field: 'controlType', values: ['true']},
         {field: 'controlValue', values: ['true']},
+        {field: 'click', values: ['true', 'false']},
       ]
     },
     {
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index b16fec5..7bb0284 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/components/card/data-card/index.jsx
@@ -370,6 +370,19 @@
   updateWrap = (res) => {
     const { card } = this.state
 
+    if (res.interaction) {
+      if (res.interaction.includes('scale')) {
+        res.scale = 'true'
+      }
+      if (res.interaction.includes('parity')) {
+        res.parity = 'true'
+      }
+      if (res.interaction.includes('hover')) {
+        res.hover = 'true'
+      }
+      delete res.interaction
+    }
+
     let _card = {...card, wrap: res}
 
     if (res.supNodes) {
@@ -538,7 +551,7 @@
             <PlusOutlined className="plus" title="娣诲姞鍗$墖" onClick={() => this.addCard()}/>
             {appType !== 'mob' ? <PlusCircleOutlined className="plus" title="娣诲姞鎼滅储" onClick={() => this.addSearch()}/> : null}
             <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={() => this.addButton()}/>
-            <NormalForm title="鏁版嵁鍗¤缃�" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
+            <NormalForm title="鏁版嵁鍗¤缃�" width={850} update={this.updateWrap} getForms={this.getWrapForms}>
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="datacard" card={card}/>
diff --git a/src/menu/components/card/data-card/index.scss b/src/menu/components/card/data-card/index.scss
index 8c298e3..43ac9dc 100644
--- a/src/menu/components/card/data-card/index.scss
+++ b/src/menu/components/card/data-card/index.scss
@@ -20,7 +20,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-color: #ffffff;
     background-position: center center;
diff --git a/src/menu/components/card/data-card/options.jsx b/src/menu/components/card/data-card/options.jsx
index 22cd055..2c480ad 100644
--- a/src/menu/components/card/data-card/options.jsx
+++ b/src/menu/components/card/data-card/options.jsx
@@ -59,6 +59,74 @@
     }
   }
 
+  let interaction = []
+  let interOptions = []
+
+  if (wrap.scale === 'true') {
+    interaction.push('scale')
+  }
+  if (wrap.parity === 'true') {
+    interaction.push('parity')
+  }
+  if (wrap.hover === 'true') {
+    interaction.push('hover')
+  }
+
+  if (subtype === 'datacard') {
+    interOptions = [
+      {value: 'parity', label: '濂囧伓寮傝壊'},
+    ]
+    if (appType !== 'mob') {
+      interOptions.push(
+        {value: 'hover', label: '鎮诞鍙樿壊'},
+        {value: 'scale', label: '鎮诞鏀惧ぇ'}
+      )
+    }
+  } else if (subtype === 'propcard' && appType !== 'mob') {
+    interOptions = [
+      {value: 'scale', label: '鎮诞鏀惧ぇ'}
+    ]
+  } else if (subtype === 'tablecard') {
+    interOptions = [
+      {value: 'parity', label: '濂囧伓寮傝壊'},
+    ]
+    if (appType !== 'mob') {
+      interOptions.push(
+        {value: 'hover', label: '鎮诞鍙樿壊'}
+      )
+    }
+  }
+
+  if (interaction.length && interOptions.length) {
+    interaction = interaction.filter(m => interOptions.findIndex(cell => cell.value === m) > -1)
+  }
+
+  // let interItem = null
+
+  // if (interOptions.length === 1) {
+  //   interItem = {
+  //     type: 'radio',
+  //     field: interOptions[0].value,
+  //     label: interOptions[0].label,
+  //     initval: interaction.length === 1 ? 'true' : 'false',
+  //     required: false,
+  //     options: [
+  //       {value: 'true', label: '鍚敤'},
+  //       {value: 'false', label: '绂佺敤'}
+  //     ]
+  //   }
+  // } else {
+  //   interItem = {
+  //     type: 'checkbox',
+  //     field: 'interaction',
+  //     label: '浜や簰鏁堟灉',
+  //     initval: interaction,
+  //     required: false,
+  //     options: interOptions,
+  //     forbid: interOptions.length === 0
+  //   }
+  // }
+
   const cardWrapForm = [
     {
       type: 'text',
@@ -306,31 +374,27 @@
       ],
       forbid: subtype !== 'datacard' || appType === 'mob'
     },
+    // {
+    //   type: 'radio',
+    //   field: 'scale',
+    //   label: '鏀惧ぇ鏁堟灉',
+    //   initval: wrap.scale || 'false',
+    //   tooltip: '榧犳爣鎮诞浜庡崱鐗囦笂鏂规椂锛屽崱鐗囨斁澶�1.05鍊嶃��',
+    //   required: false,
+    //   options: [
+    //     {value: 'false', label: '鏃�'},
+    //     {value: 'true', label: '鏈�'},
+    //   ],
+    //   forbid: subtype === 'tablecard' || appType === 'mob'
+    // },
     {
-      type: 'radio',
-      field: 'scale',
-      label: '鏀惧ぇ鏁堟灉',
-      initval: wrap.scale || 'false',
-      tooltip: '榧犳爣鎮诞浜庡崱鐗囦笂鏂规椂锛屽崱鐗囨斁澶�1.05鍊嶃��',
+      type: 'checkbox',
+      field: 'interaction',
+      label: '浜や簰鏁堟灉',
+      initval: interaction,
       required: false,
-      options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'true', label: '鏈�'},
-      ],
-      forbid: subtype === 'tablecard' || appType === 'mob'
-    },
-    {
-      type: 'radio',
-      field: 'parity',
-      label: '濂囧伓鑳屾櫙',
-      initval: wrap.parity || 'false',
-      tooltip: '鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
-      required: false,
-      options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'true', label: '鏈�'},
-      ],
-      forbid: subtype === 'propcard'
+      options: interOptions,
+      forbid: interOptions.length === 0
     },
     {
       type: 'radio',
@@ -610,6 +674,19 @@
     },
     {
       type: 'radio',
+      field: 'searchBtn',
+      label: '鎼滅储鎸夐挳',
+      initval: wrap.searchBtn || 'hidden',
+      // tooltip: '鍚敤鎼滅储鏉′欢缂撳瓨鍚庯紝鍦ㄨ彍鍗曞埛鏂版椂鎼滅储鏉′欢涓嶅彉銆�',
+      required: false,
+      options: [
+        {value: 'hidden', label: '闅愯棌'},
+        {value: 'show', label: '鏄剧ず'},
+      ],
+      forbid: appType === 'mob' || isprint,
+    },
+    {
+      type: 'radio',
       field: 'shifting',
       label: '鎸夐挳鍋忕Щ',
       initval: wrap.shifting || 'false',
@@ -669,7 +746,7 @@
           width: '20%'
         },
         {
-          title: '鑿滃崟',
+          title: '缁勪欢',
           dataIndex: 'nodes',
           inputType: 'cascader',
           editable: true,
diff --git a/src/menu/components/card/double-data-card/index.scss b/src/menu/components/card/double-data-card/index.scss
index 40ea29c..722a29f 100644
--- a/src/menu/components/card/double-data-card/index.scss
+++ b/src/menu/components/card/double-data-card/index.scss
@@ -20,7 +20,7 @@
   }
 
   .card-item, .card-item-wrap {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-color: #ffffff;
     background-position: center center;
diff --git a/src/menu/components/card/double-data-card/options.jsx b/src/menu/components/card/double-data-card/options.jsx
index 16d9f40..7d632f0 100644
--- a/src/menu/components/card/double-data-card/options.jsx
+++ b/src/menu/components/card/double-data-card/options.jsx
@@ -133,21 +133,21 @@
       tooltip: '鏁版嵁鍗″彸涓婅浼氭樉绀烘敹璧峰紑鍏炽��',
       required: false,
       options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'true', label: '鏈�'},
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
       ],
       forbid: appType === 'mob'
     },
     {
       type: 'radio',
       field: 'parity',
-      label: '濂囧伓鑳屾櫙',
+      label: '濂囧伓寮傝壊',
       initval: wrap.parity || 'false',
-      tooltip: '鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
+      tooltip: '瀛愯〃鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
       required: false,
       options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'true', label: '鏈�'},
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
       ],
     },
     {
diff --git a/src/menu/components/card/doublecardcomponent/index.jsx b/src/menu/components/card/doublecardcomponent/index.jsx
index cc2e64a..0507417 100644
--- a/src/menu/components/card/doublecardcomponent/index.jsx
+++ b/src/menu/components/card/doublecardcomponent/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Col } from 'antd'
+import { Popover, Col, Modal, Button } from 'antd'
 import { UpOutlined, PlusOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -11,6 +11,8 @@
 import Utils from '@/utils/utils.js'
 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'))
@@ -28,6 +30,7 @@
     card: null,            // 鍗$墖淇℃伅锛屽寘鎷鍙嶉潰
     appType: sessionStorage.getItem('appType'),
     visible: false,
+    timestamp: '',
     side: ''
   }
 
@@ -38,7 +41,8 @@
     const { card } = this.props
 
     this.setState({
-      card: fromJS(card).toJS()
+      card: fromJS(card).toJS(),
+      timestamp: new Date().getTime() + ''
     })
   }
 
@@ -208,8 +212,118 @@
     this.props.updateElement(_card)
   }
 
+  updateFields = (elements, resolve, position, type) => {
+    const { card } = this.state
+
+    let items = elements
+
+    if (type === 'form') {
+      items = []
+
+      elements.forEach(item => {
+        let cell = {
+          uuid: Utils.getuuid(),
+          eleType: 'text',
+          height: 1,
+          innerHeight: 21,
+          prefix: item.label ? item.label + ': ' : '',
+          datatype: item.field ? 'dynamic' : 'static',
+          field: item.field || '',
+          width: item.span || 12,
+          value: '',
+          style: {marginBottom: '15px'}
+        }
+
+        if (item.type === 'number') {
+          cell.eleType = 'number'
+          cell.decimal = typeof(item.decimal) === 'number' ? item.decimal : ''
+        }
+
+        items.push(cell)
+      })
+    }
+
+    if (items.length === 0) {
+      resolve({status: false, message: '鍏冪礌涓嶅彲涓虹┖锛�'})
+      return
+    }
+
+    let _card = { ...card }
+    let _card2 = { ...card }
+    let pass = false
+
+    if (position === 'sub') {
+      if (_card.backElements.length === 0) {
+        _card.backElements = items
+        pass = true
+      } else {
+        _card.backElements = items
+        _card2.backElements = [...card.backElements, ...items]
+      }
+    } else {
+      if (_card.elements.length === 0) {
+        _card.elements = items
+        pass = true
+      } else {
+        _card.elements = items
+        _card2.elements = [...card.elements, ...items]
+      }
+    }
+
+    if (pass) {
+      this.setState({
+        card: _card,
+        timestamp: new Date().getTime() + ''
+      })
+
+      this.props.updateElement(_card)
+    } else {
+      const that = this
+      const _modal = confirm({
+        title: '鍗$墖涓凡瀛樺湪鍏冪礌锛岃閫夋嫨瑕佽繘琛岀殑鎿嶄綔銆�',
+        className: 'mk-confirm-modal',
+        content: <div className="footer">
+          <Button key="cancel" onClick={() => _modal.destroy()}>鍙栨秷</Button>
+          <Button key="replace" className="mk-border-purple" onClick={() => {
+            that.setState({
+              card: _card,
+              timestamp: new Date().getTime() + ''
+            })
+      
+            that.props.updateElement(_card)
+            _modal.destroy()
+          }}>鏇挎崲</Button>
+          <Button key="confirm" className="mk-border-green" onClick={() => {
+            that.setState({
+              card: _card2,
+              timestamp: new Date().getTime() + ''
+            })
+      
+            that.props.updateElement(_card2)
+            _modal.destroy()
+          }}>娣诲姞</Button>
+        </div>
+      })
+    }
+
+    resolve({status: true})
+  }
+
   paste = (element, resolve, type) => {
     const { card } = this.state
+
+    if (['simpleform', 'forms', 'formgroup', 'cardcell'].includes(element.copyType)) {
+      if (element.copyType === 'simpleform') {
+        this.updateFields(element.subcards[0].fields, resolve, type, 'form')
+      } else if (element.copyType === 'forms') {
+        this.updateFields(element.fields, resolve, type, 'form')
+      } else if (element.copyType === 'formgroup') {
+        this.updateFields(element.fields, resolve, type, 'form')
+      } else {
+        this.updateFields(element.elements, resolve, type)
+      }
+      return
+    }
 
     let _uuid = Utils.getuuid()
     
@@ -238,7 +352,7 @@
 
   render() {
     const { cards } = this.props
-    const { card } = this.state
+    const { card, timestamp } = this.state
 
     let _style = {...card.style}
     let _backStyle = {...card.backStyle}
@@ -288,14 +402,14 @@
                     <EditOutlined className="edit" title="缂栬緫"/>
                   </NormalForm>
                   <CopyComponent type="cardcell" card={{...card, backElements: []}}/>
-                  <PasteController options={['action', 'customCardElement']} updateConfig={(element, resolve) => this.paste(element, resolve, 'main')} />
+                  <PasteController options={['action', 'customCardElement', 'simpleform', 'forms', 'formgroup', 'cardcell']} updateConfig={(element, resolve) => this.paste(element, resolve, 'main')} />
                   <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={() => this.changeStyle()} />
                 </div>
               } trigger="hover">
                 <ToolOutlined />
               </Popover>
             </div>
-            <CardCellComponent cards={cards} cardCell={card} side="main" elements={card.elements} updateElement={(elements, btn) => this.updateCard(elements, btn)}/>
+            <CardCellComponent cards={cards} cardCell={card} side="main" timestamp={timestamp} elements={card.elements} updateElement={(elements, btn) => this.updateCard(elements, btn)}/>
           </div>
           <Col span={card.backSetting.width || 24}>
             <div className={'card-item ' + (card.backSetting.btnControl || '')} style={_backStyle} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard('sub')}} id={card.uuid}>
@@ -308,14 +422,14 @@
                       <EditOutlined className="edit" title="缂栬緫"/>
                     </NormalForm>
                     <CopyComponent type="cardcell" card={{...card, elements: card.backElements, backElements: []}}/>
-                    <PasteController options={['action', 'customCardElement']} updateConfig={(element, resolve) => this.paste(element, resolve, 'sub')} />
+                    <PasteController options={['action', 'customCardElement', 'simpleform', 'forms', 'formgroup', 'cardcell']} updateConfig={(element, resolve) => this.paste(element, resolve, 'sub')} />
                     <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={() => this.changeStyle('sub')} />
                   </div>
                 } trigger="hover">
                   <ToolOutlined />
                 </Popover>
               </div>
-              <CardCellComponent cards={cards} cardCell={card} side="sub" elements={card.backElements} updateElement={(elements, btn) => this.updateCard(elements, btn, 'sub')}/>
+              <CardCellComponent cards={cards} cardCell={card} side="sub" timestamp={timestamp} elements={card.backElements} updateElement={(elements, btn) => this.updateCard(elements, btn, 'sub')}/>
             </div>
           </Col>
         </div>
diff --git a/src/menu/components/card/doublecardcomponent/index.scss b/src/menu/components/card/doublecardcomponent/index.scss
index 63e0e13..cc9f94f 100644
--- a/src/menu/components/card/doublecardcomponent/index.scss
+++ b/src/menu/components/card/doublecardcomponent/index.scss
@@ -117,3 +117,16 @@
     display: inline-block;
   }
 }
+
+.mk-confirm-modal {
+  .ant-modal-confirm-btns {
+    display: none;
+  }
+  .footer {
+    margin-top: 24px;
+    text-align: right;
+    .ant-btn {
+      margin-left: 8px;
+    }
+  }
+}
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
index ff9f81e..c0b2914 100644
--- a/src/menu/components/card/prop-card/index.jsx
+++ b/src/menu/components/card/prop-card/index.jsx
@@ -315,6 +315,13 @@
   updateWrap = (res) => {
     const { card } = this.state
 
+    if (res.interaction) {
+      if (res.interaction.includes('scale')) {
+        res.scale = 'true'
+      }
+      delete res.interaction
+    }
+
     let _card = {...card, wrap: res}
 
     if (res.datatype === 'static') {
diff --git a/src/menu/components/card/prop-card/index.scss b/src/menu/components/card/prop-card/index.scss
index 5e0c1e5..21c1ad6 100644
--- a/src/menu/components/card/prop-card/index.scss
+++ b/src/menu/components/card/prop-card/index.scss
@@ -19,7 +19,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-color: #ffffff;
     background-position: center center;
diff --git a/src/menu/components/card/table-card/index.jsx b/src/menu/components/card/table-card/index.jsx
index dd96ddb..5672f99 100644
--- a/src/menu/components/card/table-card/index.jsx
+++ b/src/menu/components/card/table-card/index.jsx
@@ -271,6 +271,15 @@
   }
 
   updateWrap = (res) => {
+    if (res.interaction) {
+      if (res.interaction.includes('parity')) {
+        res.parity = 'true'
+      }
+      if (res.interaction.includes('hover')) {
+        res.hover = 'true'
+      }
+      delete res.interaction
+    }
     this.updateComponent({...this.state.card, wrap: res})
   }
 
diff --git a/src/menu/components/card/table-card/index.scss b/src/menu/components/card/table-card/index.scss
index aef713c..c8abd8b 100644
--- a/src/menu/components/card/table-card/index.scss
+++ b/src/menu/components/card/table-card/index.scss
@@ -63,6 +63,7 @@
   }
   .ant-pagination {
     text-align: right;
+    margin-top: 10px;
   }
   .mk-more {
     text-align: center;
diff --git a/src/menu/components/carousel/data-card/index.scss b/src/menu/components/carousel/data-card/index.scss
index 7d9fda3..7bbacd7 100644
--- a/src/menu/components/carousel/data-card/index.scss
+++ b/src/menu/components/carousel/data-card/index.scss
@@ -19,7 +19,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-position: center center;
     background-repeat: no-repeat;
diff --git a/src/menu/components/carousel/prop-card/index.scss b/src/menu/components/carousel/prop-card/index.scss
index 07e359f..6c50965 100644
--- a/src/menu/components/carousel/prop-card/index.scss
+++ b/src/menu/components/carousel/prop-card/index.scss
@@ -19,7 +19,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-position: center center;
     background-repeat: no-repeat;
diff --git a/src/menu/components/form/formaction/actionform/index.jsx b/src/menu/components/form/formaction/actionform/index.jsx
index 09c15d7..827b091 100644
--- a/src/menu/components/form/formaction/actionform/index.jsx
+++ b/src/menu/components/form/formaction/actionform/index.jsx
@@ -57,7 +57,7 @@
     } else if (this.record.type === 'close' || this.record.type === 'reset') {
       shows = ['typeName', 'label']
     } else {
-      shows = ['typeName', 'label', 'intertype', 'Ot', 'execSuccess', 'syncComponent', 'anchors', 'linkmenu', 'output', 'reload', 'preButton', 'formCache'] // 閫夐」鍒楄〃
+      shows = ['typeName', 'label', 'intertype', 'Ot', 'execSuccess', 'syncComponent', 'anchors', 'linkmenu', 'output', 'reload', 'preButton'] // 閫夐」鍒楄〃
 
       if (this.record.execSuccess === 'never') {
         shows.push('resetForms')
diff --git a/src/menu/components/form/formaction/formconfig.jsx b/src/menu/components/form/formaction/formconfig.jsx
index 1a4e306..8bb1628 100644
--- a/src/menu/components/form/formaction/formconfig.jsx
+++ b/src/menu/components/form/formaction/formconfig.jsx
@@ -539,21 +539,6 @@
         value: 'true',
         text: '鍒锋柊'
       }]
-    },
-    // {
-    //   type: 'radio',
-    //   key: 'formCache',
-    //   label: '琛ㄥ崟缂撳瓨',
-    //   initVal: card.formCache || 'false',
-    //   tooltip: '涓昏鐢ㄤ簬鏁版嵁淇敼鍚庯紝鏇存柊鐩稿叧琛ㄥ崟鐨勯�夐」锛屾竻绌虹紦瀛樺悗琛ㄥ崟鍐嶆鎵撳紑鏃舵暟鎹細閲嶆柊鍔犺浇銆�',
-    //   required: false,
-    //   options: [{
-    //     value: 'false',
-    //     text: '涓嶆竻绌�'
-    //   }, {
-    //     value: 'clear',
-    //     text: '娓呯┖'
-    //   }]
-    // },
+    }
   ]
 }
diff --git a/src/menu/components/form/simple-form/index.jsx b/src/menu/components/form/simple-form/index.jsx
index 3a0bf93..a394711 100644
--- a/src/menu/components/form/simple-form/index.jsx
+++ b/src/menu/components/form/simple-form/index.jsx
@@ -375,7 +375,7 @@
         })
       }
 
-      if (item.type === 'switch' || item.type === 'check') {
+      if (['switch', 'check', 'popSelect'].includes(item.type)) {
         _linksupFields.push({
           field: item.field,
           label: item.label
diff --git a/src/menu/components/form/step-form/index.jsx b/src/menu/components/form/step-form/index.jsx
index dd919dc..b2a9e85 100644
--- a/src/menu/components/form/step-form/index.jsx
+++ b/src/menu/components/form/step-form/index.jsx
@@ -477,7 +477,7 @@
         })
       }
 
-      if (item.type === 'switch' || item.type === 'check') {
+      if (['switch', 'check', 'popSelect'].includes(item.type)) {
         _linksupFields.push({
           field: item.field,
           label: item.label
diff --git a/src/menu/components/form/tab-form/index.jsx b/src/menu/components/form/tab-form/index.jsx
index 66e8181..ecc6b22 100644
--- a/src/menu/components/form/tab-form/index.jsx
+++ b/src/menu/components/form/tab-form/index.jsx
@@ -482,7 +482,7 @@
         })
       }
 
-      if (item.type === 'switch' || item.type === 'check') {
+      if (['switch', 'check', 'popSelect'].includes(item.type)) {
         _linksupFields.push({
           field: item.field,
           label: item.label
diff --git a/src/menu/components/group/normal-group/index.scss b/src/menu/components/group/normal-group/index.scss
index f616fad..8d1307c 100644
--- a/src/menu/components/group/normal-group/index.scss
+++ b/src/menu/components/group/normal-group/index.scss
@@ -1,7 +1,7 @@
 .menu-group-edit-box {
   position: relative;
   box-sizing: border-box;
-  background: #ffffff;
+  // background: #ffffff;
   background-position: center center;
   background-repeat: no-repeat;
   background-size: cover;
diff --git a/src/menu/components/group/normal-group/options.jsx b/src/menu/components/group/normal-group/options.jsx
index 8b4c290..521a003 100644
--- a/src/menu/components/group/normal-group/options.jsx
+++ b/src/menu/components/group/normal-group/options.jsx
@@ -122,6 +122,34 @@
       ]
     },
     {
+      type: 'radio',
+      field: 'mergeAble',
+      label: '灞曞紑/鏀惰捣',
+      initval: setting.mergeAble || 'false',
+      tooltip: '鍚敤鏃讹紝缁勪欢鍙充笂瑙掑皢鍑虹幇灞曞紑/鏀惰捣鐨勫浘鏍囷紝鍙皢褰撳墠缁勪欢灞曞紑鎴栨敹璧枫��',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
+      ],
+      controlFields: [
+        {field: 'ctrlNumber', values: ['true']},
+      ],
+      forbid: appType === 'mob'
+    },
+    {
+      type: 'number',
+      field: 'ctrlNumber',
+      label: '鎺у埗鏁�',
+      initval: setting.ctrlNumber || 1,
+      tooltip: '褰撶粍浠舵敹璧锋椂锛屽叾鍚庨渶瑕佸睍寮�鐨勭粍浠舵暟銆�',
+      min: 1,
+      max: 5,
+      precision: 0,
+      required: true,
+      forbid: appType === 'mob'
+    },
+    {
       type: 'multiselect',
       field: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/menu/components/module/invoice/index.jsx b/src/menu/components/module/invoice/index.jsx
new file mode 100644
index 0000000..48d84b3
--- /dev/null
+++ b/src/menu/components/module/invoice/index.jsx
@@ -0,0 +1,479 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Popover, Button, Modal } from 'antd'
+import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, EllipsisOutlined, SettingOutlined } from '@ant-design/icons'
+import moment from 'moment'
+
+import Utils from '@/utils/utils.js'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { getTables, checkComponent } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import VerifyCard from './verifycard'
+import getWrapForm from './options'
+
+import './index.scss'
+
+const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+
+class Invoice extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    card: null,
+    date: moment().format('YYYY骞碝M鏈�'),
+    btn: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        width: card.width || 24,
+        name: '鍙戠エ',
+        subtype: card.subtype,
+        wrap: { name: '鍙戠エ', width: card.width || 24, datatype: 'static' },
+        style: { paddingLeft: '20px', paddingRight: '20px', paddingTop: '10px', paddingBottom: '10px' },
+        setting: { interType: 'system', primaryKey: 'ID' },
+        columns: [],
+        scripts: [],
+        buyer: {
+          pageable: true,
+          format: 'array',
+          subtype: 'invTable',
+          setting: { interType: 'system' },
+          columns: [],
+          scripts: [],
+          search: [
+            {field: 'from_to_name', label: '浼佷笟鍚嶇О', initval: '', type: 'text', match: 'like', uuid: Utils.getuuid()},
+            {field: 'from_to_tax_no', label: '浼佷笟绋庡彿', initval: '', type: 'text', match: 'like', uuid: Utils.getuuid()},
+          ],
+        },
+        detail: {
+          pageable: true,
+          format: 'array',
+          subtype: 'invTable',
+          setting: { interType: 'system' },
+          columns: [],
+          scripts: [],
+          search: [
+            {field: 'productname', label: '鍟嗗搧鍚嶇О', initval: '', type: 'text', match: 'like', uuid: Utils.getuuid()},
+            {field: 'productcode', label: '鍟嗗搧缂栫爜', initval: '', type: 'text', match: 'like', uuid: Utils.getuuid()},
+          ],
+        },
+        billSaveBtn: {type: 'billsave', intertype: 'system', label: '淇濆瓨鍗曟嵁'},
+        billOutBtn: {type: 'billout', intertype: 'custom', label: '鎻愪氦寮�绁�', procMode: 'system'},
+      }
+
+      let buys = [
+        ['浼佷笟鍚嶇О', 'from_to_name'],
+        ['浼佷笟绋庡彿', 'from_to_tax_no'],
+        ['鍦板潃', 'from_to_addr', 'Nvarchar(100)'],
+        ['鐢佃瘽', 'from_to_tel'],
+        ['寮�鎴疯', 'from_to_bank_name'],
+        ['閾惰璐﹀彿', 'from_to_account_no'],
+        ['鎵嬫満鍙�', 'from_to_mob'],
+        ['閭', 'from_to_email'],
+        ['浼佷笟缂栫爜', 'from_to_code']
+      ]
+
+      buys.forEach((cell, index) => {
+        _card.buyer.columns.push({$index: index + 1, datatype: 'Nvarchar(50)', field: cell[1], label: cell[0], uuid: Utils.getuuid()})
+      })
+
+      let details = [
+        ['id', 'id'],
+        ['鍟嗗搧缂栫爜', 'productcode'],
+        ['鍟嗗搧鍚嶇О', 'productname'],
+        ['瑙勬牸鍨嬪彿', 'spec'],
+        ['鎻忚堪', 'Description'],
+        ['璁¢噺鍗曚綅', 'unit'],
+        ['鍗曚环', 'unitprice', 'Decimal(18,10)'],
+        ['绋庡姟鍒嗙被缂栫爜', 'tax_classify_code'],
+        ['绋庡姟鍒嗙被鍚嶇О', 'tax_classify_name'],
+        // ['绋庣巼', 'tax_rate', 'Decimal(18,2)'],
+        ['涓�鑸撼绋庝汉绋庣巼', 'general_tax_rate', 'Decimal(18,2)'],
+        ['灏忚妯$撼绋庝汉寰佹敹鐜�', 'small_tax_rate', 'Decimal(18,2)'],
+        ['鏄惁浜彈浼樻儬鏀跨瓥', 'free_tax_mark'],
+        ['浼樻儬鏀跨瓥绫诲瀷', 'vat_special_management'],
+      ]
+
+      details.forEach((cell, index) => {
+        _card.detail.columns.push({$index: index + 1, datatype: cell[2] || 'Nvarchar(50)', field: cell[1], label: cell[0], uuid: Utils.getuuid()})
+      })
+
+      let cols = [
+        ['ID', 'ID'],
+        ['寮�绁ㄧ敵璇峰崟鍙�', 'io'],
+        ['鍙戠エ绉嶇被', 'invoice_type'],
+        ['璐拱鏂瑰悕绉�', 'from_to_name'],
+        ['璐拱鏂圭◣鍙�', 'from_to_tax_no'],
+        ['璐拱鏂瑰湴鍧�', 'from_to_addr', 'Nvarchar(100)'],
+        ['璐拱鏂圭數璇�', 'from_to_tel'],
+        ['璐拱鏂瑰紑鎴疯', 'from_to_bank_name'],
+        ['璐拱鏂归摱琛岃处鍙�', 'from_to_account_no'],
+        ['璐拱鏂规墜鏈哄彿', 'from_to_mob'],
+        ['璐拱鏂归偖绠�', 'from_to_email'],
+        ['璐拱鏂圭紪鐮�', 'from_to_code'],
+        ['閿�鍞柟鍚嶇О', 'orgname'],
+        ['閿�鍞柟绋庡彿', 'tax_no'],
+        ['閿�鍞柟鍦板潃', 'addr', 'Nvarchar(100)'],
+        ['閿�鍞柟鐢佃瘽', 'tel'],
+        ['閿�鍞柟寮�鎴疯', 'bank_name'],
+        ['閿�鍞柟閾惰璐﹀彿', 'account_no'],
+        ['澶囨敞', 'remark', 'Nvarchar(512)'],
+        ['鏀舵浜�', 'payee'],
+        ['澶嶆牳浜�', 'reviewer'],
+        ['寮�绁ㄤ汉', 'drawer'],
+        ['琛屽彿', 'invoice_lp'],
+        ['鍟嗗搧缂栫爜', 'productcode'],
+        ['鍟嗗搧鍚嶇О', 'productname'],
+        ['瑙勬牸鍨嬪彿', 'spec'],
+        ['璁¢噺鍗曚綅', 'unit'],
+        ['鏁伴噺', 'bill_count', 'Decimal(18,10)'],
+        ['鍗曚环', 'unitprice', 'Decimal(18,10)'],
+        ['閲戦', 'amount_line', 'Decimal(18,2)'],
+        ['绋庡姟鍒嗙被缂栫爜', 'tax_classify_code'],
+        ['绋庡姟鍒嗙被鍚嶇О', 'tax_classify_name'],
+        ['绋庣巼', 'tax_rate', 'Decimal(18,2)'],
+        ['绋庨', 'tax_amount', 'Decimal(18,2)'],
+      ]
+
+      cols.forEach((cell, index) => {
+        _card.columns.push({$index: index + 1, datatype: cell[2] || 'Nvarchar(50)', field: cell[1], label: cell[0], uuid: Utils.getuuid()})
+      })
+
+      this.updateComponent(_card)
+    } else {
+      let _card = fromJS(card).toJS()
+
+      this.setState({
+        card: _card
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (card) => {
+    card.width = card.wrap.width
+    card.name = card.wrap.name
+    
+    if (window.GLOB.styling && card.errors) { // 鏍峰紡淇敼鏃朵笉鍋氱瓫鏌�
+      this.setState({
+        card: card
+      })
+  
+      this.props.updateConfig(card)
+      return
+    }
+
+    card.$c_ds = card.wrap.datatype === 'dynamic'
+    card.errors = checkComponent(card)
+
+    if (card.errors.length === 0) {
+      if (card.buyer.setting.interType === 'system' && card.buyer.setting.execute !== 'false' && !card.buyer.setting.dataresource) {
+        card.errors.push({ level: 0, detail: '-璐拱鏂� 鏈缃暟鎹簮锛�'})
+      } else if (card.buyer.setting.interType === 'system' && card.buyer.setting.execute === 'false' && card.buyer.scripts.filter(script => script.status !== 'false').length === 0) {
+        card.errors.push({ level: 0, detail: '-璐拱鏂� 鏁版嵁婧愪腑鏃犲彲鐢ㄨ剼鏈紒'})
+      }
+    }
+    if (card.errors.length === 0) {
+      if (card.detail.setting.interType === 'system' && card.detail.setting.execute !== 'false' && !card.detail.setting.dataresource) {
+        card.errors.push({ level: 0, detail: '-鏄庣粏 鏈缃暟鎹簮锛�'})
+      } else if (card.detail.setting.interType === 'system' && card.detail.setting.execute === 'false' && card.detail.scripts.filter(script => script.status !== 'false').length === 0) {
+        card.errors.push({ level: 0, detail: '-鏄庣粏 鏁版嵁婧愪腑鏃犲彲鐢ㄨ剼鏈紒'})
+      }
+    }
+
+    if (!card.billSaveBtn.scripts || card.billSaveBtn.scripts.length === 0) {
+      card.errors.push({ level: 0, detail: '鏈坊鍔犲崟鎹繚瀛樿剼鏈紒'})
+    // } else if (!card.billOutBtn.scripts || card.billOutBtn.scripts.length === 0) {
+    //   card.errors.push({ level: 0, detail: '鏈坊鍔犳彁浜ゅ紑绁ㄥ墠缃剼鏈紒'})
+    // } else if (card.billSaveBtn.cbScripts.length === 0) {
+    //   card.errors.push({ level: 0, detail: '鏈坊鍔犳彁浜ゅ紑绁ㄥ洖璋冭剼鏈紒'})
+    }
+
+    if (card.errors.length === 0) {
+      card.$tables = getTables(card)
+      card.$tables = [...card.$tables, ...getTables(card.buyer)]
+      card.$tables = [...card.$tables, ...getTables(card.detail)]
+    }
+
+    this.setState({
+      card: card
+    })
+
+    this.props.updateConfig(card)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+  }
+
+  getStyle = (style) => {
+    let _card = {...this.state.card, style}
+    
+    this.updateComponent(_card)
+  }
+
+  getWrapForms = () => {
+    const { card } = this.state
+
+    return getWrapForm(card.wrap)
+  }
+
+  updateWrap = (res) => {
+    this.updateComponent({...this.state.card, wrap: res})
+  }
+
+  verifySubmit = () => {
+    this.verifyRef.handleConfirm().then(res => {
+      if (res.type === 'billout') {
+        this.updateComponent({...this.state.card, billOutBtn: res})
+      } else {
+        this.updateComponent({...this.state.card, billSaveBtn: res})
+      }
+
+      this.setState({ btn: null })
+    })
+  }
+
+  render() {
+    const { card, date, btn } = this.state
+
+    let style = {...card.style}
+    if (card.wrap.invColor) {
+      style['--inv-color'] = card.wrap.invColor
+    }
+
+    return (
+      <div className="menu-invoice-box" style={style} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <NormalForm title="鍩烘湰璁剧疆" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
+              <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
+            </NormalForm>
+            <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
+            <DeleteOutlined className="close" title="鍒犻櫎缁勪欢" onClick={() => this.props.deletecomponent(card.uuid)} />
+            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/>}
+          </div>
+        } trigger="hover">
+          <ToolOutlined />
+        </Popover>
+        <div className="inv-action">
+          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+            <div className="mk-popover-control">
+              <EditOutlined style={{color: '#1890ff'}} onClick={() => this.setState({btn: card.billSaveBtn})} title="缂栬緫"/>
+            </div>
+          } trigger="hover">
+            <Button className="mk-bill">淇濆瓨鍗曟嵁</Button>
+          </Popover>
+          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+            <div className="mk-popover-control">
+              <EditOutlined style={{color: '#1890ff'}} onClick={() => this.setState({btn: card.billOutBtn})} title="缂栬緫"/>
+            </div>
+          } trigger="hover">
+            <Button className="mk-submit">鎻愪氦寮�绁�</Button>
+          </Popover>
+        </div>
+        <div className="inv-header">
+          <div className="mk-select">璇烽�夋嫨鍙戠エ绉嶇被</div>
+          <div className="date">寮�绁ㄦ棩鏈燂細{date}</div>
+        </div>
+        <div className="inv-body">
+          <div className="inv-main-content">
+            <div className="inv-buyer">
+              <div className="inv-label">璐拱鏂�</div>
+              <div className="inv-content">
+                <div className="mk-input">
+                  <label>鍚嶇О锛�</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟鍚嶇О</span>
+                  <span className="extra">
+                    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                      <div className="mk-popover-control">
+                        <SettingComponent config={card.buyer} updateConfig={(res) => this.updateComponent({...card, buyer: res})} />
+                      </div>
+                    } trigger="hover">
+                      <EllipsisOutlined />
+                    </Popover>
+                  </span>
+                </div>
+                <div className="mk-input">
+                  <label>绾崇◣浜鸿瘑鍒彿锛�</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟绾崇◣浜鸿瘑鍒彿</span>
+                </div>
+                <div className="mk-input">
+                  <label>鍦板潃銆佺數璇濓細</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟鍦板潃</span>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟鐢佃瘽</span>
+                </div>
+                <div className="mk-input">
+                  <label>寮�鎴疯鍙婅处鍙凤細</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟寮�鎴疯</span>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟璐﹀彿</span>
+                </div>
+              </div>
+            </div>
+            <div className="inv-notice">
+              <div className="inv-label">閫氱煡鍒�</div>
+              <div className="inv-content">
+                <div className="mk-input">
+                  <label>鎵嬫満鍙凤細</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟鎵嬫満鍙�</span>
+                </div>
+                <div className="mk-input">
+                  <label>閭锛�</label>
+                  <span className="content">璇疯緭鍏ヨ喘涔版柟閭</span>
+                </div>
+              </div>
+            </div>
+          </div>
+          <div className="inv-details">
+            <div className="detail-wrap">
+              <div className="mk-th">
+                <div className="mk-td">璐х墿鎴栧簲绋庡姵鍔°�佹湇鍔″悕绉�</div>
+                <div className="mk-td">瑙勬牸鍨嬪彿</div>
+                <div className="mk-td">鍗曚綅</div>
+                <div className="mk-td">鏁伴噺</div>
+                <div className="mk-td">鍗曚环锛堝惈绋庯級</div>
+                <div className="mk-td">閲戦锛堝惈绋庯級</div>
+                <div className="mk-td">绋庣巼</div>
+                <div className="mk-td">绋庨</div>
+              </div>
+              <div className="mk-tr">
+                <div className="mk-td mk-left">
+                  <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                    <div className="mk-popover-control">
+                      <SettingComponent config={card.detail} updateConfig={(res) => this.updateComponent({...card, detail: res})} />
+                    </div>
+                  } trigger="hover">
+                    <EllipsisOutlined />
+                  </Popover>
+                </div>
+                <div className="mk-td mk-left"></div>
+                <div className="mk-td mk-left"></div>
+                <div className="mk-td mk-right"></div>
+                <div className="mk-td mk-right"></div>
+                <div className="mk-td mk-right"></div>
+                <div className="mk-td mk-right"></div>
+                <div className="mk-td mk-right"></div>
+              </div>
+              <div className="mk-total">
+                <div className="mk-td">鍚堣</div>
+                <div className="mk-td"></div>
+                <div className="mk-td"></div>
+                <div className="mk-td"></div>
+                <div className="mk-td"></div>
+                <div className="mk-td">锟�12</div>
+                <div className="mk-td"></div>
+                <div className="mk-td">锟�1</div>
+              </div>
+              <div className="mk-upcase">
+                <div className="mk-td">浠风◣鍚堣锛堝ぇ鍐欙級</div>
+                <div className="mk-td"></div>
+                <div className="mk-td">锛堝皬鍐欙級锟�12</div>
+              </div>
+            </div>
+          </div>
+          <div className="inv-main-content">
+            <div className="inv-buyer">
+              <div className="inv-label">閿�鍞柟</div>
+              <div className="inv-content">
+                <div className="mk-input">
+                  <label>鍚嶇О锛�</label>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟鍚嶇О</span>
+                </div>
+                <div className="mk-input">
+                  <label>绾崇◣浜鸿瘑鍒彿锛�</label>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟绾崇◣浜鸿瘑鍒彿</span>
+                </div>
+                <div className="mk-input">
+                  <label>鍦板潃銆佺數璇濓細</label>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟鍦板潃</span>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟鐢佃瘽</span>
+                </div>
+                <div className="mk-input">
+                  <label>寮�鎴疯鍙婅处鍙凤細</label>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟寮�鎴疯</span>
+                  <span className="content">璇疯緭鍏ラ攢鍞柟璐﹀彿</span>
+                </div>
+              </div>
+            </div>
+            <div className="inv-notice">
+              <div className="inv-label">澶囨敞</div>
+              <div className="inv-content" style={{paddingTop: '30px'}}>
+                <div className="mk-input">
+                  <span className="content" style={{height: '80px'}}>璇疯緭鍏ュ娉�</span>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div className="inv-tail">
+          <div className="mk-input">
+            <label>鏀舵浜猴細</label>
+            <span className="content">鏀舵浜�</span>
+          </div>
+          <div className="mk-input">
+            <label>澶嶆牳浜猴細</label>
+            <span className="content">澶嶆牳浜�</span>
+          </div>
+          <div className="mk-input">
+            <label>寮�绁ㄤ汉锛�</label>
+            <span className="content">寮�绁ㄤ汉</span>
+          </div>
+        </div>
+        <Modal
+          wrapClassName="mk-pop-modal"
+          visible={btn !== null}
+          width={'90vw'}
+          maskClosable={false}
+          okText="鎻愪氦"
+          onOk={this.verifySubmit}
+          onCancel={() => {
+            if (this.verifyRef.handleCancel) {
+              this.verifyRef.handleCancel().then(() => {
+                this.setState({ btn: null })
+              })
+            } else {
+              this.setState({ btn: null })
+            }
+          }}
+          destroyOnClose
+        >
+          <VerifyCard card={btn} wrappedComponentRef={(inst) => this.verifyRef = inst}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default Invoice
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/index.scss b/src/menu/components/module/invoice/index.scss
new file mode 100644
index 0000000..13e4eb7
--- /dev/null
+++ b/src/menu/components/module/invoice/index.scss
@@ -0,0 +1,258 @@
+.menu-invoice-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  color: #000000;
+  --inv-color: #13509c;
+
+  .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);
+  }
+
+  .inv-action {
+    text-align: right;
+    margin-right: 30px;
+    .ant-btn {
+      margin-left: 15px;
+      margin-bottom: 5px;
+      height: 30px;
+    }
+    .mk-bill:hover, .mk-bill:active, .mk-bill:focus {
+      color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+    }
+    .mk-submit, .mk-submit:hover, .mk-submit:active, .mk-submit:focus {
+      color: #fff;
+      background-color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+    }
+  }
+  .inv-header {
+    text-align: center;
+    position: relative;
+    height: 70px;
+    margin-right: 30px;
+    .mk-select {
+      position: relative;
+      display: inline-block;
+      width: 390px;
+      font-size: 25px;
+      text-align: center;
+      font-family: kaiti;
+      color: var(--inv-color, #13509c);
+    }
+    .mk-select::before, .mk-select::after {
+      content: '';
+      display: block;
+      width: 100%;
+      position: absolute;
+      border-top: var(--inv-color, #13509c) 1px solid;
+      border-bottom: var(--inv-color, #13509c) 1px solid;
+      height: 1px;
+    }
+    .mk-select::before {
+      bottom: -10px;
+    }
+    .mk-select::after {
+      bottom: -15px;
+    }
+    .date {
+      position: absolute;
+      right: 100px;
+      top: 5px;
+      color: var(--inv-color, #13509c);
+    }
+  }
+
+  .mk-input {
+    position: relative;
+    height: 28px;
+    font-size: 13px;
+    background: transparent;
+    display: flex;
+    padding: 0 5px 0 15px;
+    margin-bottom: 5px;
+    label {
+      display: inline-block;
+      height: 28px;
+      line-height: 28px;
+      text-align: right;
+      color: var(--inv-color, #13509c);
+    }
+    span {
+      display: inline-block;
+      height: 28px;
+      line-height: 28px;
+    }
+    .extra {
+      position: absolute;
+      right: 0px;
+      .anticon-ellipsis {
+        padding: 0 15px;
+      }
+    }
+    .content {
+      flex: 1;
+      border-bottom: 1px solid #d9d9d9;
+      color: #b8b8b8;
+      transition: all 0.3s;
+      padding: 0px 10px;
+    }
+  }
+  .mk-input:hover .content {
+    border-color: var(--inv-color, #13509c);
+  }
+
+  .inv-body {
+    border: var(--inv-color, #13509c) 1px solid;
+    font-size: 13px;
+    margin-right: 30px;
+
+    .inv-main-content {
+      display: flex;
+
+      .inv-buyer, .inv-notice {
+        width: 50%;
+        display: flex;
+        .inv-label {
+          color: var(--inv-color, #13509c);
+          width: 6.25%;
+          display: flex;
+          flex-direction: column;
+          writing-mode: vertical-rl;
+          justify-content: center;
+          align-items: center;
+          letter-spacing: 5px;
+          border-right: var(--inv-color, #13509c) 1px solid;
+        }
+        .inv-content {
+          flex: 1;
+          padding: 8px 0;
+        }
+      }
+      .inv-buyer {
+        border-right: var(--inv-color, #13509c) 1px solid;
+        label {
+          width: 95px;
+          min-width: 95px;
+        }
+      }
+      .inv-notice {
+        .inv-content {
+          padding-top: 45px;
+        }
+        label {
+          width: 75px;
+          min-width: 75px;
+        }
+      }
+    }
+
+    .inv-details {
+      border-top: var(--inv-color, #13509c) 1px solid;
+      border-bottom: var(--inv-color, #13509c) 1px solid;
+    }
+  }
+  .inv-tail {
+    display: flex;
+    padding-top: 10px;
+    margin-right: 30px;
+    .mk-input {
+      display: flex;
+      flex: 1;
+      label {
+        width: 40%;
+        color: rgba(0, 0, 0, 0.85);
+      }
+      span {
+        width: 40%;
+        flex: none;
+      }
+    }
+  }
+
+  .detail-wrap {
+    position: relative;
+  
+    .mk-th, .mk-tr, .mk-total {
+      position: relative;
+      display: flex;
+      border-bottom: var(--inv-color, #13509c) 1px solid;
+  
+      .mk-td {
+        width: 10%;
+        height: 40px;
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 0 3px;
+        position: relative;
+      }
+      .mk-td:not(:last-child) {
+        border-right: var(--inv-color, #13509c) 1px solid;
+      }
+      .mk-td:first-child {
+        width: 20%;
+      }
+      .mk-td:nth-child(2), .mk-td:nth-child(6) {
+        width: 15%;
+      }
+  
+      .mk-left {
+        justify-content: start;
+      }
+      .mk-right {
+        justify-content: end;
+      }
+      .anticon-ellipsis {
+        padding: 0 10px;
+        position: absolute;
+        right: 0;
+      }
+    }
+    .mk-tr.active, .mk-tr:hover {
+      background: var(--mk-sys-color1);
+    }
+    .mk-upcase {
+      display: flex;
+  
+      .mk-td {
+        width: 40%;
+        height: 40px;
+        display: flex;
+        align-items: center;
+        padding: 0 20px;
+      }
+      .mk-td:first-child {
+        width: 20%;
+        padding: 0;
+        border-right: var(--inv-color, #13509c) 1px solid;
+        justify-content: center;
+      }
+      .mk-td:last-child {
+        justify-content: end;
+      }
+    }
+  }
+}
+.menu-invoice-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-invoice-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
+
+
diff --git a/src/menu/components/module/invoice/options.jsx b/src/menu/components/module/invoice/options.jsx
new file mode 100644
index 0000000..29284b3
--- /dev/null
+++ b/src/menu/components/module/invoice/options.jsx
@@ -0,0 +1,81 @@
+/**
+ * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
+ */
+export default function (wrap) {
+  let menu = window.GLOB.customMenu
+  let books = []
+  let bookids = []
+  menu.components.forEach(item => {
+    if (item.subtype === 'account') {
+      books.push({
+        value: item.uuid,
+        label: item.name
+      })
+      bookids.push(item.uuid)
+    }
+  })
+
+  const wrapForm = [
+    {
+      type: 'radio',
+      field: 'datatype',
+      label: '绫诲瀷',
+      initval: wrap.datatype || 'static',
+      required: true,
+      options: [
+        {value: 'static', label: '鏂板鍙戠エ'},
+        {value: 'dynamic', label: '鏌ョ湅鍗曟嵁'},
+      ]
+    },
+    {
+      type: 'text',
+      field: 'name',
+      label: '缁勪欢鍚嶇О',
+      initval: wrap.name || '',
+      tooltip: '鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�',
+      required: true
+    },
+    {
+      type: 'number',
+      field: 'width',
+      label: '瀹藉害',
+      initval: wrap.width || 24,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      precision: 0,
+      required: true
+    },
+    {
+      type: 'select',
+      field: 'supBook',
+      label: '璐﹀',
+      initval: wrap.supBook || '',
+      required: true,
+      options: books,
+      allowClear: true
+    },
+    {
+      type: 'radio',
+      field: 'business_type',
+      label: '鍙戠エ绫诲瀷',
+      initval: wrap.business_type || 'sell',
+      required: true,
+      options: [
+        {value: 'sell', label: '閿�椤瑰彂绁�'},
+        {value: 'buy', label: '杩涢」鍙戠エ'},
+      ]
+    },
+    {
+      type: 'color',
+      field: 'invColor',
+      label: '鏍峰紡',
+      initval: wrap.invColor || '',
+      tooltip: '鍙戠エ缁勪欢涓竟妗嗕互鍙婃枃瀛楃殑棰滆壊銆�',
+      allowClear: true,
+      required: false
+    },
+  ]
+
+  return wrapForm
+} 
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/verifycard/baseform/index.jsx b/src/menu/components/module/invoice/verifycard/baseform/index.jsx
new file mode 100644
index 0000000..e36d470
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/baseform/index.jsx
@@ -0,0 +1,110 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input } from 'antd'
+// import { QuestionCircleOutlined } from '@ant-design/icons'
+
+// import './index.scss'
+const { TextArea } = Input
+
+class BaseForm extends Component {
+  static propTpyes = {
+    verify: PropTypes.object,
+    onChange: PropTypes.func
+  }
+
+  state = {}
+
+  handleConfirm = () => {
+    const { verify } = this.props
+    
+    if (verify.type === 'billout') {
+      return new Promise((resolve, reject) => {
+        this.props.form.validateFieldsAndScroll((err, values) => {
+          if (!err) {
+            resolve(values)
+          }
+        })
+      })
+    } else {
+      return Promise.resolve()
+    }
+  }
+
+  // onOptionChange = (value, key) => {
+  //   const { verify } = this.props
+
+  //   let _verify = {...verify, [key]: value}
+
+  //   this.props.onChange(_verify)
+  // }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { verify } = this.props
+
+    return (
+      <Form className="base-form">
+        <Row gutter={24}>
+          <Col span={8}>
+            <Form.Item label="鎸夐挳鍚嶇О">
+              <Input value={verify.label} disabled={true}/>
+            </Form.Item>
+          </Col>
+          {/* <Col span={8}>
+            <Form.Item label={
+              <Tooltip placement="bottomLeft" title="">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鎺ュ彛绫诲瀷
+              </Tooltip>
+            }>
+              <Radio.Group value={verify.intertype} disabled={true}>
+                <Radio value="system">绯荤粺</Radio>
+                <Radio value="custom">鑷畾涔�</Radio>
+              </Radio.Group>
+            </Form.Item>
+          </Col> */}
+          {/* {verify.type === 'billout' ? <Col span={8}>
+            <Form.Item label={
+              <Tooltip placement="bottomLeft" title="">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鍙傛暟澶勭悊
+              </Tooltip>
+            }>
+              {getFieldDecorator('procMode', {
+                initialValue: verify.procMode || 'system',
+              })(
+                <Radio.Group onChange={(e) => {this.onOptionChange(e.target.value, 'procMode')}}>
+                  <Radio value="system">绯荤粺鍑芥暟</Radio>
+                  <Radio value="none">鏃�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null} */}
+          {verify.type === 'billout' ? <Col span={24}>
+            <Form.Item label="娴嬭瘯鍦板潃">
+              {getFieldDecorator('interface', {
+                initialValue: verify.interface || '',
+                rules: [
+                  { required: true, message: '璇疯緭鍏ユ祴璇曞湴鍧�!' }
+                ]
+              })(
+                <TextArea rows={2}/>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {verify.type === 'billout' ? <Col span={24}>
+            <Form.Item label="姝e紡鍦板潃">
+              {getFieldDecorator('proInterface', {
+                initialValue: verify.proInterface || '',
+              })(
+                <TextArea rows={2}/>
+              )}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(BaseForm)
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/verifycard/baseform/index.scss b/src/menu/components/module/invoice/verifycard/baseform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/baseform/index.scss
diff --git a/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx b/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx
new file mode 100644
index 0000000..6eb1a0d
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx
@@ -0,0 +1,294 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Button, Modal, Tooltip, Radio, Select, Switch, notification } from 'antd'
+import { QuestionCircleOutlined } from '@ant-design/icons'
+
+import Api from '@/api'
+import { checkSQL } from '@/utils/utils-custom.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+// import './index.scss'
+
+class CustomForm extends Component {
+  static propTpyes = {
+    systemScripts: PropTypes.array,
+    customScripts: PropTypes.array,
+    scriptsChange: PropTypes.func
+  }
+
+  state = {
+    editItem: null,
+    loading: false,
+    skip: false
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    if (this.props.type) {
+      this.props.form.setFieldsValue({
+        sql: record.sql
+      })
+    } else {
+      this.props.form.setFieldsValue({
+        sql: record.sql,
+        position: record.position || 'back'
+      })
+    }
+  }
+
+  handleConfirm = () => {
+    const { type } = this.props
+    const { editItem, skip } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (type === 'fullscreen' && err) {
+        notification.warning({
+          top: 92,
+          message: '璇疯緭鍏ql!',
+          duration: 5
+        })
+        return
+      }
+
+      if (!err) {
+        if (/^[\s\n]+$/.test(values.sql)) {
+          notification.warning({
+            top: 92,
+            message: '璇疯緭鍏ql!',
+            duration: 5
+          })
+          return
+        }
+
+        values.uuid = editItem ? editItem.uuid : ''
+        values.position = values.position || (editItem ? editItem.position : 'front')
+
+        if (type === 'fullscreen' && editItem) {
+          values.status = editItem.status || 'true'
+        }
+
+        let pass = checkSQL(values.sql, 'customscript')
+
+        if (!pass) return
+
+        let sql = `
+          /* 绯荤粺瀛楁 */
+
+          Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
+          
+          Select @UserName='', @FullName='', @RoleID='', @mk_departmentcode='', @mk_organization='', @mk_user_type='', @mk_nation='', @mk_province='', @mk_city='', @mk_district='', @mk_address='', @ErrorCode='', @retmsg='', @account_id='', @account_year_id='', @account_code='', @account_year_code='', @bid=''
+
+        `
+
+        let _prevCustomScript = '' // 榛樿sql鍓嶆墽琛岃剼鏈�
+        let _backCustomScript = '' // 榛樿sql鍚庢墽琛岃剼鏈�
+
+        this.props.customScripts.forEach(item => {
+          if (item.status === 'false') return
+
+          if (item.position === 'front') {
+            _prevCustomScript += `
+            /* 榛樿sql鍓嶈剼鏈� */
+            ${values.uuid === item.uuid ? values.sql : item.sql}
+            `
+          } else {
+            _backCustomScript += `
+            /* 榛樿sql鍚庤剼鏈� */
+            ${values.uuid === item.uuid ? values.sql : item.sql}
+            `
+          }
+        })
+
+        if (!values.uuid) {
+          if (values.position === 'front') {
+            _prevCustomScript += `
+            /* 榛樿sql鍓嶈剼鏈� */
+            ${values.sql}
+            `
+          } else {
+            _backCustomScript += `
+            /* 榛樿sql鍚庤剼鏈� */
+            ${values.sql}
+            `
+          }
+        }
+
+        sql += _prevCustomScript + _backCustomScript
+        sql += `
+          aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg
+        `
+
+        // 鏁版嵁鏉冮檺
+        sql = sql.replace(/@\$|\$@/ig, '')
+        sql = sql.replace(/@datam@/ig, `''`)
+        sql = sql.replace(/@typename@/ig, `'debug'`)
+        
+        if (skip) {
+          this.setState({
+            skip: false,
+            editItem: null
+          }, () => {
+            this.props.scriptsChange(values)
+          })
+          this.props.form.setFieldsValue({
+            sql: ' '
+          })
+        } else {
+          this.setState({loading: true})
+          Api.sDebug(sql).then(res => {
+            if (res.status || res.ErrCode === '-2') {
+              this.setState({
+                loading: false,
+                editItem: null
+              }, () => {
+                this.props.scriptsChange(values)
+              })
+              this.props.form.setFieldsValue({
+                sql: ' '
+              })
+            } else {
+              this.setState({loading: false})
+  
+              Modal.error({
+                title: res.message
+              })
+            }
+          })
+        }
+      }
+    })
+  }
+
+  handleCancel = () => {
+    this.setState({
+      editItem: null
+    })
+
+    this.props.form.setFieldsValue({
+      sql: ' '
+    })
+  }
+
+  selectScript = (value, option) => {
+    if (!value || !option) return
+    let _sql = this.props.form.getFieldValue('sql')
+    if (/^\s+$/.test(_sql)) {
+      _sql = ''
+    }
+    if (_sql) {
+      _sql = _sql + ` 
+
+      `
+    }
+
+    _sql = _sql.replace(/\s{6}$/, '')
+    _sql = _sql + `/*${option.props.children}*/
+    `
+    _sql = _sql.replace(/\s{4}$/, '')
+    _sql = _sql + value
+
+    this.props.form.setFieldsValue({
+      sql: _sql
+    })
+  }
+
+  render() {
+    const { systemScripts, type } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { editItem, skip } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          {!type ? <Col span={8}>
+            <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0, whiteSpace: 'nowrap'}}>
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+            </Form.Item>
+          </Col> : null}
+          {!type ? <Col span={24} className="sqlfield">
+            <Form.Item label="鍙敤瀛楁">
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鍏叡鍊硷紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
+            </Form.Item>
+          </Col> : null}
+          {!type ? <Col span={8} style={{whiteSpace: 'nowrap'}}>
+            <Form.Item style={{marginBottom: 0}} label={
+              <Tooltip placement="bottomLeft" title={'鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�'}>
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鎵ц浣嶇疆
+              </Tooltip>
+            }>
+              {getFieldDecorator('position', {
+                initialValue: 'front'
+              })(
+                <Radio.Group>
+                  <Radio value="front">sql鍓�</Radio>
+                  <Radio value="back">sql鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {!type ? <Col span={8}>
+            <Form.Item label="蹇嵎娣诲姞" style={{marginBottom: 0}}>
+              <Select
+                showSearch
+                dropdownMatchSelectWidth={false}
+                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                onChange={this.selectScript}
+              >
+                <Select.Option key="default" value="defaultSql">榛樿sql</Select.Option>
+                {systemScripts.map((option, i) =>
+                  <Select.Option key={i} value={option.value}>{option.name}</Select.Option>
+                )}
+              </Select>
+            </Form.Item>
+          </Col> : null}
+          <Col span={5} className="add" style={{whiteSpace: 'nowrap'}}>
+            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}>
+              {type === 'fullscreen' && !editItem ? '娣诲姞' : '淇濆瓨'}
+            </Button>
+            <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}>
+              鍙栨秷
+            </Button>
+          </Col>
+          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
+            寮哄埗淇濆瓨锛�
+            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
+          </Col>
+          <Col span={24} className="sql">
+            <Form.Item label={
+              <Tooltip placement="bottomLeft" title="鏁版嵁鏉冮檺鏇挎崲绗� $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\'">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                sql
+              </Tooltip>
+            }>
+              {getFieldDecorator('sql', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: '璇疯緭鍏ql!'
+                  }
+                ]
+              })(<CodeMirror />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.scss b/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/callbackcustomscript/index.scss
diff --git a/src/menu/components/module/invoice/verifycard/customscript/index.jsx b/src/menu/components/module/invoice/verifycard/customscript/index.jsx
new file mode 100644
index 0000000..fee69b5
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/customscript/index.jsx
@@ -0,0 +1,284 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Button, notification, Modal, Tooltip, Select, Switch } from 'antd'
+import { QuestionCircleOutlined } from '@ant-design/icons'
+
+import Api from '@/api'
+import { checkSQL } from '@/utils/utils-custom.js'
+import CodeMirror from '@/templates/zshare/codemirror'
+// import './index.scss'
+
+class CustomForm extends Component {
+  static propTpyes = {
+    type: PropTypes.any,
+    systemScripts: PropTypes.array,
+    customScripts: PropTypes.array,
+    scriptsChange: PropTypes.func
+  }
+
+  state = {
+    editItem: null,
+    loading: false,
+    skip: false
+  }
+
+  edit = (record) => {
+    this.setState({
+      editItem: record
+    })
+
+    this.props.form.setFieldsValue({
+      sql: record.sql
+    })
+  }
+
+  handleConfirm = () => {
+    const { type } = this.props
+    const { editItem, skip } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    this.props.form.validateFieldsAndScroll((err, values) => {
+      if (type === 'fullscreen' && err) {
+        notification.warning({
+          top: 92,
+          message: '璇疯緭鍏ql!',
+          duration: 5
+        })
+        return
+      }
+      if (!err) {
+        if (/^[\s\n]+$/.test(values.sql)) {
+          notification.warning({
+            top: 92,
+            message: '璇疯緭鍏ql!',
+            duration: 5
+          })
+          return
+        }
+        values.uuid = editItem ? editItem.uuid : ''
+
+        if (type === 'fullscreen' && editItem) {
+          values.status = editItem.status || 'true'
+        }
+
+        let pass = checkSQL(values.sql, 'customscript')
+
+        if (!pass) return
+
+        let sql = `
+          /* 绯荤粺瀛楁 */
+
+          Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
+          
+          Select @UserName='', @FullName='', @RoleID='', @mk_departmentcode='', @mk_organization='', @mk_user_type='', @mk_nation='', @mk_province='', @mk_city='', @mk_district='', @mk_address='', @ErrorCode='', @retmsg='', @account_id='', @account_year_id='', @account_code='', @account_year_code='', @bid=''
+          
+          /* 鍙戠エ涓昏〃瀛楁 */
+          
+          Declare @invoice_type Nvarchar(50), @from_to_name Nvarchar(50), @from_to_tax_no Nvarchar(50), @from_to_addr Nvarchar(100), @from_to_tel Nvarchar(50), @from_to_bank_name Nvarchar(50), @from_to_account_no Nvarchar(50), @from_to_mob Nvarchar(50), @from_to_email Nvarchar(50), @from_to_code Nvarchar(50), @orgname Nvarchar(50), @tax_no Nvarchar(50), @addr Nvarchar(100), @tel Nvarchar(50), @bank_name Nvarchar(50), @account_no Nvarchar(50), @remark Nvarchar(512), @payee Nvarchar(50), @reviewer Nvarchar(50), @drawer Nvarchar(50), @io Nvarchar(50), @orgcode Nvarchar(50), @total_net_amount Decimal(18,2), @total_tax Decimal(18,2), @total_amount Decimal(18,2)
+          
+          Select @invoice_type='', @from_to_name='', @from_to_tax_no='', @from_to_addr='', @from_to_tel='', @from_to_bank_name='', @from_to_account_no='', @from_to_mob='', @from_to_email='', @from_to_code='', @orgname='', @tax_no='', @addr='', @tel='', @bank_name='', @account_no='', @remark='', @payee='', @reviewer='', @drawer='', @io='', @orgcode='', @total_net_amount=0, @total_tax=0, @total_amount=0
+          
+          /* 鍙戠エ鏄庣粏涓存椂琛� */
+          Declare @details_list table (productcode Nvarchar(50), productname Nvarchar(50), spec Nvarchar(50), unit Nvarchar(50), bill_count Decimal(18,10), unitprice Decimal(18,10), amount_line Decimal(18,2), tax_classify_code Nvarchar(50), tax_classify_name Nvarchar(50), tax_rate Decimal(18,2), tax_amount Decimal(18,2), free_tax_mark Nvarchar(50), vat_special_management Nvarchar(50), invoice_lp Nvarchar(50), jskey Nvarchar(50), data_type Nvarchar(50))
+          
+          Insert into @details_list (productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount, free_tax_mark, vat_special_management, invoice_lp, jskey, data_type)
+          
+          Select '', '', '', '', 0, 0, 0, '', '', 0, 0, '', '', '', '', ''
+
+        `
+
+        this.props.customScripts.forEach(item => {
+          let _item = values.uuid === item.uuid ? values : item
+
+          if (_item.status === 'false') return
+
+          sql += `
+          ${_item.sql}
+          `
+        })
+
+        if (!values.uuid) {
+          sql += `
+          ${values.sql}
+          `
+        }
+
+        sql += `
+          aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg
+        `
+
+        // 鏁版嵁鏉冮檺
+        sql = sql.replace(/@\$|\$@/ig, '')
+        sql = sql.replace(/@datam@/ig, `''`)
+        sql = sql.replace(/@typename@/ig, `'debug'`)
+        
+        if (skip) {
+          this.setState({
+            skip: false,
+            editItem: null
+          }, () => {
+            this.props.scriptsChange(values)
+          })
+          this.props.form.setFieldsValue({
+            sql: ' '
+          })
+        } else {
+          this.setState({loading: true})
+          Api.sDebug(sql).then(res => {
+            if (res.status || res.ErrCode === '-2') {
+              this.setState({
+                loading: false,
+                editItem: null
+              }, () => {
+                this.props.scriptsChange(values)
+              })
+              this.props.form.setFieldsValue({
+                sql: ' '
+              })
+            } else {
+              this.setState({loading: false})
+  
+              Modal.error({
+                title: res.message
+              })
+            }
+          })
+        }
+      }
+    })
+  }
+
+  handleCancel = () => {
+    this.setState({
+      editItem: null
+    })
+
+    this.props.form.setFieldsValue({
+      sql: ' '
+    })
+  }
+
+  selectScript = (value, option) => {
+    if (!value || !option) return
+
+    let _sql = this.props.form.getFieldValue('sql')
+    if (/^\s+$/.test(_sql)) {
+      _sql = ''
+    }
+    if (_sql) {
+      _sql = _sql + ` 
+
+      `
+    }
+
+    _sql = _sql.replace(/\s{6}$/, '')
+    _sql = _sql + `/*${option.props.children}*/
+    `
+    _sql = _sql.replace(/\s{4}$/, '')
+    _sql = _sql + value
+
+    this.props.form.setFieldsValue({
+      sql: _sql
+    })
+  }
+
+  render() {
+    const { systemScripts, type } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { editItem, skip } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="verify-form">
+        <Row gutter={24}>
+          {!type ? <Col span={8}>
+            <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0, whiteSpace: 'nowrap'}}>
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+            </Form.Item>
+          </Col> : null}
+          {!type ? <Col span={24} className="sqlfield">
+            <Form.Item label={'鍙敤瀛楁'}>
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="鍏叡鍊硷紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�"><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��"><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="璐﹀瀛楁锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��"><span style={{color: '#13c2c2'}}>account_id, account_year_id, account_code, account_year_code </span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="涓昏〃瀛楁锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��"><span style={{color: '#8E44AD'}}>invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, from_to_code, orgname, tax_no, addr, tel, bank_name, account_no, remark, payee, reviewer, drawer</span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="瀛愯〃瀛楁锛堝晢鍝佹槑缁嗭級锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��">productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount</Tooltip>
+            </Form.Item>
+          </Col> : null}
+          {/* {!_type ? <Col span={8} style={{whiteSpace: 'nowrap'}}>
+            <Form.Item style={{marginBottom: 0}} label={
+              <Tooltip placement="bottomLeft" title="鑷畾涔夎剼鏈笌榛樿sql浣嶇疆鍏崇郴銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鎵ц浣嶇疆
+              </Tooltip>
+            }>
+              {getFieldDecorator('position', {
+                initialValue: 'front'
+              })(
+                <Radio.Group>
+                  <Radio value="init">鍒濆鍖�</Radio>
+                  <Radio value="front">sql鍓�</Radio>
+                  <Radio value="back">sql鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null} */}
+          {!type ? <Col span={8}>
+            <Form.Item label={'蹇嵎娣诲姞'} style={{marginBottom: 0}}>
+              <Select
+                showSearch
+                dropdownMatchSelectWidth={false}
+                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                onSelect={this.selectScript}
+              >
+                {systemScripts.map((option, i) =>
+                  <Select.Option key={i} value={option.value}>{option.name}</Select.Option>
+                )}
+              </Select>
+            </Form.Item>
+          </Col> : null}
+          <Col span={5} className="add" style={{whiteSpace: 'nowrap'}}>
+            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 30}}>
+              {type === 'fullscreen' && !editItem ? '娣诲姞' : '淇濆瓨'}
+            </Button>
+            <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}>
+              鍙栨秷
+            </Button>
+          </Col>
+          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
+            寮哄埗淇濆瓨锛�
+            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
+          </Col>
+          <Col span={24} className="sql">
+            <Form.Item label={
+              <Tooltip placement="bottomLeft" title="鏁版嵁鏉冮檺鏇挎崲绗� $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\'">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                sql
+              </Tooltip>
+            }>
+              {getFieldDecorator('sql', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: '璇疯緭鍏ql!'
+                  }
+                ]
+              })(<CodeMirror />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(CustomForm)
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/verifycard/customscript/index.scss b/src/menu/components/module/invoice/verifycard/customscript/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/customscript/index.scss
diff --git a/src/menu/components/module/invoice/verifycard/index.jsx b/src/menu/components/module/invoice/verifycard/index.jsx
new file mode 100644
index 0000000..0f51541
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/index.jsx
@@ -0,0 +1,690 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Form, Tabs, Row, Col, Button, Popconfirm, notification, Modal, message, Typography, InputNumber } from 'antd'
+import { CheckCircleOutlined, StopOutlined, EditOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import BaseForm from './baseform'
+import CustomScript from './customscript'
+import CallBackCustomScript from './callbackcustomscript'
+import asyncComponent from '@/utils/asyncComponent'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { TabPane } = Tabs
+const { confirm } = Modal
+const { Paragraph } = Typography
+const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
+const FullScripts = asyncComponent(() => import('@/templates/zshare/verifycard/fullScripts'))
+
+class VerifyCard extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    card: PropTypes.object,
+    columns: PropTypes.array
+  }
+
+  state = {
+    activeKey: 'base',
+    verify: {},
+    systemScripts: [],
+    scriptsColumns: [
+      {
+        title: 'SQL',
+        dataIndex: 'sql',
+        width: '70%',
+        render: (text) => {
+          let title = text.match(/^\s*\/\*.+\*\//)
+          title = title && title[0] ? title[0] : ''
+          let _text = title ? text.replace(title, '') : text
+
+          return (
+            <div>
+              {title ? <span style={{color: '#a50'}}>{title}<span style={{fontSize: '12px', marginLeft: '5px'}}>{_text.length}</span></span> : null}
+              <Paragraph copyable={{ text: text }} ellipsis={{ rows: 4, expandable: true }}>{_text}</Paragraph>
+            </div>
+          )
+        }
+      },
+      // {
+      //   title: '鎵ц浣嶇疆',
+      //   dataIndex: 'position',
+      //   width: '10%',
+      //   render: (text, record) => {
+      //     if (record.position === 'init') {
+      //       return <span style={{color: 'orange'}}>鍒濆鍖�</span>
+      //     } else if (record.position === 'front') {
+      //       return <span style={{color: '#26C281'}}>sql鍓�</span>
+      //     } else {
+      //       return <span style={{color: '#1890ff'}}>sql鍚�</span>
+      //     }
+      //   }
+      // },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '10%',
+        render: (text, record) => record.status === 'false' ?
+          (
+            <div style={{color: '#ff4d4f'}}>
+              绂佺敤
+              <StopOutlined style={{marginLeft: '5px'}} />
+            </div>
+          ) :
+          (
+            <div style={{color: '#26C281'}}>
+              鍚敤
+              <CheckCircleOutlined style={{marginLeft: '5px'}}/>
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '140px',
+        dataIndex: 'operation',
+        render: (_, record) =>
+          (<div style={{textAlign: 'center'}}>
+            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
+            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
+            <Popconfirm
+              overlayClassName="popover-confirm"
+              title="纭畾鍒犻櫎鍚�?"
+              onConfirm={() => this.handleDelete(record, 'scripts')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ],
+    cbScriptsColumns: [
+      {
+        title: 'SQL',
+        dataIndex: 'sql',
+        width: '60%',
+        render: (text) => {
+          let title = text.match(/^\s*\/\*.+\*\//)
+          title = title && title[0] ? title[0] : ''
+          let _text = title ? text.replace(title, '') : text
+
+          return (
+            <div>
+              {title ? <span style={{color: '#a50'}}>{title}<span style={{fontSize: '12px', marginLeft: '5px'}}>{_text.length}</span></span> : null}
+              <Paragraph copyable={{ text: text }} ellipsis={{ rows: 4, expandable: true }}>{_text}</Paragraph>
+            </div>
+          )
+        }
+      },
+      {
+        title: '鎵ц浣嶇疆',
+        dataIndex: 'position',
+        width: '10%',
+        render: (_, record) => {
+          if (record.position === 'front') {
+            return <span style={{color: '#26C281'}}>sql鍓�</span>
+          } else {
+            return <span style={{color: '#1890ff'}}>sql鍚�</span>
+          }
+        }
+      },
+      {
+        title: '鐘舵��',
+        dataIndex: 'status',
+        width: '10%',
+        render: (_, record) => record.status === 'false' ?
+          (
+            <div style={{color: '#ff4d4f'}}>
+              绂佺敤
+              <StopOutlined style={{marginLeft: '5px'}} />
+            </div>
+          ) :
+          (
+            <div style={{color: '#26C281'}}>
+              鍚敤
+              <CheckCircleOutlined style={{marginLeft: '5px'}}/>
+            </div>
+          )
+      },
+      {
+        title: '鎿嶄綔',
+        align: 'center',
+        width: '20%',
+        dataIndex: 'operation',
+        render: (text, record) =>
+          (<div style={{textAlign: 'center'}}>
+            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record, 'cbscripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
+            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record, 'cbscripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
+            <Popconfirm
+              overlayClassName="popover-confirm"
+              title="纭畾鍒犻櫎鍚�?"
+              onConfirm={() => this.handleDelete(record, 'cbscripts')
+            }>
+              <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
+            </Popconfirm>
+          </div>)
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount() {
+    const { card } = this.props
+    let _verify = fromJS(card).toJS()
+
+    // _verify.intertype = _verify.intertype || 'system'
+    _verify.scripts = _verify.scripts || []
+    _verify.cbScripts = _verify.cbScripts || []
+
+    _verify.scripts.forEach((item, i) => {
+      item.$index = i + 1
+    })
+    _verify.cbScripts.forEach((item, i) => {
+      item.$index = i + 1
+    })
+
+    this.setState({
+      activeKey: 'base',
+      verify: _verify,
+      oriVerify: fromJS(_verify).toJS()
+    })
+  }
+
+  componentDidMount() {
+    let mutilForms = [
+      {
+        obj_name: 'scripts',
+        arr_field: 'funcname,longparam',
+        LText: window.btoa(window.encodeURIComponent(`Select distinct func+Remark as funcname,longparam, s.Sort from s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`))
+      }
+    ]
+
+    mutilForms = mutilForms.map(item => `select '${item.obj_name}' as obj_name,'${item.arr_field}' as arr_field,'${item.LText}' as LText`)
+
+    let mutilparam = {
+      func: 'sPC_Get_SelectedList',
+      LText: mutilForms.join(' union all '),
+      obj_name: '',
+      arr_field: '',
+      table_type: 'Y',
+      exec_type: 'x'
+    }
+
+    mutilparam.LText = Utils.formatOptions(mutilparam.LText, 'x')
+    mutilparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    mutilparam.secretkey = Utils.encrypt('', mutilparam.timestamp)
+    mutilparam.open_key = Utils.encryptOpenKey(mutilparam.secretkey, mutilparam.timestamp)
+
+    if (window.GLOB.cloudServiceApi) { // 浜戠璇锋眰
+      mutilparam.rduri = window.GLOB.cloudServiceApi
+      mutilparam.userid = sessionStorage.getItem('CloudUserID') || ''
+      mutilparam.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
+    }
+
+    Api.getSystemCacheConfig(mutilparam).then(res => {
+      if (res.status) {
+        this.setState({
+          systemScripts: res.scripts.map(item => {
+            return {
+              name: item.funcname,
+              value: window.decodeURIComponent(window.atob(item.longparam))
+            }
+          })
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  scriptsChange = (values) => {
+    let verify = fromJS(this.state.verify).toJS()
+
+    if (values.uuid) {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.scripts.push(values)
+    }
+
+    MKEmitter.emit('editLineId', values.uuid)
+
+    this.setState({ verify })
+  }
+
+  cbScriptsChange = (values) => {
+    let verify = fromJS(this.state.verify).toJS()
+
+    if (values.uuid) {
+      verify.cbScripts = verify.cbScripts.map(item => {
+        if (item.uuid === values.uuid) {
+          return values
+        } else {
+          return item
+        }
+      })
+    } else {
+      values.uuid = Utils.getuuid()
+      verify.cbScripts.push(values)
+    }
+
+    MKEmitter.emit('editLineId', values.uuid)
+
+    this.setState({ verify })
+  }
+
+  handleDelete = (record, type) => {
+    const { verify } = this.state
+
+    if (type === 'scripts') {
+      verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
+    } else if (type === 'cbscripts') {
+      verify.cbScripts = verify.cbScripts.filter(item => item.uuid !== record.uuid)
+    }
+
+    this.setState({ verify })
+  }
+
+  handleEdit = (record, type) => {
+    let node = null
+
+    if (type === 'scripts') {
+      this.scriptsForm.edit(record)
+      node = document.getElementById('mk-normal-script')
+    } else if (type === 'cbscripts') {
+      this.cbscriptsForm.edit(record)
+      node = document.getElementById('mk-callback-script')
+    }
+
+    if (node && node.scrollTop) {
+      let inter = Math.ceil(node.scrollTop / 10)
+
+      let timer = setInterval(() => {
+        if (node.scrollTop - inter > 0) {
+          node.scrollTop = node.scrollTop - inter
+        } else {
+          node.scrollTop = 0
+          clearInterval(timer)
+        }
+      }, 10)
+    }
+  }
+
+  handleStatus = (record, type) => {
+    let verify = fromJS(this.state.verify).toJS()
+    record.status = record.status === 'false' ? 'true' : 'false'
+
+    if (type === 'scripts') {
+      verify.scripts = verify.scripts.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    } else if (type === 'cbscripts') {
+      verify.cbScripts = verify.cbScripts.map(item => {
+        if (item.uuid === record.uuid) {
+          return record
+        } else {
+          return item
+        }
+      })
+    }
+
+    this.setState({ verify })
+  }
+
+  showError = (errorType) => {
+    const { verify } = this.state
+
+    if (errorType === 'S') {
+      let time = verify.stime || 2
+      notification.success({
+        top: 92,
+        message: '鎵ц鎴愬姛锛�',
+        duration: time
+      })
+    } else if (errorType === 'Y') {
+      Modal.success({
+        title: '鎵ц鎴愬姛锛�'
+      })
+    } else if (errorType === 'F') {
+      notification.error({
+        className: 'notification-custom-error',
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: verify.ftime || 10
+      })
+    } else if (errorType === 'N') {
+      notification.error({
+        top: 92,
+        message: '鎵ц澶辫触锛�',
+        duration: verify.ntime || 10
+      })
+    } else if (errorType === 'E') {
+      Modal.error({
+        title: '鎵ц澶辫触锛�'
+      })
+    } else if (errorType === 'NM') {
+      message.error('鎵ц澶辫触锛�')
+    }
+  }
+
+  timeChange = (val, type) => {
+    const { verify } = this.state
+
+    this.setState({
+      verify: {...verify, [type]: val}
+    })
+  }
+
+  handleConfirm = () => {
+    const { activeKey } = this.state
+    let verify = fromJS(this.state.verify).toJS()
+
+    let msg = ''
+    if (this.scriptsForm && this.scriptsForm.state.editItem) {
+      msg = '鍓嶇疆鑴氭湰'
+    } else if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
+      msg = '鍓嶇疆鑴氭湰'
+    } else if (this.cbscriptsForm && this.cbscriptsForm.state.editItem) {
+      msg = '鍥炶皟鑴氭湰'
+    } else if (this.cbscriptsForm && this.cbscriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.cbscriptsForm.props.form.getFieldValue('sql'))) {
+      msg = '鍥炶皟鑴氭湰'
+    }
+
+    return new Promise((resolve, reject) => {
+      if (activeKey === 'base' && verify.type === 'billout') {
+        this.baseForm.handleConfirm().then(res => {
+          let _verify = {...verify, ...res}
+          
+          if (msg) {
+            confirm({
+              content: msg + '鏈繚瀛橈紝纭畾鎻愪氦鍚楋紵',
+              onOk() {
+                resolve(_verify)
+              },
+              onCancel() {}
+            })
+          } else {
+            resolve(_verify)
+          }
+        })
+      } else {
+        if (msg) {
+          confirm({
+            content: msg + '鏈繚瀛橈紝纭畾鎻愪氦鍚楋紵',
+            onOk() {
+              resolve(verify)
+            },
+            onCancel() {}
+          })
+        } else {
+          resolve(verify)
+        }
+      }
+    })
+  }
+
+  handleCancel = () => {
+    const { verify, oriVerify } = this.state
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      if (!is(fromJS(verify), fromJS(oriVerify))) {
+        confirm({
+          content: '鎸夐挳淇℃伅宸蹭慨鏀癸紝纭畾鍙栨秷鍚楋紵',
+          onOk() {
+            resolve()
+          },
+          onCancel() {}
+        })
+      } else {
+        resolve()
+      }
+    })
+  }
+
+  changeTab = (val) => {
+    const { activeKey, verify } = this.state
+
+    if (activeKey === 'base') {
+      this.baseForm.handleConfirm().then(res => {
+        this.setState({
+          verify: {...verify, ...res},
+          activeKey: val
+        })
+      })
+    } else {
+      this.setState({
+        activeKey: val
+      })
+    }
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { card, columns } = this.props
+    const { activeKey, verify, scriptsColumns, cbScriptsColumns } = this.state
+    
+    return (
+      <div>
+        <div className="mk-com-name">{card.label}</div>
+        <Tabs activeKey={activeKey} className="mk-invoice-tabs" onChange={this.changeTab}>
+          <TabPane tab="鍩虹璁剧疆" key="base">
+            <BaseForm columns={columns} verify={verify} onChange={(verify) => this.setState({verify})} wrappedComponentRef={(inst) => this.baseForm = inst}/>
+          </TabPane>
+          <TabPane tab={
+            <span>
+              鍓嶇疆鑴氭湰
+              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
+            </span>
+          } key="scripts" id="mk-normal-script">
+            <FullScripts
+              scripts={verify.scripts}
+              getScriptsFullForm={() => this.scriptsFullForm}
+              getScriptsForm={() => this.scriptsForm}
+              handleStatus={this.handleStatus}
+              handleDelete={this.handleDelete}
+            >
+              <CustomScript
+                type="fullscreen"
+                customScripts={verify.scripts}
+                systemScripts={this.state.systemScripts}
+                scriptsChange={this.scriptsChange}
+                wrappedComponentRef={(inst) => this.scriptsFullForm = inst}
+              />
+            </FullScripts>
+            <CustomScript
+              customScripts={verify.scripts}
+              systemScripts={this.state.systemScripts}
+              scriptsChange={this.scriptsChange}
+              wrappedComponentRef={(inst) => this.scriptsForm = inst}
+            />
+            <EditTable actions={['move']} data={verify.scripts} columns={scriptsColumns} onChange={(scripts) => {this.setState({verify: {...verify, scripts}})}}/>
+          </TabPane>
+          {card.type === 'billout' ? <TabPane tab={
+            <span>
+              鍥炶皟鑴氭湰
+              {verify.cbScripts.length ? <span className="count-tip">{verify.cbScripts.length}</span> : null}
+            </span>
+          } key="cbScripts" id="mk-callback-script">
+            <FullScripts
+              scripts={verify.cbScripts}
+              getScriptsFullForm={() => this.cbscriptsFullForm}
+              getScriptsForm={() => this.cbscriptsForm}
+              handleStatus={(item) => this.handleStatus(item, 'cbscripts')}
+              handleDelete={(item) => this.handleDelete(item, 'cbscripts')}
+            >
+              <CallBackCustomScript
+                type="fullscreen"
+                customScripts={verify.cbScripts}
+                systemScripts={this.state.systemScripts}
+                scriptsChange={this.cbScriptsChange}
+                wrappedComponentRef={(inst) => this.cbscriptsFullForm = inst}
+              />
+            </FullScripts>
+            <CallBackCustomScript
+              customScripts={verify.cbScripts}
+              systemScripts={this.state.systemScripts}
+              scriptsChange={this.cbScriptsChange}
+              wrappedComponentRef={(inst) => this.cbscriptsForm = inst}
+            />
+            <EditTable actions={['move']} data={verify.cbScripts} columns={cbScriptsColumns} onChange={(cbScripts) => {this.setState({verify: {...verify, cbScripts}})}}/>
+          </TabPane> : null}
+          <TabPane tab="sql绀轰緥" key="sql">
+            <div className="mk-sql-wrap">
+              <p className="note">{`/* 绯荤粺瀛楁 */`}</p>
+              <p>
+                Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
+              </p>
+              <p>
+                Select @UserName='', @FullName='', @RoleID='', @mk_departmentcode='', @mk_organization='', @mk_user_type='', @mk_nation='', @mk_province='', @mk_city='', @mk_district='', @mk_address='', @ErrorCode='', @retmsg='', @account_id='', @account_year_id='', @account_code='', @account_year_code='', @bid=''
+              </p>
+              <p className="note">{`/* 鍙戠エ涓昏〃瀛楁 */`}</p>
+              <p>
+                Declare @invoice_type Nvarchar(50), @from_to_name Nvarchar(50), @from_to_tax_no Nvarchar(50), @from_to_addr Nvarchar(100), @from_to_tel Nvarchar(50), @from_to_bank_name Nvarchar(50), @from_to_account_no Nvarchar(50), @from_to_mob Nvarchar(50), @from_to_email Nvarchar(50), @from_to_code Nvarchar(50), @orgname Nvarchar(50), @tax_no Nvarchar(50), @addr Nvarchar(100), @tel Nvarchar(50), @bank_name Nvarchar(50), @account_no Nvarchar(50), @remark Nvarchar(512), @payee Nvarchar(50), @reviewer Nvarchar(50), @drawer Nvarchar(50), @io Nvarchar(50), @orgcode Nvarchar(50), @total_net_amount Decimal(18,2), @total_tax Decimal(18,2), @total_amount Decimal(18,2)
+              </p>
+              <p>
+                Select @invoice_type='', @from_to_name='', @from_to_tax_no='', @from_to_addr='', @from_to_tel='', @from_to_bank_name='', @from_to_account_no='', @from_to_mob='', @from_to_email='', @from_to_code='', @orgname='', @tax_no='', @addr='', @tel='', @bank_name='', @account_no='', @remark='', @payee='', @reviewer='', @drawer='', @io='', @orgcode='', @total_net_amount=0, @total_tax=0, @total_amount=0
+              </p>
+              <p className="note">{`/* 鍙戠エ鏄庣粏涓存椂琛� */`}</p>
+              <p>
+                Declare @details_list table (productcode Nvarchar(50), productname Nvarchar(50), spec Nvarchar(50), unit Nvarchar(50), bill_count Decimal(18,10), unitprice Decimal(18,10), amount_line Decimal(18,2), tax_classify_code Nvarchar(50), tax_classify_name Nvarchar(50), tax_rate Decimal(18,2), tax_amount Decimal(18,2), free_tax_mark Nvarchar(50), vat_special_management Nvarchar(50), invoice_lp Nvarchar(50), jskey Nvarchar(50), data_type Nvarchar(50))
+              </p>
+              <p>
+                Insert into @details_list (productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount, free_tax_mark, vat_special_management, invoice_lp, jskey, data_type)
+              </p>
+              <p>
+                Select '', '', '', '', 0, 0, 0, '', '', 0, 0, '', '', '', '', ''
+              </p>
+              <p className="note">{`/* 鍓嶇疆鑴氭湰 */`}</p>
+              <p>
+                ......
+              </p>
+              <p>
+                aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg
+              </p>
+            </div>
+          </TabPane>
+          <TabPane tab="淇℃伅鎻愮ず" key="tip">
+            <Form className="tip-form">
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> S </span>
+                    <Button onClick={() => {this.showError('S')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label="鍋滅暀鏃堕棿">
+                    <InputNumber defaultValue={verify.stime || 2} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'stime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> Y </span>
+                    <Button onClick={() => {this.showError('Y')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> -1 </span>
+                    鎵ц鎴愬姛鏃犳彁绀恒��
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> N </span>
+                    <Button onClick={() => {this.showError('N')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label="鍋滅暀鏃堕棿">
+                    <InputNumber defaultValue={verify.ntime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ntime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> F </span>
+                    <Button onClick={() => {this.showError('F')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+                <Col span={8}>
+                  <Form.Item label="鍋滅暀鏃堕棿">
+                    <InputNumber defaultValue={verify.ftime || 10} min={1} max={10000} precision={0} onChange={(val) => {this.timeChange(val, 'ftime')}} />
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> E </span>
+                    <Button onClick={() => {this.showError('E')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> NM </span>
+                    <Button onClick={() => {this.showError('NM')}} type="primary" size="small">
+                      鏌ョ湅
+                    </Button>
+                  </Form.Item>
+                </Col>
+              </Row>
+              <Row gutter={24}>
+                <Col offset={6} span={6}>
+                  <Form.Item label="鎻愮ず缂栫爜">
+                    <span className="errorval"> -2 </span>
+                    鎵ц澶辫触鏃犳彁绀�
+                  </Form.Item>
+                </Col>
+              </Row>
+            </Form>
+          </TabPane>
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(VerifyCard)
\ No newline at end of file
diff --git a/src/menu/components/module/invoice/verifycard/index.scss b/src/menu/components/module/invoice/verifycard/index.scss
new file mode 100644
index 0000000..c05f0e1
--- /dev/null
+++ b/src/menu/components/module/invoice/verifycard/index.scss
@@ -0,0 +1,124 @@
+.mk-invoice-tabs {
+  .ant-tabs-nav .ant-tabs-tab {
+    margin-right: 25px;
+  }
+  .ant-tabs-nav-scroll {
+    text-align: center;
+  }
+  .ant-tabs-content {
+    min-height: 40vh;
+  }
+  table tr td {
+    word-wrap: break-word;
+    word-break: break-word;
+  }
+  .count-tip {
+    position: absolute;
+    top: 0px;
+    color: #1890ff;
+    font-size: 12px;
+  }
+  .ant-input-disabled {
+    color: rgba(0, 0, 0, 0.85);
+    background-color: #ffffff;
+    cursor: text;
+  }
+  .ant-radio-disabled + span {
+    color: rgba(0, 0, 0, 0.85);
+  }
+  .base-form {
+    padding-right: 50px;
+    .ant-form-item {
+      display: flex;
+      .ant-form-item-control-wrapper {
+        flex: 1;
+      }
+    }
+    .ant-col-8 {
+      .ant-form-item-label {
+        width: 33.33%;
+      }
+    }
+    .ant-col-24 {
+      .ant-form-item-label {
+        width: 10.8%;
+      }
+    }
+  }
+  .tip-form {
+    .ant-form-item {
+      display: flex;
+    }
+  }
+  .mk-sql-wrap {
+    color: rgba(0, 0, 0, 0.85);
+    .note {
+      margin-bottom: 0px;
+    }
+  }
+  .verify-form {
+    .sql {
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+        padding-top: 4px;
+      }
+      .CodeMirror {
+        height: 350px;
+      }
+    }
+    .sqlfield {
+      .ant-form-item {
+        margin-bottom: 5px;
+      }
+      .ant-form-item-control {
+        line-height: 24px;
+      }
+      .ant-form-item-label {
+        line-height: 25px;
+      }
+      .ant-form-item-children {
+        line-height: 22px;
+      }
+      .ant-col-sm-8 {
+        width: 10.5%;
+      }
+      .ant-col-sm-16 {
+        width: 89.5%;
+      }
+    }
+    .add {
+      padding-top: 4px;
+
+      .mk-green {
+        margin-bottom: 15px;
+      }
+    }
+  }
+  .custom-table .ant-empty {
+    margin: 20px 8px!important;
+  }
+  .errorval {
+    display: inline-block;
+    width: 30px;
+  }
+  .operation-btn {
+    display: inline-block;
+    font-size: 16px;
+    padding: 0 5px;
+    cursor: pointer;
+  }
+  .operation-btn:not(:first-child) {
+    margin-left: 5px;
+  }
+  .full-scripts {
+    position: absolute;
+    right: 24px;
+    top: 0px;
+    font-size: 16px;
+    color: #1890ff;
+    z-index: 1;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/module/voucher/index.jsx b/src/menu/components/module/voucher/index.jsx
index 905ef23..4d26cc9 100644
--- a/src/menu/components/module/voucher/index.jsx
+++ b/src/menu/components/module/voucher/index.jsx
@@ -122,16 +122,17 @@
           <ToolOutlined />
         </Popover>
         <div className="voucher-box">
-          {card.wrap.type === 'createVoucher' ? <div className="voucher-header">
-            <Button className="add-background header-btn">淇濆瓨骞舵柊澧�</Button>
-            <Button className="add-background header-btn">淇濆瓨</Button>
-            <Button className="print-background header-btn">鎵撳嵃</Button>
-            <Button className="out-background header-btn">鏇村</Button>
+          {card.wrap.type === 'createVoucher' ? <div className="voucher-header" style={{padding: `10px ${card.wrap.space || 0}px`}}>
+            <Button>淇濆瓨骞舵柊澧�</Button>
+            <Button>淇濆瓨</Button>
+            <Button>鎵撳嵃</Button>
+            <Button>鏇村</Button>
           </div> : null}
-          {card.wrap.type === 'checkVoucher' ? <div className="voucher-header">
-            <Button className="add-background header-btn">淇濆瓨</Button>
-            <Button className="print-background header-btn">鎵撳嵃</Button>
-            <Button className="out-background header-btn">鍏抽棴</Button>
+          {card.wrap.type === 'checkVoucher' ? <div className="voucher-header" style={{padding: `10px ${card.wrap.space || 0}px`}}>
+            <Button>淇濆瓨</Button>
+            <Button>鎵撳嵃</Button>
+            <Button>瀹℃牳</Button>
+            <Button>鍏抽棴</Button>
           </div> : null}
           <div className="voucher-body" style={{padding: `0px ${card.wrap.space || 0}px`}}>
             {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="pre-wrap">
@@ -158,8 +159,8 @@
                 妯℃澘绫诲瀷:
                 <div>鏃ュ父鏀嚭<DownOutlined/></div>
               </div>
-              <Button className="close-temp header-btn">鍏抽棴</Button>
-              <Button className="save-temp header-btn">淇濆瓨</Button>
+              <Button>鍏抽棴</Button>
+              <Button>淇濆瓨</Button>
             </div> : null}
             <VoucherTable config={card}/>
             {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="user">鍒跺崟浜猴細</div> : null}
diff --git a/src/menu/components/module/voucher/index.scss b/src/menu/components/module/voucher/index.scss
index 964fd36..9f43cfe 100644
--- a/src/menu/components/module/voucher/index.scss
+++ b/src/menu/components/module/voucher/index.scss
@@ -24,10 +24,13 @@
     padding: 10px;
     border-bottom: 1px solid #eeeeee;
 
-    .header-btn {
+    .ant-btn {
       height: 28px;
       min-width: 80px;
       margin-right: 10px;
+      background-color: #ffffff;
+      border-color: #d8d8d8;
+      color: rgba(0, 0, 0, 0.65);
     }
   }
   .voucher-body {
@@ -76,12 +79,14 @@
         }
       }
     }
-    .header-btn {
-      float: right;
-      margin-left: 10px;
-    }
     .pre-wrap {
       padding: 10px 0px;
+      >.ant-btn {
+        margin-right: 10px;
+        background-color: #ffffff;
+        border-color: #d8d8d8;
+        color: rgba(0, 0, 0, 0.65);
+      }
     }
     .voucher-date {
       display: inline-block;
@@ -117,38 +122,6 @@
     .user {
       padding-top: 15px;
     }
-  }
-
-  .add-background {
-    background: #26C281;
-    border-color: #26C281;
-    color: #ffffff;
-  }
-  .print-background {
-    background-color: #8E44AD;
-    border-color: #8E44AD;
-    color: #ffffff;
-  }
-  .out-background {
-    background-color: rgb(50, 197, 210);
-    border-color: rgb(50, 197, 210);
-    color: #ffffff;
-  }
-  .save-temp {
-    background-color: #1890ff;
-    border-color: #1890ff;
-    color: #ffffff;
-  }
-  .close-temp {
-    background-color: #ffffff;
-    border-color: #f5222d;
-    color: #f5222d;
-  }
-
-  .system-background {
-    background: #1890ff;
-    border-color: #1890ff;
-    color: #ffffff;
   }
 }
 .menu-voucher-box::after {
diff --git a/src/menu/components/module/voucher/options.jsx b/src/menu/components/module/voucher/options.jsx
index bdc8eb0..2f268e6 100644
--- a/src/menu/components/module/voucher/options.jsx
+++ b/src/menu/components/module/voucher/options.jsx
@@ -1,3 +1,4 @@
+import React from 'react'
 import MenuUtils from '@/utils/utils-custom.js'
 
 /**
@@ -56,6 +57,7 @@
         {field: 'voucherType', values: ['createVoucher', 'checkVoucher']},
         {field: 'voucherTypeText', values: ['createVoucher', 'checkVoucher']},
         {field: 'voucherSign', values: ['createVoucher', 'checkVoucher']},
+        {field: 'printTemp', values: ['createVoucher', 'checkVoucher']},
         {field: 'supModule', values: ['checkTemp', 'checkVoucher']},
         {field: 'attachStatus', values: ['createVoucher', 'checkVoucher']},
       ]
@@ -138,6 +140,26 @@
       ]
     },
     {
+      type: 'printTemps',
+      field: 'printTemp',
+      label: '鎵撳嵃妯℃澘',
+      initval: wrap.printTemp || '',
+      help: (record) => {
+        if (record.printTemp) {
+          return <span onClick={() => {
+            sessionStorage.setItem('mk-print-temp', record.printTemp)
+            window.open('#/hs')
+
+            setTimeout(() => {
+              sessionStorage.removeItem('mk-print-temp')
+            }, 50)
+          }} style={{color: '#1890ff', cursor: 'pointer', fontSize: '13px'}}>#鏌ョ湅妯℃澘</span>
+        }
+        return ''
+      },
+      required: true
+    },
+    {
       type: 'number',
       field: 'space',
       label: '鐣欑櫧',
diff --git a/src/menu/components/module/voucher/voucherTable/index.scss b/src/menu/components/module/voucher/voucherTable/index.scss
index c46fe8d..38a139c 100644
--- a/src/menu/components/module/voucher/voucherTable/index.scss
+++ b/src/menu/components/module/voucher/voucherTable/index.scss
@@ -10,9 +10,8 @@
     position: absolute;
     bottom: 10px;
   }
-  >.ant-table-wrapper {
+  .ant-table-wrapper {
     position: relative;
-    z-index: 1;
   }
   .ant-table {
     color: inherit;
diff --git a/src/menu/components/search/main-search/dragsearch/card.jsx b/src/menu/components/search/main-search/dragsearch/card.jsx
index e09f49c..6e153b6 100644
--- a/src/menu/components/search/main-search/dragsearch/card.jsx
+++ b/src/menu/components/search/main-search/dragsearch/card.jsx
@@ -118,11 +118,11 @@
     if (options.length === 0) {
       options = [{Value: '1', Text: '閫夐」1'}, {Value: '2', Text: '閫夐」2'}]
     }
-    formItem = (<Radio.Group value={card.initval} style={{lineHeight: '36px'}}>
+    formItem = (<Radio.Group value={card.initval} style={{lineHeight: '40px', whiteSpace: 'nowrap'}}>
       {options.map((item, i) => (<Radio key={i} value={item.Value}> {item.Text} </Radio>))}
     </Radio.Group>)
   } else if (card.type === 'check') {
-    formItem = <Checkbox style={{lineHeight: '36px'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
+    formItem = <Checkbox style={{lineHeight: '36px', whiteSpace: 'nowrap'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
   } else if (card.type === 'range') {
     let vals = card.initval.split(',')
     formItem = (<>
diff --git a/src/menu/components/search/main-search/index.jsx b/src/menu/components/search/main-search/index.jsx
index 1f3669c..57643d2 100644
--- a/src/menu/components/search/main-search/index.jsx
+++ b/src/menu/components/search/main-search/index.jsx
@@ -354,9 +354,9 @@
   }
 
   getWrapForms = () => {
-    const { wrap, action } = this.state.card
+    const { card } = this.state
 
-    return getWrapForm(wrap, action)
+    return getWrapForm(card.wrap, card.uuid)
   }
 
   updateWrap = (res) => {
diff --git a/src/menu/components/search/main-search/options.jsx b/src/menu/components/search/main-search/options.jsx
index 8228b2b..2ed6c06 100644
--- a/src/menu/components/search/main-search/options.jsx
+++ b/src/menu/components/search/main-search/options.jsx
@@ -1,7 +1,8 @@
+import MenuUtils from '@/utils/utils-custom.js'
 /**
  * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
  */
-export default function (wrap, action = []) {
+export default function (wrap, uuid) {
   let roleList = sessionStorage.getItem('sysRoles')
   let appType = sessionStorage.getItem('appType')
 
@@ -14,6 +15,9 @@
   } else {
     roleList = []
   }
+
+  let menu = window.GLOB.customMenu
+  let modules = MenuUtils.getSupModules(menu.components, uuid, menu.interfaces)
 
   const wrapForm = [
     {
@@ -168,6 +172,15 @@
       forbid: !!appType
     },
     {
+      type: 'cascader',
+      field: 'supModule',
+      label: '涓婄骇缁勪欢',
+      initval: wrap.supModule || [],
+      required: false,
+      options: modules,
+      forbid: sessionStorage.getItem('editMenuType') === 'popview'
+    },
+    {
       type: 'multiselect',
       field: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index 72c1ce9..7c83d79 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -12,17 +12,18 @@
 
 const { TextArea } = Input
 const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
+const CodeMirror = asyncComponent(() => import('@/templates/zshare/codemirror'))
 const MKTable = asyncComponent(() => import('@/components/normalform/modalform/mkTable'))
 const acTyOptions = {
-  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hoverTitle', 'hidden', 'preButton', 'formCache'],
-  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hoverTitle', 'hidden', 'preButton', 'formCache'],
-  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hoverTitle', 'hidden', 'preButton', 'formCache'],
-  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
-  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
-  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
-  tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'linkmenu', 'width', 'hidden', 'openTab'],
-  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
-  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
+  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'hoverTitle', 'hidden', 'preButton'],
+  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hoverTitle', 'hidden', 'preButton'],
+  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hoverTitle', 'hidden', 'preButton'],
+  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'hover', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
+  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'hover', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
+  popview: ['label', 'Ot', 'OpenType', 'show', 'hover', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
+  tab: ['label', 'Ot', 'OpenType', 'show', 'hover', 'icon', 'class', 'color', 'linkmenu', 'width', 'hidden', 'openTab'],
+  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
+  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'hover', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
   form: ['label', 'OpenType', 'formType', 'intertype', 'Ot', 'execSuccess', 'execError', 'syncComponent', 'width', 'openmenu', 'refreshTab', 'title', 'hidden']
 }
 
@@ -160,7 +161,7 @@
     let reRequired = {}
     let reReadonly = {}
 
-    if (openType === 'pop' || openType === 'prompt' || openType === 'exec') {
+    if (['pop', 'prompt', 'exec'].includes(openType)) {
       let intertype = this.record.intertype
 
       reOptions.intertype = this.state.interTypeOptions
@@ -214,7 +215,7 @@
           shows.push('exInterface', 'exProInterface')
         }
       } else if (intertype === 'inner') {
-        shows.push('innerFunc', 'output', 'recordUser')
+        shows.push('innerFunc', 'output', 'extraParam')
         if (Ot === 'requiredOnce') { // 鍓嶇疆鍑芥暟
           shows.push('preFunc')
         }
@@ -295,7 +296,7 @@
           shows.push('exInterface', 'exProInterface')
         }
       } else if (intertype === 'inner') {
-        shows.push('innerFunc', 'recordUser')
+        shows.push('innerFunc', 'extraParam')
         reRequired.innerFunc = true
       } else {
         shows.push('sql', 'sqlType')
@@ -346,7 +347,7 @@
           shows.push('exInterface', 'exProInterface')
         }
       } else if (this.record.intertype === 'inner') {
-        shows.push('innerFunc', 'recordUser')
+        shows.push('innerFunc', 'extraParam')
         reRequired.innerFunc = true
       }
       if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
@@ -381,7 +382,7 @@
           shows.push('exInterface', 'exProInterface')
         }
       } else if (this.record.intertype === 'inner') {
-        shows.push('innerFunc', 'recordUser')
+        shows.push('innerFunc', 'extraParam')
         reRequired.innerFunc = true
       }
       if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
@@ -408,6 +409,16 @@
     } else if (openType === 'tab') {
       reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl', 'requiredOnce'].includes(op.value))
 
+      if (Ot === 'notRequired') {
+        shows.push('sysId')
+      }
+
+      if (shows.includes('linkmenu') && this.record.linkmenu[0] === 'multiMenu') {
+        shows.push('multiMenus')
+      } else if (this.record.sysId === 'js') {
+        shows.push('sign')
+      }
+
       reRequired.linkmenu = true
       reTooltip.linkmenu = ''
     } else if (openType === 'innerpage') {
@@ -425,7 +436,10 @@
         reRequired.linkmenu = true
         reTooltip.linkmenu = ''
       } else if (this.record.pageTemplate === 'billprint') {
-        shows.push('printTemp')
+        shows.push('printTemp', 'preHandle')
+        if (this.record.preHandle === 'true') {
+          shows.push('pre_func')
+        }
         reOptions.Ot = requireOptions
       } else if (this.record.pageTemplate === 'pay') {
         reOptions.Ot = requireOptions.filter(op => op.value === 'requiredSgl')
@@ -459,7 +473,7 @@
             shows.push('exInterface', 'exProInterface')
           }
         } else if (this.record.intertype === 'inner') {
-          shows.push('innerFunc', 'recordUser')
+          shows.push('innerFunc', 'extraParam')
           reRequired.innerFunc = true
         }
         if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
@@ -554,15 +568,21 @@
         shows.push('reason')
       }
     }
-
+    
     if (shows.includes('syncComponent') && this.record.syncComponent[0] === 'multiComponent') {
       shows.push('syncComponents')
     }
-
+    
+    if (this.record.hidden !== 'true') {
+      shows.push('permission')
+    }
     if (this.record.show === 'icon') {
       reRequired.icon = true
     } else {
       reRequired.icon = false
+      if (['pop', 'prompt', 'exec', 'popview', 'tab', 'innerpage'].includes(openType)) {
+        shows.push('showName')
+      }
     }
 
     return {
@@ -582,6 +602,7 @@
    * 3銆佸垏鎹㈡爣绛剧被鍨嬶紝閲嶇疆鍙�夋爣绛�
    */
   optionChange = (key, value) => {
+    const { type } = this.props
     const { hasclass, appType, requireOptions } = this.state
 
     this.record[key] = value
@@ -616,9 +637,16 @@
         _fieldval.label = '瀵煎嚭Excel'
         _fieldval.class = 'dgreen'
         _fieldval.execSuccess = 'never'
-        _fieldval.Ot = 'requiredOnce'
         _fieldval.control = ''
-        this.record.Ot = 'requiredOnce'
+
+        if (type !== 'card') {
+          _fieldval.Ot = 'requiredOnce'
+          this.record.Ot = 'requiredOnce'
+        } else {
+          _fieldval.Ot = 'notRequired'
+          this.record.Ot = 'notRequired'
+        }
+
         this.record.label = '瀵煎嚭Excel'
         this.record.class = 'dgreen'
         this.record.execSuccess = 'never'
@@ -784,7 +812,7 @@
       let className = ''
       let content = null
       let initVal = item.initVal || ''
-      let help = item.help || ''
+      let help = item.help || null
 
       if (item.type === 'splitLine') {
         fields.push(
@@ -951,27 +979,53 @@
         ]
 
         content = <KeyInterface type={item.key === 'exInterface' ? 'develop' : 'product'}/>
+      } else if (item.type === 'codemirror') {
+        span = 24
+        className = 'codemirror'
+        rules = [
+          { required: item.readonly ? false : item.required, message: '璇疯緭鍏�' + item.label + '!' }
+        ]
+
+        content = <CodeMirror mode="text/javascript"/>
       }
 
       if (help && typeof(help) === 'function') {
         help = help(this.record)
       }
 
-      fields.push(
-        <Col span={span} key={index}>
-          <Form.Item className={className} help={help} label={item.tooltip ?
-            <Tooltip placement="topLeft" overlayStyle={{maxWidth: item.tooltip.length > 25 ? 350 : 250 }} title={<span onClick={(e) => e.stopPropagation()}>{item.tooltip}</span>}>
-              <QuestionCircleOutlined className="mk-form-tip" />
-              {item.label}
-            </Tooltip> : item.label
-          }>
-            {getFieldDecorator(item.key, {
-              initialValue: initVal,
-              rules: rules
-            })(content)}
-          </Form.Item>
-        </Col>
-      )
+      if (help) {
+        fields.push(
+          <Col span={span} key={index}>
+            <Form.Item className={className} help={help} label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayStyle={{maxWidth: item.tooltip.length > 25 ? 350 : 250 }} title={<span onClick={(e) => e.stopPropagation()}>{item.tooltip}</span>}>
+                <QuestionCircleOutlined className="mk-form-tip" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: initVal,
+                rules: rules
+              })(content)}
+            </Form.Item>
+          </Col>
+        )
+      } else {
+        fields.push(
+          <Col span={span} key={index}>
+            <Form.Item className={className} label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayStyle={{maxWidth: item.tooltip.length > 25 ? 350 : 250 }} title={<span onClick={(e) => e.stopPropagation()}>{item.tooltip}</span>}>
+                <QuestionCircleOutlined className="mk-form-tip" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: initVal,
+                rules: rules
+              })(content)}
+            </Form.Item>
+          </Col>
+        )
+      }
     })
 
     return fields
@@ -1078,14 +1132,32 @@
         
               let id = values.linkmenu[values.linkmenu.length - 1]
         
-              list.forEach(item => {
-                if (item.MenuID === id) {
-                  values.MenuID = id
-                  values.MenuName = item.MenuName
-                  values.MenuNo = item.MenuNo
-                  values.tabType = item.type
-                }
-              })
+              if (id !== 'multiMenu') {
+                list.forEach(item => {
+                  if (item.MenuID === id) {
+                    values.MenuID = id
+                    values.MenuName = item.MenuName
+                    values.MenuNo = item.MenuNo
+                    values.tabType = item.type
+                  }
+                })
+                delete values.multiMenus
+              } else {
+                values.multiMenus.forEach(menu => {
+                  menu.sign = menu.sign || ''
+
+                  let _id = menu.menuId[menu.menuId.length - 1]
+
+                  list.forEach(item => {
+                    if (item.MenuID === _id) {
+                      menu.MenuID = _id
+                      menu.MenuName = item.MenuName
+                      menu.MenuNo = item.MenuNo
+                      menu.tabType = item.type
+                    }
+                  })
+                })
+              }
             }
           } else if (values.OpenType === 'funcbutton' && values.funcType === 'expPdf') {
             values.Ot = 'notRequired'
@@ -1115,6 +1187,14 @@
             })
           }
 
+          if (values.extraParam) {
+            values.extraParam.forEach(n => {
+              values[n] = 'true'
+            })
+
+            delete values.extraParam
+          }
+
           resolve(values)
         } else {
           reject(err)
diff --git a/src/menu/components/share/actioncomponent/actionform/index.scss b/src/menu/components/share/actioncomponent/actionform/index.scss
index a056976..6f639c4 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.scss
+++ b/src/menu/components/share/actioncomponent/actionform/index.scss
@@ -17,6 +17,17 @@
       width: 86%;
     }
   }
+  .codemirror {
+    .ant-col-sm-7 {
+      width: 14%;
+    }
+    .ant-col-sm-17 {
+      width: 86%;
+    }
+    .ant-form-item-label {
+      opacity: 0;
+    }
+  }
   .ant-radio-group {
     white-space: nowrap;
     .ant-radio-wrapper {
diff --git a/src/menu/components/share/actioncomponent/actionform/mkPrintTemps/index.jsx b/src/menu/components/share/actioncomponent/actionform/mkPrintTemps/index.jsx
index 4ad9280..3d37897 100644
--- a/src/menu/components/share/actioncomponent/actionform/mkPrintTemps/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/mkPrintTemps/index.jsx
@@ -74,6 +74,7 @@
         showSearch
         allowClear
         value={value}
+        dropdownMatchSelectWidth={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/menu/components/share/actioncomponent/formconfig.jsx b/src/menu/components/share/actioncomponent/formconfig.jsx
index 8c39bc9..937540a 100644
--- a/src/menu/components/share/actioncomponent/formconfig.jsx
+++ b/src/menu/components/share/actioncomponent/formconfig.jsx
@@ -8,7 +8,7 @@
  * @param {*} setting        缁勪欢閰嶇疆
  * @param {*} usefulFields   瀛樺偍杩囩▼鍙敤鐨勫紑濮嬪瓧娈�
  */
-export function getActionForm (card, functip, config, usefulFields, modules = [], anchors = [], side) {
+export function getActionForm (card, functip, config, usefulFields, modules = [], anchors = [], side, position) {
   let appType = sessionStorage.getItem('appType')
   let viewType = sessionStorage.getItem('editMenuType') // 寮圭獥 popview
   let setting = config.setting || {}
@@ -313,6 +313,29 @@
     card.formType = 'switch'
   }
 
+  let width = card.width || (card.width === 0 ? 0 : 12)
+  if (/x/.test(card.width)) {
+    width = +width.replace(/x/, '.5')
+  }
+
+  let extraParam = []
+  if (card.recordUser === 'true') {
+    extraParam.push('recordUser')
+  }
+  if (card.dataM === 'true') {
+    extraParam.push('dataM')
+  }
+
+  if (!appType) {
+    if (typeof(card.openmenu) === 'string') {
+      card.openmenu = []
+    }
+  } else {
+    if (typeof(card.openmenu) !== 'string') {
+      card.openmenu = ''
+    }
+  }
+
   let forms = [
     {
       type: 'select',
@@ -494,14 +517,14 @@
       initVal: card.linkmenu || (isApp ? '' : []),
       required: true,
       extendName: 'MenuNo',
-      options: isApp ? appMenus : menulist
+      options: isApp ? appMenus : (menulist.length ? [...menulist, {value: 'multiMenu', label: '澶氳彍鍗�'}] : [])
     },
     {
       type: 'text',
       key: 'prefix',
       label: '鍓嶇紑',
       initVal: card.prefix || '',
-      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid寮�澶淬��',
+      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid锛�:鎴�,锛夊紑澶达紝mkbid锛�:鎴�,锛夎烦杞悗灏嗚鍘婚櫎銆備緥濡傦細mkbid:123456 璺宠浆鍚庨〉闈ID涓� 123456銆�',
       required: false
     },
     {
@@ -809,10 +832,10 @@
       key: 'width',
       min: 0,
       max: 24,
-      precision: 0,
+      precision: 1,
       label: '瀹藉害',
-      initVal: card.width || (card.width === 0 ? 0 : 12),
-      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼�備负 0 鏃跺搴﹁嚜閫傚簲銆�',
+      initVal: width,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼�備负 0 鏃跺搴﹁嚜閫傚簲銆傚彲璁剧疆鍗婂垪鍗�.5銆�',
       forbid: type !== 'card',
       required: true
     },
@@ -847,6 +870,25 @@
       }, {
         value: 'link',
         text: '鏂囧瓧+鍥炬爣'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'hover',
+      label: '鎮诞鏁堟灉',
+      initVal: card.hover || '',
+      tooltip: '榧犳爣鎮诞鎸夐挳涓婃柟鏃剁殑棰滆壊鍙樺寲銆�',
+      required: false,
+      forbid: type === 'card' || appType === 'mob',
+      options: [{
+        value: '',
+        text: '鏃�'
+      }, {
+        value: 'mk-btn-hover-bg',
+        text: '鑳屾櫙鍙樺寲'
+      }, {
+        value: 'mk-btn-hover-border',
+        text: '杈规鍙樺寲'
       }]
     },
     {
@@ -1029,14 +1071,14 @@
       tooltip: '鎵ц鎴愬姛鍚庣殑杩斿洖鍊笺�傜郴缁熷嚱鏁板彲鎸囧畾杩斿洖鐨勫彉閲忥紙浠绗﹀紑澶达紝杩斿洖id鏃跺彲浣跨敤@id@锛夛紱鑷畾涔夊嚱鏁板彲鎸囧畾杩斿洖瀛楁锛堝id锛夈��',
       initVal: card.output || '',
       required: false,
-      forbid: viewType === 'popview'
+      // forbid: viewType === 'popview'
     },
     {
       type: 'text',
       key: 'tipTitle',
       label: '纭鎻愮ず',
       initVal: card.tipTitle || '',
-      tooltip: '娉細寮圭獥锛堣〃鍗曪級鍦ㄦ樉绀轰负鏄惁妗嗘椂鏈夋晥銆�',
+      tooltip: '鎻愮ず妗嗙殑纭鎻愮ず淇℃伅銆�',
       required: false
     },
     {
@@ -1047,6 +1089,20 @@
       tooltip: '榧犳爣鎮诞鍦ㄦ寜閽笂鏂规椂鐨勬彁绀轰俊鎭��',
       forbid: appType === 'mob',
       required: false
+    },
+    {
+      type: 'select',
+      key: 'showName',
+      label: '鏄剧ず鍐呭',
+      initVal: card.showName || '',
+      tooltip: '琛岀骇鎸夐挳鍙�氳繃琛屼俊鎭帶鍒舵寜閽樉绀哄唴瀹广��',
+      required: false,
+      allowClear: true,
+      forbid: position !== 'line',
+      options: columns.map(item => ({
+        value: item.field,
+        text: `${item.label}锛�${item.field}锛塦
+      }))
     },
     {
       type: 'radio',
@@ -1221,18 +1277,18 @@
       forbid: appType === 'mob'
     },
     {
-      type: 'radio',
-      key: 'recordUser',
-      label: '璁板綍鐢ㄦ埛',
-      initVal: card.recordUser || 'false',
-      tooltip: '褰撻�夋嫨鈥滄槸鈥濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� username 涓� fullname銆�',
+      type: 'checkbox',
+      key: 'extraParam',
+      label: '鎵╁睍鍙傛暟',
+      initVal: extraParam,
+      tooltip: '閫夋嫨鈥滅敤鎴蜂俊鎭�濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� username 涓� fullname銆傞�夋嫨鈥滄暟鎹鐞嗗憳鈥濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� dataM 锛岀鐞嗗憳鍊间负鈥淵鈥濓紝鏅�氱敤鎴蜂负绌恒��',
       required: false,
       options: [{
-        value: 'false',
-        text: '鍚�'
+        value: 'recordUser',
+        text: '鐢ㄦ埛淇℃伅'
       }, {
-        value: 'true',
-        text: '鏄�'
+        value: 'dataM',
+        text: '鏁版嵁绠$悊鍛�'
       }]
     },
     {
@@ -1282,21 +1338,21 @@
       initVal: card.reason || '',
       required: false
     },
-    {
-      type: 'radio',
-      key: 'formCache',
-      label: '琛ㄥ崟缂撳瓨',
-      initVal: card.formCache || 'false',
-      tooltip: '涓昏鐢ㄤ簬鏁版嵁淇敼鍚庯紝鏇存柊鐩稿叧琛ㄥ崟鐨勯�夐」锛屾竻绌虹紦瀛樺悗琛ㄥ崟鍐嶆鎵撳紑鏃舵暟鎹細閲嶆柊鍔犺浇銆�',
-      required: false,
-      options: [{
-        value: 'false',
-        text: '涓嶆竻绌�'
-      }, {
-        value: 'clear',
-        text: '娓呯┖'
-      }]
-    },
+    // {
+    //   type: 'radio',
+    //   key: 'formCache',
+    //   label: '琛ㄥ崟缂撳瓨',
+    //   initVal: card.formCache || 'false',
+    //   tooltip: '涓昏鐢ㄤ簬鏁版嵁淇敼鍚庯紝鏇存柊鐩稿叧琛ㄥ崟鐨勯�夐」锛屾竻绌虹紦瀛樺悗琛ㄥ崟鍐嶆鎵撳紑鏃舵暟鎹細閲嶆柊鍔犺浇銆�',
+    //   required: false,
+    //   options: [{
+    //     value: 'false',
+    //     text: '涓嶆竻绌�'
+    //   }, {
+    //     value: 'clear',
+    //     text: '娓呯┖'
+    //   }]
+    // },
     {
       type: 'radio',
       key: 'hidden',
@@ -1311,6 +1367,18 @@
         value: 'true',
         text: '鏄�'
       }]
+    },
+    {
+      type: 'radio',
+      key: 'permission',
+      label: '鏉冮檺楠岃瘉',
+      initVal: card.permission || 'true',
+      required: false,
+      options: [
+        {value: 'true', text: '缁ф壙鑿滃崟'},
+        {value: 'false', text: '绂佺敤'},
+      ],
+      forbid: viewType === 'popview'
     },
     {
       type: 'splitLine',
@@ -1457,6 +1525,87 @@
           options: modules
         }
       ]
+    },
+    {
+      type: 'radio',
+      key: 'sysId',
+      label: '鑷畾涔塈D',
+      initVal: card.sysId || '',
+      tooltip: '涓嶉�夎鎸夐挳鍙湪鍓嶇鐢熸垚ID鍊�(32浣�)锛屼綔涓哄悗缁彍鍗曠殑BID锛屽瓨鍦ㄦ爣璁版椂锛孖D鍊煎悗灏嗘嫾鎺ユ爣璁板�笺��',
+      required: false,
+      options: [{
+        value: '',
+        text: '绌�'
+      }, {
+        value: 'js',
+        text: '鍓嶇鐢熸垚'
+      }]
+    },
+    {
+      type: 'text',
+      key: 'sign',
+      label: '鏍囪',
+      initVal: card.sign || '',
+      required: false
+    },
+    {
+      type: 'table',
+      key: 'multiMenus',
+      label: '鑿滃崟鍒楄〃',
+      initVal: card.multiMenus || [],
+      required: true,
+      actions: ['edit', 'del', 'add', 'move'],
+      columns: [
+        {
+          title: '鍚嶇О',
+          dataIndex: 'name',
+          inputType: 'text',
+          editable: true,
+          required: false,
+          width: '30%'
+        },
+        {
+          title: '鑿滃崟',
+          dataIndex: 'menuId',
+          inputType: 'cascader',
+          editable: true,
+          required: true,
+          extends: [{key: 'label', value: 'label', mutilLabel: 'name'}],
+          width: '30%',
+          render: (text, record) => record.label,
+          options: menulist
+        },
+        {
+          title: '鏍囪',
+          dataIndex: 'sign',
+          inputType: 'text',
+          editable: true,
+          required: false,
+          width: '20%'
+        }
+      ]
+    },
+    {
+      type: 'radio',
+      key: 'preHandle',
+      label: '鑷畾涔夎剼鏈�',
+      initVal: card.preHandle || 'false',
+      // tooltip: '闅愯棌鍚庢寜閽湪椤甸潰涓笉鏄剧ず锛屼笖涓嶅弬涓庢潈闄愬垎閰嶃��',
+      required: false,
+      options: [{
+        value: 'false',
+        text: '绂佺敤'
+      }, {
+        value: 'true',
+        text: '鍚敤'
+      }]
+    },
+    {
+      type: 'codemirror',
+      key: 'pre_func',
+      label: '鑷畾涔夎剼鏈�',
+      initVal: card.pre_func || '',
+      required: true,
     }
   ]
 
@@ -1470,7 +1619,7 @@
  * @param {*} setting        缁勪欢閰嶇疆
  * @param {*} usefulFields   瀛樺偍杩囩▼鍙敤鐨勫紑濮嬪瓧娈�
  */
-export function getBaseTableActionForm (card, functip, config, usefulFields, modules) {
+export function getBaseTableActionForm (card, functip, config, usefulFields, modules, position) {
   let viewType = sessionStorage.getItem('editMenuType') // 寮圭獥 popview
   let setting = config.setting || {}
   let columns = config.columns || []
@@ -1559,6 +1708,14 @@
 
   if (card.OpenType === 'form') { // 鎷栨嫿娣诲姞绫诲瀷杞崲
     card.OpenType = 'pop'
+  }
+
+  let extraParam = []
+  if (card.recordUser === 'true') {
+    extraParam.push('recordUser')
+  }
+  if (card.dataM === 'true') {
+    extraParam.push('dataM')
   }
 
   let forms = [
@@ -1721,7 +1878,7 @@
       initVal: card.linkmenu || [],
       required: true,
       extendName: 'MenuNo',
-      options: menulist
+      options: menulist.length ? [...menulist, {value: 'multiMenu', label: '澶氳彍鍗�'}] : []
     },
     {
       type: 'textarea',
@@ -2063,6 +2220,24 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'hover',
+      label: '鎮诞鏁堟灉',
+      initVal: card.hover || '',
+      tooltip: '榧犳爣鎮诞鎸夐挳涓婃柟鏃剁殑棰滆壊鍙樺寲銆�',
+      required: false,
+      options: [{
+        value: '',
+        text: '鏃�'
+      }, {
+        value: 'mk-btn-hover-bg',
+        text: '鑳屾櫙鍙樺寲'
+      }, {
+        value: 'mk-btn-hover-border',
+        text: '杈规鍙樺寲'
+      }]
+    },
+    {
       type: 'icon',
       key: 'icon',
       label: '鍥炬爣',
@@ -2166,14 +2341,14 @@
       tooltip: '鎵ц鎴愬姛鍚庣殑杩斿洖鍊笺�傜郴缁熷嚱鏁板彲鎸囧畾杩斿洖鐨勫彉閲忥紙浠绗﹀紑澶达紝杩斿洖id鏃跺彲浣跨敤@id@锛夛紱鑷畾涔夊嚱鏁板彲鎸囧畾杩斿洖瀛楁锛堝id锛夈��',
       initVal: card.output || '',
       required: false,
-      forbid: viewType === 'popview'
+      // forbid: viewType === 'popview'
     },
     {
       type: 'text',
       key: 'tipTitle',
       label: '纭鎻愮ず',
       initVal: card.tipTitle || '',
-      tooltip: '娉細寮圭獥锛堣〃鍗曪級鍦ㄦ樉绀轰负鏄惁妗嗘椂鏈夋晥銆�',
+      tooltip: '鎻愮ず妗嗙殑纭鎻愮ず淇℃伅銆�',
       required: false
     },
     {
@@ -2183,6 +2358,20 @@
       initVal: card.hoverTitle || '',
       tooltip: '榧犳爣鎮诞鍦ㄦ寜閽笂鏂规椂鐨勬彁绀轰俊鎭��',
       required: false
+    },
+    {
+      type: 'select',
+      key: 'showName',
+      label: '鏄剧ず鍐呭',
+      initVal: card.showName || '',
+      tooltip: '琛岀骇鎸夐挳鍙�氳繃琛屼俊鎭帶鍒舵寜閽樉绀哄唴瀹广��',
+      required: false,
+      allowClear: true,
+      forbid: position !== 'line',
+      options: columns.map(item => ({
+        value: item.field,
+        text: `${item.label}锛�${item.field}锛塦
+      }))
     },
     {
       type: 'radio',
@@ -2279,18 +2468,18 @@
       required: false
     },
     {
-      type: 'radio',
-      key: 'recordUser',
-      label: '璁板綍鐢ㄦ埛',
-      initVal: card.recordUser || 'false',
-      tooltip: '褰撻�夋嫨鈥滄槸鈥濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� username 涓� fullname銆�',
+      type: 'checkbox',
+      key: 'extraParam',
+      label: '鎵╁睍鍙傛暟',
+      initVal: extraParam,
+      tooltip: '閫夋嫨鈥滅敤鎴蜂俊鎭�濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� username 涓� fullname銆傞�夋嫨鈥滄暟鎹鐞嗗憳鈥濇椂锛屽唴閮ㄥ嚱鏁扮殑浼犲弬浼氬鍔� dataM 锛岀鐞嗗憳鍊间负鈥淵鈥濓紝鏅�氱敤鎴蜂负绌恒��',
       required: false,
       options: [{
-        value: 'false',
-        text: '鍚�'
+        value: 'recordUser',
+        text: '鐢ㄦ埛淇℃伅'
       }, {
-        value: 'true',
-        text: '鏄�'
+        value: 'dataM',
+        text: '鏁版嵁绠$悊鍛�'
       }]
     },
     {
@@ -2340,21 +2529,21 @@
       initVal: card.reason || '',
       required: false
     },
-    {
-      type: 'radio',
-      key: 'formCache',
-      label: '琛ㄥ崟缂撳瓨',
-      initVal: card.formCache || 'false',
-      tooltip: '涓昏鐢ㄤ簬鏁版嵁淇敼鍚庯紝鏇存柊鐩稿叧琛ㄥ崟鐨勯�夐」锛屾竻绌虹紦瀛樺悗琛ㄥ崟鍐嶆鎵撳紑鏃舵暟鎹細閲嶆柊鍔犺浇銆�',
-      required: false,
-      options: [{
-        value: 'false',
-        text: '涓嶆竻绌�'
-      }, {
-        value: 'clear',
-        text: '娓呯┖'
-      }]
-    },
+    // {
+    //   type: 'radio',
+    //   key: 'formCache',
+    //   label: '琛ㄥ崟缂撳瓨',
+    //   initVal: card.formCache || 'false',
+    //   tooltip: '涓昏鐢ㄤ簬鏁版嵁淇敼鍚庯紝鏇存柊鐩稿叧琛ㄥ崟鐨勯�夐」锛屾竻绌虹紦瀛樺悗琛ㄥ崟鍐嶆鎵撳紑鏃舵暟鎹細閲嶆柊鍔犺浇銆�',
+    //   required: false,
+    //   options: [{
+    //     value: 'false',
+    //     text: '涓嶆竻绌�'
+    //   }, {
+    //     value: 'clear',
+    //     text: '娓呯┖'
+    //   }]
+    // },
     {
       type: 'radio',
       key: 'hidden',
@@ -2369,6 +2558,18 @@
         value: 'true',
         text: '鏄�'
       }]
+    },
+    {
+      type: 'radio',
+      key: 'permission',
+      label: '鏉冮檺楠岃瘉',
+      initVal: card.permission || 'true',
+      required: false,
+      options: [
+        {value: 'true', text: '鍚敤'},
+        {value: 'false', text: '绂佺敤'},
+      ],
+      forbid: viewType === 'popview'
     },
     {
       type: 'radio',
@@ -2420,6 +2621,87 @@
           options: modules
         }
       ]
+    },
+    {
+      type: 'radio',
+      key: 'sysId',
+      label: '鑷畾涔塈D',
+      initVal: card.sysId || '',
+      tooltip: '涓嶉�夎鎸夐挳鍙湪鍓嶇鐢熸垚ID鍊�(32浣�)锛屼綔涓哄悗缁彍鍗曠殑BID锛屽瓨鍦ㄦ爣璁版椂锛孖D鍊煎悗灏嗘嫾鎺ユ爣璁板�笺��',
+      required: false,
+      options: [{
+        value: '',
+        text: '绌�'
+      }, {
+        value: 'js',
+        text: '鍓嶇鐢熸垚'
+      }]
+    },
+    {
+      type: 'text',
+      key: 'sign',
+      label: '鏍囪',
+      initVal: card.sign || '',
+      required: false
+    },
+    {
+      type: 'table',
+      key: 'multiMenus',
+      label: '鑿滃崟鍒楄〃',
+      initVal: card.multiMenus || [],
+      required: true,
+      actions: ['edit', 'del', 'add', 'move'],
+      columns: [
+        {
+          title: '鍚嶇О',
+          dataIndex: 'name',
+          inputType: 'text',
+          editable: true,
+          required: false,
+          width: '30%'
+        },
+        {
+          title: '鑿滃崟',
+          dataIndex: 'menuId',
+          inputType: 'cascader',
+          editable: true,
+          required: true,
+          extends: [{key: 'label', value: 'label', mutilLabel: 'name'}],
+          width: '30%',
+          render: (text, record) => record.label,
+          options: menulist
+        },
+        {
+          title: '鏍囪',
+          dataIndex: 'sign',
+          inputType: 'text',
+          editable: true,
+          required: false,
+          width: '20%'
+        }
+      ]
+    },
+    {
+      type: 'radio',
+      key: 'preHandle',
+      label: '鑷畾涔夎剼鏈�',
+      initVal: card.preHandle || 'false',
+      // tooltip: '闅愯棌鍚庢寜閽湪椤甸潰涓笉鏄剧ず锛屼笖涓嶅弬涓庢潈闄愬垎閰嶃��',
+      required: false,
+      options: [{
+        value: 'false',
+        text: '绂佺敤'
+      }, {
+        value: 'true',
+        text: '鍚敤'
+      }]
+    },
+    {
+      type: 'codemirror',
+      key: 'pre_func',
+      label: '鑷畾涔夎剼鏈�',
+      initVal: card.pre_func || '',
+      required: true,
     }
   ]
 
diff --git a/src/menu/components/share/actioncomponent/index.jsx b/src/menu/components/share/actioncomponent/index.jsx
index 4029b06..96a9190 100644
--- a/src/menu/components/share/actioncomponent/index.jsx
+++ b/src/menu/components/share/actioncomponent/index.jsx
@@ -120,7 +120,17 @@
     const { card, actionlist } = this.state
 
     let _card = fromJS(card).toJS()
-    _card.style = style
+    _card.style = fromJS(style).toJS()
+
+    if (_card.style.paddingLeft === '15px') {
+      delete _card.style.paddingLeft
+    }
+    if (_card.style.paddingRight === '15px') {
+      delete _card.style.paddingRight
+    }
+    if (_card.style.minHeight === '28px') {
+      delete _card.style.minHeight
+    }
 
     let _actionlist = actionlist.map(cell => {
       if (cell.uuid === _card.uuid) return _card
@@ -137,6 +147,10 @@
   changeBtnStyle = (element) => {
     let _style = element.style ? fromJS(element.style).toJS() : {}
     let options = ['font', 'border', 'background', 'margin', 'padding', 'minHeight']
+
+    _style.paddingLeft = _style.paddingLeft || '15px'
+    _style.paddingRight = _style.paddingRight || '15px'
+    _style.minHeight = _style.minHeight || '28px'
 
     this.setState({
       card: element
@@ -718,6 +732,7 @@
           destroyOnClose
         >
           <ActionForm
+            type={config.type === 'tree' ? 'card' : ''}
             card={card}
             formlist={this.state.formlist}
             inputSubmit={this.handleSubmit}
diff --git a/src/menu/components/share/normalheader/index.jsx b/src/menu/components/share/normalheader/index.jsx
index acc4e22..e0ed3f4 100644
--- a/src/menu/components/share/normalheader/index.jsx
+++ b/src/menu/components/share/normalheader/index.jsx
@@ -36,11 +36,22 @@
   }
 
   getStyle = (style) => {
-    if (!style.borderBottomWidth) {
-      style.borderBottomWidth = '0px'
+    let _style = fromJS(style).toJS()
+    if (!_style.borderBottomWidth) {
+      _style.borderBottomWidth = '0px'
+    }
+    if (_style.fontFamily) {
+      if (_style.fontFamily.length === 0) {
+        delete _style.fontFamily
+      } else {
+        _style.fontFamily = _style.fontFamily.join(',')
+      }
+    }
+    if (_style.lineHeight === 2.8) {
+      delete _style.lineHeight
     }
 
-    let _config = {...this.props.config, headerStyle: style}
+    let _config = {...this.props.config, headerStyle: _style}
     
     this.props.updateComponent(_config)
   }
@@ -48,9 +59,13 @@
   changeStyle = () => {
     const { config } = this.props
 
-    let options = ['font', 'border', 'background', 'padding']
+    let _style = config.headerStyle ? fromJS(config.headerStyle).toJS() : {}
+    let options = ['font', 'border', 'background', 'padding', 'fontFamily']
 
-    MKEmitter.emit('changeStyle', options, config.headerStyle, this.getStyle)
+    _style.fontFamily = _style.fontFamily ? _style.fontFamily.split(',') : []
+    _style.lineHeight = _style.lineHeight || 2.8
+
+    MKEmitter.emit('changeStyle', options, _style, this.getStyle)
   }
 
   render() {
diff --git a/src/menu/components/share/normalheader/index.scss b/src/menu/components/share/normalheader/index.scss
index 0d9f65f..cc3679c 100644
--- a/src/menu/components/share/normalheader/index.scss
+++ b/src/menu/components/share/normalheader/index.scss
@@ -12,6 +12,7 @@
     text-decoration: inherit;
     font-weight: inherit;
     font-style: inherit;
+    font-family: inherit;
     float: left;
     line-height: inherit;
     margin-left: 10px;
@@ -41,6 +42,10 @@
     border: 1px solid #d9d9d9;
     opacity: 0.6;
   }
+  .ant-input-search.ant-input-group-wrapper {
+    position: relative;
+    top: 5px;
+  }
 }
 .normal-header:not(.tree-search) {
   display: flex;
diff --git a/src/menu/components/share/searchcomponent/dragsearch/card.jsx b/src/menu/components/share/searchcomponent/dragsearch/card.jsx
index 6061187..f13b469 100644
--- a/src/menu/components/share/searchcomponent/dragsearch/card.jsx
+++ b/src/menu/components/share/searchcomponent/dragsearch/card.jsx
@@ -1,6 +1,6 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
-import { Select, DatePicker, Input, Popover, Form, Switch, Checkbox } from 'antd'
+import { Select, DatePicker, Input, Popover, Form, Switch, Checkbox, Radio } from 'antd'
 import { EditOutlined, CopyOutlined, CloseOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -105,15 +105,23 @@
       format={format}
       className="data-range"
       placeholder={['BeginTime', 'EndTime']}
-      renderExtraFooter={() => 'extra footer'}
+      renderExtraFooter={() => 'extra footer'} 
       value={_defaultValue}
     />
   } else if (card.type === 'group') {
     formItem = <DateGroup card={card} />
   } else if (card.type === 'switch') {
     formItem = (<Switch checkedChildren={card.openText || ''} unCheckedChildren={card.closeText || ''} style={{marginTop: '8px'}} checked={card.initval === card.openVal}/>)
+  } else if (card.type === 'radio') {
+    let options = card.options
+    if (options.length === 0) {
+      options = [{Value: '1', Text: '閫夐」1'}, {Value: '2', Text: '閫夐」2'}]
+    }
+    formItem = (<Radio.Group value={card.initval} style={{lineHeight: '40px', whiteSpace: 'nowrap'}}>
+      {options.map((item, i) => (<Radio key={i} value={item.Value}> {item.Text} </Radio>))}
+    </Radio.Group>)
   } else if (card.type === 'check') {
-    formItem = <Checkbox style={{lineHeight: '36px'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
+    formItem = <Checkbox style={{lineHeight: '36px', whiteSpace: 'nowrap'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
   } else if (card.type === 'range') {
     type = 'range-wrap'
     let vals = card.initval.split(',')
diff --git a/src/menu/components/share/searchcomponent/index.jsx b/src/menu/components/share/searchcomponent/index.jsx
index 6752638..5aecd30 100644
--- a/src/menu/components/share/searchcomponent/index.jsx
+++ b/src/menu/components/share/searchcomponent/index.jsx
@@ -93,6 +93,7 @@
    * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
    */
   handleSearch = (card) => {
+    const { config } = this.props
     const { searchlist } = this.state
     let linkableFields = []
 
@@ -107,10 +108,17 @@
       })
     })
 
+    let columns = null
+    if (config.columns && config.columns.length) {
+      columns = config.columns.map(item => {
+        return {key: item.uuid, text: item.field, value: item.field, label: item.label}
+      })
+    }
+
     this.setState({
       visible: true,
       card: card,
-      formlist: getSearchForm(card, linkableFields, [], 'header')
+      formlist: getSearchForm(card, linkableFields, columns, 'header')
     })
   }
 
diff --git a/src/menu/components/share/searchcomponent/index.scss b/src/menu/components/share/searchcomponent/index.scss
index fd5bdac..48586a9 100644
--- a/src/menu/components/share/searchcomponent/index.scss
+++ b/src/menu/components/share/searchcomponent/index.scss
@@ -1,9 +1,14 @@
 .model-custom-header-search-list {
   padding: 0px;
 
-  .ant-row >.ant-col {
-    float: right;
-    padding: 0 6px;
+  >.ant-row {
+    text-align: right;
+    >.ant-col {
+      display: inline-block;
+      float: none;
+      padding: 0 6px;
+      text-align: left;
+    }
   }
 
   .page-card {
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 8af9c30..3377f09 100644
--- a/src/menu/components/table/base-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/base-table/columns/editColumn/index.jsx
@@ -91,7 +91,7 @@
 
     if (this.record.type === 'text' || this.record.type === 'number') {
       if (this.record.perspective === 'linkmenu') {
-        _options.push('linkmenu', 'linkfields', 'open')
+        _options.push('linkmenu', 'open')
       } else if (this.record.perspective === 'linkurl') {
         _options.push('linkurl', 'linkfields', 'open')
       }
diff --git a/src/menu/components/table/base-table/options.jsx b/src/menu/components/table/base-table/options.jsx
index 85ee2bf..288cd00 100644
--- a/src/menu/components/table/base-table/options.jsx
+++ b/src/menu/components/table/base-table/options.jsx
@@ -20,6 +20,17 @@
     },
     {
       type: 'radio',
+      field: 'parity',
+      label: '濂囧伓寮傝壊',
+      initval: wrap.parity || 'false',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
+      ]
+    },
+    {
+      type: 'radio',
       field: 'bordered',
       label: '杈规',
       initval: wrap.bordered || 'true',
@@ -36,8 +47,8 @@
       initval: wrap.actionfixed !== 'true' ? 'false' : 'true',
       required: false,
       options: [
-        {value: 'true', label: '鏄�'},
-        {value: 'false', label: '鍚�'},
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
       ]
     },
     {
@@ -64,20 +75,6 @@
         {value: 'small', label: '灏�'},
         {value: 'mini', label: '杩蜂綘'},
       ]
-    },
-    {
-      type: 'select',
-      field: 'selected',
-      label: '鏁版嵁閫変腑',
-      initval: wrap.selected || 'false',
-      tooltip: '鍒濆鍖栵細鏁版嵁鍔犺浇鏃堕�変腑棣栬鏁版嵁锛屼粎鎵ц涓�娆°�傛暟鎹姞杞斤細姣忔鏁版嵁鍔犺浇鏃跺潎閫変腑棣栬锛堝綋鎸夐挳鎵ц瀹屾垚骞惰繑鍥炰富閿�兼椂锛岄粯璁ら�変腑涓婚敭鍊煎搴旇锛夈�傞�変腑鏍囪锛氳繑鍥炴暟鎹腑瀛樺湪 selected 瀛楁锛屼笖鍊间负 true 鐨勬暟鎹閫変腑銆傛敞锛氬惎鐢ㄦ棤浜哄�煎畧鏃舵棤鏁堛��',
-      required: false,
-      options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'init', label: '鍒濆鍖�'},
-        {value: 'always', label: '鏁版嵁鍔犺浇'},
-        {value: 'sign', label: '閫変腑鏍囪'}
-      ],
     },
     // {
     //   type: 'radio',
@@ -138,15 +135,18 @@
       ]
     },
     {
-      type: 'number',
-      field: 'btnlimit',
-      label: '鎸夐挳闄愬埗',
-      initval: wrap.btnlimit || '',
-      tooltip: '鎸夐挳鏁伴噺闄愬埗锛岃秴鍑虹殑鎸夐挳浼氬湪鏇村涓笅鎷夋樉绀猴紝娉細鏇村涓殑鎸夐挳涓嶈缁戝畾鍙屽嚮浜嬩欢銆�',
-      min: 3,
-      max: 3000,
-      precision: 0,
-      required: false
+      type: 'select',
+      field: 'selected',
+      label: '鏁版嵁閫変腑',
+      initval: wrap.selected || 'false',
+      tooltip: '鍒濆鍖栵細鏁版嵁鍔犺浇鏃堕�変腑棣栬鏁版嵁锛屼粎鎵ц涓�娆°�傛暟鎹姞杞斤細姣忔鏁版嵁鍔犺浇鏃跺潎閫変腑棣栬锛堝綋鎸夐挳鎵ц瀹屾垚骞惰繑鍥炰富閿�兼椂锛岄粯璁ら�変腑涓婚敭鍊煎搴旇锛夈�傞�変腑鏍囪锛氳繑鍥炴暟鎹腑瀛樺湪 selected 瀛楁锛屼笖鍊间负 true 鐨勬暟鎹閫変腑銆傛敞锛氬惎鐢ㄦ棤浜哄�煎畧鏃舵棤鏁堛��',
+      required: false,
+      options: [
+        {value: 'false', label: '鏃�'},
+        {value: 'init', label: '鍒濆鍖�'},
+        {value: 'always', label: '鏁版嵁鍔犺浇'},
+        {value: 'sign', label: '閫変腑鏍囪'}
+      ],
     },
     {
       type: 'number',
@@ -211,6 +211,17 @@
     },
     {
       type: 'number',
+      field: 'btnlimit',
+      label: '鎸夐挳闄愬埗',
+      initval: wrap.btnlimit || '',
+      tooltip: '鎸夐挳鏁伴噺闄愬埗锛岃秴鍑虹殑鎸夐挳浼氬湪鏇村涓笅鎷夋樉绀猴紝娉細鏇村涓殑鎸夐挳涓嶈缁戝畾鍙屽嚮浜嬩欢銆�',
+      min: 3,
+      max: 3000,
+      precision: 0,
+      required: false
+    },
+    {
+      type: 'number',
       field: 'maxPageSize',
       label: '姣忛〉鏈�澶ф暟',
       initval: wrap.maxPageSize || '',
diff --git a/src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx b/src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
index 0e64f59..ad0da61 100644
--- a/src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
+++ b/src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
@@ -266,7 +266,7 @@
           </Col> : null}
           {!type ? <Col span={10}>
             <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0, whiteSpace: 'nowrap'}}>
-              ErrorCode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT锛�, retmsg
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT锛�, retmsg
             </Form.Item>
           </Col> : null}
           {!type ? <Col span={24} className="sqlfield">
diff --git a/src/menu/components/table/edit-table/columns/tableIn/index.scss b/src/menu/components/table/edit-table/columns/tableIn/index.scss
index 16b42cb..2f0266d 100644
--- a/src/menu/components/table/edit-table/columns/tableIn/index.scss
+++ b/src/menu/components/table/edit-table/columns/tableIn/index.scss
@@ -52,10 +52,6 @@
   .custom-table .ant-empty {
     margin: 20px 8px!important;
   }
-  .excel-custom-table {
-    position: relative;
-    top: -25px;
-  }
   .errorval {
     display: inline-block;
     width: 30px;
diff --git a/src/menu/components/table/edit-table/options.jsx b/src/menu/components/table/edit-table/options.jsx
index 7773bdf..f3e8d31 100644
--- a/src/menu/components/table/edit-table/options.jsx
+++ b/src/menu/components/table/edit-table/options.jsx
@@ -129,7 +129,18 @@
         {value: 'default', label: '澶�'},
         {value: 'middle', label: '涓�'},
         {value: 'small', label: '灏�'},
-        {value: 'mini', label: '杩蜂綘'},
+        // {value: 'mini', label: '杩蜂綘'},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'parity',
+      label: '濂囧伓寮傝壊',
+      initval: wrap.parity || 'false',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
       ]
     },
     {
@@ -193,7 +204,7 @@
       initval: wrap.permission || (!appType ? 'true' : 'false'),
       required: false,
       options: [
-        {value: 'true', label: '鍚敤'},
+        {value: 'true', label: !appType ? '缁ф壙鑿滃崟' : '鍚敤'},
         {value: 'false', label: '绂佺敤'},
       ],
       forbid: sessionStorage.getItem('editMenuType') === 'popview'
diff --git a/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx b/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
index b50848d..49c4c7f 100644
--- a/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
+++ b/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -61,6 +61,9 @@
     value: 'colspan',
     text: '鍚堝苟鍒�'
   }, {
+    value: 'extend',
+    text: '鎵╁睍鍒�'
+  }, {
     value: 'index',
     text: '搴忓彿'
   }]
@@ -197,6 +200,95 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'colUnit',
+      label: '鍗曚綅',
+      initVal: card.colUnit || 'day',
+      required: true,
+      options: [{
+        value: 'day',
+        text: '澶�'
+      }, {
+        value: 'hour',
+        text: '灏忔椂'
+      }]
+    },
+    {
+      type: 'number',
+      key: 'shift',
+      label: '鍋忕Щ閲�',
+      initVal: card.shift || 0,
+      min: -1000,
+      max: 1000,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'quota',
+      label: '鎸囨爣鏁�',
+      initVal: card.quota || 7,
+      min: 1,
+      max: 1000,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'dayFormat',
+      label: '鏍煎紡鍖�',
+      initVal: card.dayFormat || 'M/DD',
+      required: true,
+      options: [{
+        value: 'M/DD',
+        label: 'M/DD锛�4/29锛�'
+      }, {
+        value: 'M-DD',
+        label: 'M-DD锛�4-29锛�'
+      }, {
+        value: 'M鏈圖D鏃�',
+        label: 'M鏈圖D鏃ワ紙4鏈�29鏃ワ級'
+      }, {
+        value: 'M/DD week',
+        label: 'M/DD week锛�4/29 鏄熸湡涓�锛�'
+      }, {
+        value: 'M-DD week',
+        label: 'M-DD week锛�4-29 鏄熸湡涓�锛�'
+      }, {
+        value: 'M鏈圖D鏃� week',
+        label: 'M鏈圖D鏃� week锛�4鏈�29鏃� 鏄熸湡涓�锛�'
+      }]
+    },
+    {
+      type: 'select',
+      key: 'hourFormat',
+      label: '鏍煎紡鍖�',
+      initVal: card.hourFormat || 'H:00',
+      required: true,
+      options: [{
+        value: 'H:00',
+        label: 'H:00锛�15:00锛�'
+      }, {
+        value: 'H point',
+        label: 'H锛�15鐐癸級'
+      }, {
+        value: 'h:00',
+        label: 'h:00锛�3:00 pm锛�'
+      }]
+    },
+    {
+      type: 'text',
+      key: 'supField',
+      label: '涓婄骇瀛楁',
+      initVal: card.supField || '',
+      tooltip: '鏉ユ簮浜庝笂绾х粍浠剁殑瀛楁闆嗭紙涓婄骇缁勪欢涓虹┖鏃朵粠url鍙傛暟涓�夊彇锛夛紝璇ュ瓧娈靛�硷紙鐢ㄩ�楀彿鍒嗛殧锛夊彲鎺у埗鎵╁睍鍒楃殑鍒楀悕銆�',
+      required: false,
+      rules: [{
+        pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
+        message: '瀛楁鍚嶅彧鍏佽鍖呭惈鏁板瓧銆佸瓧姣嶃�佹眽瀛椾互鍙奯'
+      }]
+    },
+    {
       type: 'number',
       key: 'startTime',
       precision: 0,
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 bb4f805..afa1f03 100644
--- a/src/menu/components/table/normal-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -20,6 +20,7 @@
   custom: ['label', 'type', 'Align', 'Width', 'blacklist', 'IsSort'],
   action: ['label', 'type', 'Align', 'Width'],
   formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'],
+  extend: ['label', 'field', 'type', 'Align', 'Width', 'colUnit', 'shift', 'quota', 'supField'],
   index: ['label', 'type', 'Align', 'Width']
 }
 
@@ -89,7 +90,7 @@
 
     if (this.record.type === 'text' || this.record.type === 'number') {
       if (this.record.perspective === 'linkmenu') {
-        _options.push('linkmenu', 'linkfields', 'open')
+        _options.push('linkmenu', 'open')
       } else if (this.record.perspective === 'linkurl') {
         _options.push('linkurl', 'linkfields', 'open')
       }
@@ -97,6 +98,12 @@
       _options.push('decimal')
     } else if (this.record.type === 'custom' && this.record.IsSort === 'true') {
       _options.push('sortField')
+    } else if (this.record.type === 'extend') {
+      if (this.record.colUnit === 'day') {
+        _options.push('dayFormat')
+      } else {
+        _options.push('hourFormat')
+      }
     }
 
     if (this.record.Hide !== 'true') {
@@ -186,7 +193,7 @@
       }
     } else if (key === 'format' && value === 'percent') {
       this.props.form.setFieldsValue({postfix: '%'})
-    } else if (['perspective', 'eval', 'IsSort', 'textFormat'].includes(key)) {
+    } else if (['perspective', 'eval', 'IsSort', 'textFormat', 'colUnit'].includes(key)) {
       let _options = this.getOptions()
 
       this.setState({
@@ -211,12 +218,12 @@
       if (item.hidden || item.forbid) return
 
       if (item.type === 'text') {
-        let rules = []
+        let rules = item.rules || []
         if (item.key !== 'linkurl') {
-          rules = [{
+          rules.push({
             max: formRule.input.max,
             message: formRule.input.message
-          }]
+          })
         }
         fields.push(
           <Col span={12} key={index}>
@@ -356,7 +363,7 @@
             </Form.Item>
           </Col>
         )
-      } else if (item.type === 'cascader') { // 澶氶��
+      } else if (item.type === 'cascader') {
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.label}>
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index 6bdefb2..9286025 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/src/menu/components/table/normal-table/index.jsx
@@ -278,11 +278,11 @@
   }
 
   getWrapForms = () => {
-    const { wrap, action, columns, cols } = this.state.card
+    const { card } = this.state
 
     let _actions = []
 
-    cols.forEach(col => {
+    card.cols.forEach(col => {
       if (col.type === 'custom') {
         col.elements.forEach(cell => {
           if (cell.eleType !== 'button') return
@@ -292,7 +292,7 @@
       }
     })
 
-    return getWrapForm(wrap, _actions, columns, action)
+    return getWrapForm(card.wrap, _actions, card.columns, card.action, card.supNodes || [], card.uuid)
   }
 
   updateWrap = (res) => {
@@ -311,7 +311,21 @@
     res.borderRadius = card.wrap.borderRadius || 0
     res.resetContrl = card.wrap.resetContrl || 'init'
 
-    this.updateComponent({...card, wrap: res})
+    let _card = {...card, wrap: res}
+
+    if (res.supNodes) {
+      _card.supNodes = res.supNodes
+      _card.supNodes = _card.supNodes.map(item => {
+        item.componentId = item.nodes[item.nodes.length - 1]
+        return item
+      })
+
+      delete res.supNodes
+    } else {
+      delete _card.supNodes
+    }
+
+    this.updateComponent(_card)
   }
 
   updatecolumn = (config) => {
diff --git a/src/menu/components/table/normal-table/options.jsx b/src/menu/components/table/normal-table/options.jsx
index 416258c..22662e1 100644
--- a/src/menu/components/table/normal-table/options.jsx
+++ b/src/menu/components/table/normal-table/options.jsx
@@ -1,7 +1,9 @@
+import MenuUtils from '@/utils/utils-custom.js'
+
 /**
  * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
  */
-export default function (wrap, action = [], columns = [], toolBtns) {
+export default function (wrap, action = [], columns = [], toolBtns, supNodes, id = '') {
   let roleList = sessionStorage.getItem('sysRoles')
   let appType = sessionStorage.getItem('appType')
   let isprint = sessionStorage.getItem('MenuType') === 'billPrint'
@@ -16,6 +18,9 @@
   } else {
     roleList = []
   }
+
+  let menu = window.GLOB.customMenu
+  let modules = MenuUtils.getSupModules(menu.components, id, menu.interfaces)
 
   const wrapForm = [
     {
@@ -69,6 +74,17 @@
       ],
       controlFields: [
         {field: 'selected', values: ['radio', 'checkbox']},
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'parity',
+      label: '濂囧伓寮傝壊',
+      initval: wrap.parity || 'false',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
       ]
     },
     {
@@ -155,20 +171,6 @@
       ]
     },
     {
-      type: 'select',
-      field: 'selected',
-      label: '鏁版嵁閫変腑',
-      initval: wrap.selected || 'false',
-      tooltip: '鍒濆鍖栵細鏁版嵁鍔犺浇鏃堕�変腑棣栬鏁版嵁锛屼粎鎵ц涓�娆°�傛暟鎹姞杞斤細姣忔鏁版嵁鍔犺浇鏃跺潎閫変腑棣栬锛堝綋鎸夐挳鎵ц瀹屾垚骞惰繑鍥炰富閿�兼椂锛岄粯璁ら�変腑涓婚敭鍊煎搴旇锛夈�傞�変腑鏍囪锛氳繑鍥炴暟鎹腑瀛樺湪 selected 瀛楁锛屼笖鍊间负 true 鐨勬暟鎹閫変腑銆�',
-      required: false,
-      options: [
-        {value: 'false', label: '鏃�'},
-        {value: 'init', label: '鍒濆鍖�'},
-        {value: 'always', label: '鏁版嵁鍔犺浇'},
-        {value: 'sign', label: '閫変腑鏍囪'}
-      ],
-    },
-    {
       type: 'color',
       field: 'borderColor',
       label: '杈规棰滆壊',
@@ -190,16 +192,18 @@
       ]
     },
     {
-      type: 'number',
-      field: 'btnlimit',
-      label: '鎸夐挳闄愬埗',
-      initval: wrap.btnlimit || '',
-      tooltip: '鎸夐挳鏁伴噺闄愬埗锛岃秴鍑虹殑鎸夐挳浼氬湪鏇村涓笅鎷夋樉绀猴紝娉細鏇村涓殑鎸夐挳涓嶈缁戝畾鍙屽嚮浜嬩欢銆�',
-      min: 3,
-      max: 3000,
-      precision: 0,
+      type: 'select',
+      field: 'selected',
+      label: '鏁版嵁閫変腑',
+      initval: wrap.selected || 'false',
+      tooltip: '鍒濆鍖栵細鏁版嵁鍔犺浇鏃堕�変腑棣栬鏁版嵁锛屼粎鎵ц涓�娆°�傛暟鎹姞杞斤細姣忔鏁版嵁鍔犺浇鏃跺潎閫変腑棣栬锛堝綋鎸夐挳鎵ц瀹屾垚骞惰繑鍥炰富閿�兼椂锛岄粯璁ら�変腑涓婚敭鍊煎搴旇锛夈�傞�変腑鏍囪锛氳繑鍥炴暟鎹腑瀛樺湪 selected 瀛楁锛屼笖鍊间负 true 鐨勬暟鎹閫変腑銆�',
       required: false,
-      forbid: appType !== '' || isprint
+      options: [
+        {value: 'false', label: '鏃�'},
+        {value: 'init', label: '鍒濆鍖�'},
+        {value: 'always', label: '鏁版嵁鍔犺浇'},
+        {value: 'sign', label: '閫変腑鏍囪'}
+      ],
     },
     {
       type: 'select',
@@ -254,6 +258,18 @@
     },
     {
       type: 'number',
+      field: 'btnlimit',
+      label: '鎸夐挳闄愬埗',
+      initval: wrap.btnlimit || '',
+      tooltip: '鎸夐挳鏁伴噺闄愬埗锛岃秴鍑虹殑鎸夐挳浼氬湪鏇村涓笅鎷夋樉绀猴紝娉細鏇村涓殑鎸夐挳涓嶈缁戝畾鍙屽嚮浜嬩欢銆�',
+      min: 3,
+      max: 3000,
+      precision: 0,
+      required: false,
+      forbid: appType !== '' || isprint
+    },
+    {
+      type: 'number',
       field: 'maxPageSize',
       label: '姣忛〉鏈�澶ф暟',
       initval: wrap.maxPageSize || '',
@@ -288,6 +304,22 @@
         {value: 'false', label: '蹇界暐'},
       ],
       forbid: isprint
+    },
+    {
+      type: 'radio',
+      field: 'supType',
+      label: '涓婄骇绫诲瀷',
+      initval: wrap.supType || 'single',
+      tooltip: '涓婄骇缁勪欢涓哄崟涓�缁勪欢鎴栧涓粍浠躲��',
+      required: false,
+      forbid: appType === 'mob' || isprint,
+      options: [
+        {value: 'single', label: '鍗曠粍浠�'},
+        {value: 'multi', label: '澶氱粍浠�'},
+      ],
+      controlFields: [
+        {field: 'supNodes', values: ['multi']},
+      ]
     },
     {
       type: 'radio',
@@ -335,6 +367,36 @@
       options: roleList,
       forbid: !!appType || isprint
     },
+    {
+      type: 'table',
+      field: 'supNodes',
+      label: '涓婄骇缁勪欢',
+      initval: supNodes,
+      required: true,
+      forbid: appType === 'mob' || isprint,
+      span: 24,
+      actions: ['edit', 'del', 'add', 'move'],
+      columns: [
+        {
+          title: '搴忓彿',
+          dataIndex: '$index',
+          editable: false,
+          required: false,
+          width: '20%'
+        },
+        {
+          title: '缁勪欢',
+          dataIndex: 'nodes',
+          inputType: 'cascader',
+          editable: true,
+          required: true,
+          extends: [{key: 'label', value: 'label'}],
+          width: '50%',
+          render: (text, record) => record.label,
+          options: modules
+        }
+      ]
+    }
   ]
 
   return wrapForm
diff --git a/src/menu/components/timeline/normal-timeline/index.scss b/src/menu/components/timeline/normal-timeline/index.scss
index 2f88860..51b98ae 100644
--- a/src/menu/components/timeline/normal-timeline/index.scss
+++ b/src/menu/components/timeline/normal-timeline/index.scss
@@ -23,7 +23,7 @@
   }
 
   .card-item {
-    overflow: hidden;
+    // overflow: hidden;
     position: relative;
     background-color: #ffffff;
     background-position: center center;
diff --git a/src/menu/components/tree/antd-tree/index.jsx b/src/menu/components/tree/antd-tree/index.jsx
index b093ad7..515d1d0 100644
--- a/src/menu/components/tree/antd-tree/index.jsx
+++ b/src/menu/components/tree/antd-tree/index.jsx
@@ -15,6 +15,7 @@
 
 const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const PasteComponent = asyncIconComponent(() => import('@/components/paste'))
 const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
@@ -88,6 +89,7 @@
     card.name = card.wrap.name
 
     card.$c_ds = true
+    card.$c_ac = true
       
     card.errors = checkComponent(card)
 
@@ -160,6 +162,20 @@
     MKEmitter.emit('addButton', card.uuid, newcard)
   }
 
+  pasteComponent = (res, resolve) => {
+    if (res.style) {
+      delete res.style.width
+      delete res.style.float
+    }
+
+    res.Ot = res.Ot === 'requiredSgl' ? 'requiredSgl' : 'notRequired'
+
+    resolve({status: true})
+
+    res.uuid = Utils.getuuid()
+    this.addButton(res)
+  }
+
   setSubConfig = (item) => {
     const { card, appType } = this.state
     let btn = fromJS(item).toJS()
@@ -180,9 +196,9 @@
   }
 
   getWrapForms = () => {
-    const { wrap, columns } = this.state.card
+    const { wrap, columns, action } = this.state.card
 
-    return getWrapForm(wrap, columns)
+    return getWrapForm(wrap, columns, action.findIndex(item => item.Ot === 'requiredSgl') > -1)
   }
 
   updateWrap = (res) => {
@@ -205,6 +221,9 @@
   render() {
     const { card } = this.state
     let _style = resetStyle(card.style)
+    if (card.wrap.lineHeight) {
+      _style['--mk-tree-line-height'] = card.wrap.lineHeight + 'px'
+    }
 
     return (
       <div className="menu-tree-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
@@ -217,6 +236,7 @@
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="tree" card={card}/>
+            <PasteComponent options={['action']} updateConfig={this.pasteComponent} />
             <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
             <ClockComponent config={card} updateConfig={this.updateComponent}/>
             <DeleteOutlined className="close" title="鍒犻櫎缁勪欢" onClick={() => this.props.deletecomponent(card.uuid)} />
diff --git a/src/menu/components/tree/antd-tree/index.scss b/src/menu/components/tree/antd-tree/index.scss
index 20df956..37f6cfb 100644
--- a/src/menu/components/tree/antd-tree/index.scss
+++ b/src/menu/components/tree/antd-tree/index.scss
@@ -7,6 +7,7 @@
   background-size: cover;
   min-height: 100px;
   overflow-y: auto;
+  --mk-tree-line-height: 24px;
 
   .anticon-tool {
     position: absolute;
@@ -28,6 +29,15 @@
   .model-menu-action-list:not(.length0) {
     margin: 10px 0px;
   }
+  .model-menu-action-list {
+    .ant-btn {
+      border-width: 0px;
+    }
+  }
+  .ant-tree li .ant-tree-node-content-wrapper, .ant-tree li span.ant-tree-switcher, .ant-tree li span.ant-tree-iconEle {
+    height: var(--mk-tree-line-height);
+    line-height: var(--mk-tree-line-height);
+  }
 }
 .menu-tree-box::after {
   display: block;
diff --git a/src/menu/components/tree/antd-tree/options.jsx b/src/menu/components/tree/antd-tree/options.jsx
index d8b6a7e..54c8c0d 100644
--- a/src/menu/components/tree/antd-tree/options.jsx
+++ b/src/menu/components/tree/antd-tree/options.jsx
@@ -1,7 +1,7 @@
 /**
  * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
  */
-export default function (wrap, columns = []) {
+export default function (wrap, columns = [], hasLineAction) {
   let roleList = sessionStorage.getItem('sysRoles')
   let appType = sessionStorage.getItem('appType')
   let ispop = sessionStorage.getItem('editMenuType') === 'popview'
@@ -79,6 +79,16 @@
       required: true
     },
     {
+      type: 'number',
+      field: 'lineHeight',
+      label: '琛岄珮',
+      initval: wrap.lineHeight || 24,
+      min: 24,
+      max: 200,
+      precision: 0,
+      required: true
+    },
+    {
       type: 'radio',
       field: 'showIcon',
       label: '鍥炬爣',
@@ -124,6 +134,19 @@
     },
     {
       type: 'radio',
+      field: 'actShow',
+      label: '鎸夐挳鏄剧ず',
+      initval: wrap.actShow || 'dropdown',
+      tooltip: '閫夋嫨鍗曡鎸夐挳鐨勬樉绀烘柟寮忋��',
+      required: false,
+      forbid: !hasLineAction,
+      options: [
+        {value: 'dropdown', label: '涓嬫媺'},
+        {value: 'line', label: '琛屽唴'},
+      ]
+    },
+    {
+      type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
       initval: wrap.permission || 'false',
diff --git a/src/menu/datasource/verifycard/customscript/index.jsx b/src/menu/datasource/verifycard/customscript/index.jsx
index 489c1f6..c44da19 100644
--- a/src/menu/datasource/verifycard/customscript/index.jsx
+++ b/src/menu/datasource/verifycard/customscript/index.jsx
@@ -226,7 +226,7 @@
           </Col> : null}
           <Col span={18}>
             <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0}}>
-              ErrorCode, retmsg
+              errorcode, retmsg
               <span style={{marginLeft: 25}}>
                 鎴愬姛锛�
                 <span className="error-val" onClick={() => {this.showError('S')}}> S </span>銆�
diff --git a/src/menu/datasource/verifycard/index.jsx b/src/menu/datasource/verifycard/index.jsx
index ceabb28..b31ecfd 100644
--- a/src/menu/datasource/verifycard/index.jsx
+++ b/src/menu/datasource/verifycard/index.jsx
@@ -48,6 +48,7 @@
     systemScripts: [],
     median: {},
     visible: false,
+    editLineId: '',
     pvisible: false,
     reload: false,
     script: null,
@@ -677,7 +678,8 @@
       if (config.subtype === 'dualdatacard') {
         _columns = [...columns, ...subColumns]
       }
-      let r = SettingUtils.getDebugSql(setting, _scripts, _columns, searches, config.type)
+
+      let r = SettingUtils.getDebugSql(setting, _scripts, _columns, searches, config.subtype)
 
       let _debugId = md5(r.sql)
       
@@ -809,7 +811,9 @@
       return
     }
 
+    let editLineId = ''
     if (script) {
+      editLineId = script.uuid
       _scripts = _scripts.map(item => {
         if (script.uuid === item.uuid) {
           item.sql = scriptValue
@@ -824,10 +828,11 @@
         status: 'true'
       }
 
+      editLineId = _script.uuid
       _scripts.push(_script)
     }
 
-    this.setState({loading: true})
+    this.setState({loading: true, editLineId})
 
     this.sqlverify(() => {this.setState({scripts: _scripts, script: null, scriptValue: '', loading: false})}, () => {this.setState({loading: false})}, 'script', _scripts)
   }
@@ -954,7 +959,8 @@
   }
 
   copyColumns = () => {
-    const { columns } = this.state
+    const { columns, setting } = this.state
+
     let m = []
     let n = []
     let s = []
@@ -978,8 +984,29 @@
     }
 
     let oInput = document.createElement('input')
-    oInput.value = `/*${m.join(',')}*/
-      ${n.join(',')}`
+    oInput.value = `create table #${setting.tableName || 'tb'}
+    (${m.join(',')},sort_id INT IDENTITY(1,1))
+    insert into #${setting.tableName || 'tb'}
+    (${n.join(',')})
+    select ${n.join(',')}
+    from ${setting.dataresource ? `(${setting.dataresource.replace(/\n/g, ' ')}) tb` : setting.tableName || 'tb'}
+    order by @orderBy@
+    
+    declare @mk_total int
+    set @mk_total = 0
+      
+    select @mk_total = count(1) from #${setting.tableName || 'tb'}
+      declare @pageIndex_top int 
+      set @pageIndex_top=(@pageIndex@-1)*@pageSize@ 
+      
+      if @mk_total > @pageIndex@*@pageSize@
+        delete #${setting.tableName || 'tb'} where sort_id > @pageIndex@*@pageSize@ 
+      
+      if @pageIndex_top > 0
+        delete #${setting.tableName || 'tb'} where sort_id <= @pageIndex_top
+
+    drop table #${setting.tableName || 'tb'}`
+
     document.body.appendChild(oInput)
     oInput.select()
     document.execCommand('Copy')
@@ -1106,7 +1133,7 @@
 
   render() {
     const { config } = this.props
-    const { columns, subColumns, median, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue, searchKey } = this.state
+    const { columns, subColumns, median, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue, searchKey, editLineId } = this.state
 
     return (
       <div className="model-data-source-wrap">
@@ -1130,7 +1157,7 @@
               wrappedComponentRef={(inst) => this.settingForm = inst}
             /> : null}
           </TabPane>
-          {config.subtype !== 'basetable' ? <TabPane tab={
+          {!['basetable', 'invoice', 'invTable'].includes(config.subtype) ? <TabPane tab={
             <span>
               瀛楁闆�
               {columns.length ? <span className="count-tip">{columns.length}</span> : null}
@@ -1186,7 +1213,7 @@
                 })
                 return
               }
-              this.setState({visible: true, script: null, scriptValue: ''})
+              this.setState({visible: true, script: null, scriptValue: '', editLineId: ''})
             }}/> : null}
             <CustomScriptsForm
               type={config.type}
@@ -1236,8 +1263,14 @@
                   </div>
                 )
               } else {
+                let sign = ''
+                if (script && script.uuid === item.uuid) {
+                  sign = 'active'
+                } else if (editLineId === item.uuid) {
+                  sign = 'edited'
+                }
                 return (
-                  <div className={'script-item ' + (script && script.uuid === item.uuid ? 'active' : '') } key={item.uuid}>
+                  <div className={'script-item ' + sign} key={item.uuid}>
                     <div style={{cursor: 'pointer'}} onClick={() => {
                       this.setState({script: item, scriptValue: item.sql})
                     }}>
diff --git a/src/menu/datasource/verifycard/index.scss b/src/menu/datasource/verifycard/index.scss
index e791cda..308bfb9 100644
--- a/src/menu/datasource/verifycard/index.scss
+++ b/src/menu/datasource/verifycard/index.scss
@@ -195,6 +195,11 @@
         .script-item.active {
           background-color: #bae7ff;
         }
+        .script-item.edited {
+          .ant-typography {
+            color: #1890ff;
+          }
+        }
         .ant-typography {
           margin-bottom: 5px;
         }
diff --git a/src/menu/datasource/verifycard/settingform/index.jsx b/src/menu/datasource/verifycard/settingform/index.jsx
index d52d420..560e5d9 100644
--- a/src/menu/datasource/verifycard/settingform/index.jsx
+++ b/src/menu/datasource/verifycard/settingform/index.jsx
@@ -375,7 +375,7 @@
               </Form.Item>
             </Col> : null}
             {setting.interType === 'system' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
-              {window.GLOB.process ? <span className="process-btn" onClick={this.addProcess}>宸ヤ綔娴�</span> : null}
+              {window.GLOB.process && !['invoice', 'invTable'].includes(config.subtype) ? <span className="process-btn" onClick={this.addProcess}>宸ヤ綔娴�</span> : null}
               <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 2 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 22 }} } label={
                 <Tooltip placement="topLeft" title={`浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� ''銆� @$ -> */ 鎴� ''銆俙}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -409,7 +409,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            <Col span={8}>
+            {!['invTable'].includes(config.subtype) ? <Col span={8}>
               <Form.Item label="涓婚敭">
                 {getFieldDecorator('primaryKey', {
                   initialValue: setting.primaryKey || ''
@@ -423,7 +423,7 @@
                   </Select>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             {/* 鏁扮粍鏁版嵁锛岄渶璁剧疆鎺掑簭瑙勫垯 */}
             {config.format === 'array' ? <Col span={8}>
               <Form.Item label={
@@ -454,7 +454,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            {!['navbar', 'balcony', 'menubar'].includes(config.type) && (!config.wrap || config.wrap.supType !== 'multi') && MenuType !== 'billPrint' ? <Col span={8}>
+            {!['balcony', 'menubar', 'commonbar', 'tabbar', 'invTable'].includes(config.subtype) && (!config.wrap || config.wrap.supType !== 'multi') && MenuType !== 'billPrint' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'璇ョ粍浠跺鏋滃彈鍏朵粬缁勪欢鎺у埗锛岃閫夐」鐩稿簲鐨勭粍浠讹紝娌℃湁鏃堕�夆�滄棤鈥濄��'}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -516,7 +516,7 @@
               </Form.Item>
             </Col> : null}
             {/* 1銆佷笉鍒嗛〉涓斾笉瀛樺湪涓婄骇妯″潡 */}
-            {!['navbar', 'interface', 'calendar'].includes(config.type) && !['editable', 'basetable', 'dualdatacard'].includes(config.subtype) && (!config.pageable || (config.pageable && setting.laypage === 'false')) && (setting.supModule.length === 0 || setting.supModule[0] === 'empty') && setting.interType === 'system' && setting.onload !== 'false' ? <Col span={8}>
+            {!['navbar', 'interface', 'calendar'].includes(config.type) && !['editable', 'basetable', 'dualdatacard', 'invoice', 'invTable'].includes(config.subtype) && (!config.pageable || (config.pageable && setting.laypage === 'false')) && (setting.supModule.length === 0 || setting.supModule[0] === 'empty') && setting.interType === 'system' && setting.onload !== 'false' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'鍒濆鍖栧姞杞芥椂锛屾槸鍚︿笌鍏朵粬缁勪欢涓�鍚屽姞杞芥暟鎹紝娉細濡傝彍鍗曟湭浣跨敤鍚庣缂撳瓨锛屽垯鏌ヨ璇彞澶т簬8000瀛楃鏃舵棤鏁堛��'}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -533,7 +533,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {!['navbar', 'balcony', 'menubar'].includes(config.type) && !['basetable'].includes(config.subtype) ? <Col span={8}>
+            {!['navbar', 'balcony', 'menubar'].includes(config.type) && !['basetable', 'invoice', 'invTable'].includes(config.subtype) ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={config.type === 'interface' ? '鍗曠嫭鎼滅储缁勪欢鍙綔涓哄叕鍏辨暟鎹簮鐨勬悳绱㈡潯浠躲��' : '浼樺厛浣跨敤鍚岀骇鐨勬悳绱㈡潯浠剁粍浠讹紝鍚岀骇鎼滅储涓嶅瓨鍦ㄦ椂锛屼緷娆″悜涓婇�夊彇锛屼笌褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵竴鍚岀敤浣滄暟鎹繃婊わ紙褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵紭鍏堬級銆�'}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -683,8 +683,7 @@
           wrapClassName="mk-flow-type"
           visible={visible}
           width={400}
-          maskClosable={false}
-          closable={false}
+          onCancel={() => this.setState({visible: false})}
           footer={[
             <Button key="cancel" className="mk-green" onClick={() => this.execAddProcess('flowstart')}>鍙戣捣</Button>,
             <Button key="confirm" className="mk-primary" onClick={() => this.execAddProcess('flowcheck')}>瀹℃壒</Button>
diff --git a/src/menu/datasource/verifycard/utils.jsx b/src/menu/datasource/verifycard/utils.jsx
index b443500..291ef35 100644
--- a/src/menu/datasource/verifycard/utils.jsx
+++ b/src/menu/datasource/verifycard/utils.jsx
@@ -75,7 +75,7 @@
       {reg: /@sum\$|\$sum@/ig, value: ''},
     ]
 
-    if (window.GLOB.process) {
+    if (window.GLOB.process && type !== 'invoice') {
       regs.push({reg: /@works_flow_code@/ig, value: `'${getuuid()}'`})
     }
 
@@ -101,7 +101,7 @@
       `
     }
 
-    if (window.GLOB.urlFields) {
+    if (window.GLOB.urlFields && type !== 'invoice') {
       window.GLOB.urlFields.forEach(field => {
         let reg = new RegExp('@' + field + '@', 'ig')
         _dataresource = _dataresource.replace(reg, `'0'`)
diff --git a/src/menu/debug/index.jsx b/src/menu/debug/index.jsx
index 9b48dde..93bcf14 100644
--- a/src/menu/debug/index.jsx
+++ b/src/menu/debug/index.jsx
@@ -770,7 +770,7 @@
     }
     _sql = `Declare @tbid nvarchar(50),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@BillCode nvarchar(50),@BVoucher nvarchar(50),@FIBVoucherDate nvarchar(50), @FiYear nvarchar(50),@ModularDetailCode nvarchar(50), @UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100),@mk_deleted int,@bid nvarchar(50)${_declarefields}
       `
-  
+
     let userName = 'User_Name'
     let fullName = 'Full_Name'
     let RoleID = 'role_id'
@@ -1281,15 +1281,46 @@
       let detailId = '0'
   
       if (verify.flowSql === 'true') {
-        _sql += `
-        /* 宸ヤ綔娴侀粯璁ql */
-        insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
-        select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
-        insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
-        select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
-        insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
-        select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
-        `
+        if (verify.flowType === 'start') {
+          _sql += `
+            /* 宸ヤ綔娴侀粯璁ql */
+            insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
+            select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
+            insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
+            select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+            insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+            select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
+          `
+        } else {
+          _sql += `
+            /* 宸ヤ綔娴侀粯璁ql */
+            update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+            where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+            insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
+            select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+            
+            update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+            where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+
+            if @check_userids@ != ''
+            begin
+                  insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+                  insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@check_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+            end
+            if @notice_userids@ != ''
+            begin
+                  update n
+                  set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+                  from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
+                  inner join (select ID from dbo.SplitComma(@notice_userids@)) s
+                  on n.userid = s.id
+                  insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@notice_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@notice_userids@)
+            end
+          `
+        }
       }
   
       _sql = _sql.replace(/@start_type@/ig, `'寮�濮�'`)
@@ -1494,7 +1525,7 @@
       `
     }
 
-    sql = `create table #${sheet} (${declarefields.join(',')},jskey nvarchar(50),BID nvarchar(50) )
+    sql = `create table #${sheet} (${declarefields.join(',')},jskey nvarchar(50),BID nvarchar(50))
       Declare @UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100),@ErrorCode nvarchar(50),@retmsg nvarchar(4000),@tbid Nvarchar(512)
       
       Select  @ErrorCode='', @retmsg='', @UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}'
@@ -1709,11 +1740,10 @@
     let item = {setting: {}, columns: [], search: []}
 
     btn.verify.columns.forEach(col => {
-      if (col.Column && col.Column !== '$Index') {
-        item.columns.push({
-          field: col.Column
-        })
-      }
+      if (col.output === 'false' || !col.Column || col.Column === '$Index') return
+      item.columns.push({
+        field: col.Column
+      })
     })
 
     if (btn.verify.useSearch !== 'false') {
diff --git a/src/menu/header/index.jsx b/src/menu/header/index.jsx
index 9617900..f7a1c6d 100644
--- a/src/menu/header/index.jsx
+++ b/src/menu/header/index.jsx
@@ -7,15 +7,17 @@
 class MenuHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   render () {
     const { menuName } = this.props
+    const { logo } = this.state
 
     return (
       <header className="menu-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="menu-name">{menuName}</div>
         <div className="header-setting">
           <img src={this.state.avatar} alt=""/>
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index b56942a..47269bf 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -30,6 +30,7 @@
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 const Voucher = asyncComponent(() => import('@/menu/components/module/voucher'))
 const Account = asyncComponent(() => import('@/menu/components/module/account'))
+const Invoice = asyncComponent(() => import('@/menu/components/module/invoice'))
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 const AntvX6 = asyncComponent(() => import('@/menu/components/chart/antv-X6'))
@@ -135,6 +136,8 @@
       return (<Voucher card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'module' && card.subtype === 'account') {
       return (<Account card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'module' && card.subtype === 'invoice') {
+      return (<Invoice card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/modalconfig/index.jsx b/src/menu/modalconfig/index.jsx
index 8bb149f..6388269 100644
--- a/src/menu/modalconfig/index.jsx
+++ b/src/menu/modalconfig/index.jsx
@@ -135,7 +135,7 @@
         })
       }
 
-      if (item.type === 'switch' || item.type === 'check') {
+      if (['switch', 'check', 'popSelect'].includes(item.type)) {
         _linksupFields.push({
           field: item.field,
           label: item.label
diff --git a/src/menu/modalconfig/index.scss b/src/menu/modalconfig/index.scss
index d73bd57..9449b04 100644
--- a/src/menu/modalconfig/index.scss
+++ b/src/menu/modalconfig/index.scss
@@ -76,8 +76,16 @@
     height: 100%;
     overflow-y: hidden;
     background: #ffffff;
-    .ant-card-head {
-      min-height: 44px;
+    .ant-card {
+      padding-top: 45px;
+      .ant-card-head {
+        min-height: 44px;
+        position: fixed;
+        width: calc(100vw - 235px);
+        top: 48px;
+        z-index: 12;
+        background: #ffffff;
+      }
     }
     .ant-card-head-title {
       padding: 5px 0;
diff --git a/src/menu/modulecell/index.jsx b/src/menu/modulecell/index.jsx
index 4bc5e54..f587103 100644
--- a/src/menu/modulecell/index.jsx
+++ b/src/menu/modulecell/index.jsx
@@ -22,6 +22,7 @@
           { value: 'qrcode', text: '浜岀淮鐮�', type: 'action', class: 'element', $init: true},
           { value: 'currentDate', text: '褰撳墠鏃堕棿', type: 'action', class: 'element', $init: true},
           { value: 'formula', text: '鍏紡', type: 'action', class: 'element', $init: true},
+          { value: 'tag', text: '鏍囩', type: 'action', class: 'element', $init: true},
           { value: 'color', text: '棰滆壊', type: 'action', class: 'element', $init: true},
           { value: 'sequence', text: '搴忓彿', type: 'action', class: 'element', $init: true }
         ]
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index 1607a5a..9013a15 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -32,6 +32,7 @@
 import Voucher from '@/assets/mobimg/voucher.png'
 import Account from '@/assets/mobimg/account.png'
 import canlendar from '@/assets/mobimg/canlendar.png'
+import Invoice from '@/assets/img/invoice.png'
 
 // 缁勪欢閰嶇疆淇℃伅
 export const menuOptions = [
@@ -72,4 +73,5 @@
   { type: 'menu', url: Iframe, component: 'iframe', subtype: 'iframe', title: 'iframe', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Account, component: 'module', subtype: 'account', title: '璐﹀', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Voucher, component: 'module', subtype: 'voucher', title: '鍑瘉', width: 24, forbid: ['billPrint'] },
+  { type: 'menu', url: Invoice, component: 'module', subtype: 'invoice', title: '鍙戠エ', width: 24, forbid: ['billPrint'] },
 ]
diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx
index 89f5ca9..789d1e5 100644
--- a/src/menu/stylecontroller/index.jsx
+++ b/src/menu/stylecontroller/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import { is, fromJS } from 'immutable'
-import { Collapse, Form, Col, InputNumber, Input, Select, Radio, Drawer, Button, message } from 'antd'
+import { Collapse, Form, Col, InputNumber, Input, Select, Radio, Drawer, Button, message, Checkbox } from 'antd'
 import {
   ColumnHeightOutlined,
   FontSizeOutlined,
@@ -53,7 +53,8 @@
     backgroundImage: '',
     options: [],
     borposition: 'outer',
-    type: ''
+    type: '',
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   callback = null
@@ -130,30 +131,37 @@
   onCloseDrawer = () => {
     let card = fromJS(this.state.card).toJS()
 
-    let check = false
-    if (card.borderWidth === '0px') {
+    if (card.borderWidth === '0px' || !card.borderWidth) {
       delete card.borderWidth
       delete card.borderColor
-      check = true
-    } else if (card.borderLeftWidth === '0px') {
-      delete card.borderLeftWidth
-      delete card.borderLeftColor
-      check = true
-    } else if (card.borderRightWidth === '0px') {
-      delete card.borderRightWidth
-      delete card.borderRightColor
-      check = true
-    } else if (card.borderTopWidth === '0px') {
-      delete card.borderTopWidth
-      delete card.borderTopColor
-      check = true
-    } else if (card.borderBottomWidth === '0px') {
-      delete card.borderBottomWidth
-      delete card.borderBottomColor
-      check = true
     }
 
-    if (check) {
+    if (card.borderLeftWidth === '0px' || !card.borderLeftWidth) {
+      delete card.borderLeftWidth
+      delete card.borderLeftColor
+    }
+    if (card.borderRightWidth === '0px' || !card.borderRightWidth) {
+      delete card.borderRightWidth
+      delete card.borderRightColor
+    }
+    if (card.borderTopWidth === '0px' || !card.borderTopWidth) {
+      delete card.borderTopWidth
+      delete card.borderTopColor
+    }
+    if (card.borderBottomWidth === '0px' || !card.borderBottomWidth) {
+      delete card.borderBottomWidth
+      delete card.borderBottomColor
+    }
+
+    if (/0px 0px 0px | transparent/.test(card.boxShadow)) {
+      delete card.hShadow
+      delete card.vShadow
+      delete card.shadowBlur
+      delete card.shadowColor
+      delete card.boxShadow
+    }
+
+    if (!is(fromJS(this.state.card), fromJS(card))) {
       this.callback && this.callback(card)
     }
 
@@ -285,7 +293,7 @@
   changeShadowColor = (val) => {
     const { card } = this.state
 
-    let boxShadow = `${card.hShadow || '0px'} ${card.vShadow || '0px'} ${card.shadowBlur || '0px'} ${val}`
+    let boxShadow = `${card.hShadow || '0px'} ${card.vShadow || '0px'} ${card.shadowBlur || '0px'} ${val || 'transparent'}`
 
     this.updateStyle({shadowColor: val, boxShadow})
   }
@@ -561,7 +569,7 @@
   }
 
   render () {
-    const { card, options, backgroundImage, borposition, fonts, type } = this.state
+    const { card, options, backgroundImage, borposition, fonts, type, logo } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -577,7 +585,7 @@
       <Drawer
         title={
           <div className="header-logo">
-            <img src={MainLogo} alt=""/>
+            <img src={logo} alt=""/>
           </div>
         }
         placement="left"
@@ -716,6 +724,25 @@
                       <Radio.Button value="line-through"><StrikethroughOutlined title="涓垝绾�"/></Radio.Button>
                       <Radio.Button value="overline" style={{textDecoration: 'overline'}}><span title="涓婂垝绾�">O</span></Radio.Button>
                     </Radio.Group>
+                  </Form.Item>
+                </Col> : null}
+                {options.includes('fontFamily') ? <Col span={24}>
+                  <Form.Item
+                    colon={false}
+                    label=" "
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <Checkbox.Group options={[
+                      { label: '寰蒋闆呴粦', value: 'Microsoft YaHei' },
+                      { label: '瀹嬩綋', value: 'Simsun' },
+                      { label: '榛戜綋', value: 'Simhei' },
+                      { label: '浠垮畫', value: 'FangSong' },
+                      { label: '妤蜂綋', value: 'KaiTi' },
+                      // { label: 'Helvetica', value: 'Helvetica' },
+                      // { label: 'Arial', value: 'Arial' },
+                      // { label: 'Verdana', value: 'Verdana' },
+                      // { label: 'Georgia', value: 'Georgia' },
+                    ]} defaultValue={card.fontFamily} onChange={(val) => this.changeNormalStyle(val, 'fontFamily')} />
                   </Form.Item>
                 </Col> : null}
               </Panel> : null}
@@ -865,11 +892,11 @@
                     label={<ColumnWidthOutlined title="杈规瀹藉害"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    {borposition === 'outer' ? <StyleInput defaultValue={card.borderWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'left' ? <StyleInput defaultValue={card.borderLeftWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'right' ? <StyleInput defaultValue={card.borderRightWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'top' ? <StyleInput defaultValue={card.borderTopWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
-                    {borposition === 'bottom' ? <StyleInput defaultValue={card.borderBottomWidth || '0px'} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'outer' ? <StyleInput defaultValue={card.borderWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'left' ? <StyleInput defaultValue={card.borderLeftWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'right' ? <StyleInput defaultValue={card.borderRightWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'top' ? <StyleInput defaultValue={card.borderTopWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
+                    {borposition === 'bottom' ? <StyleInput defaultValue={card.borderBottomWidth || ''} options={['px']} onChange={this.changeBorderWidth}/> : null}
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -878,11 +905,11 @@
                     label={<BgColorsOutlined title="杈规棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    {borposition === 'outer' ? <ColorSketch value={card.borderColor || ''} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'left' ? <ColorSketch value={card.borderLeftColor || ''} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'right' ? <ColorSketch value={card.borderRightColor || ''} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'top' ? <ColorSketch value={card.borderTopColor || ''} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'bottom' ? <ColorSketch value={card.borderBottomColor || ''} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'outer' ? <ColorSketch allowClear={true} value={card.borderColor || ''} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'left' ? <ColorSketch allowClear={true} value={card.borderLeftColor || ''} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'right' ? <ColorSketch allowClear={true} value={card.borderRightColor || ''} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'top' ? <ColorSketch allowClear={true} value={card.borderTopColor || ''} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'bottom' ? <ColorSketch allowClear={true} value={card.borderBottomColor || ''} onChange={this.changeBorderColor} /> : null}
                   </Form.Item>
                   <Form.Item
                     colon={false}
@@ -909,7 +936,7 @@
                     label={<BgColorsOutlined title="闃村奖棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch value={card.shadowColor || ''} onChange={this.changeShadowColor} />
+                    <ColorSketch allowClear={true} value={card.shadowColor || ''} onChange={this.changeShadowColor} />
                   </Form.Item>
                   <Form.Item
                     colon={false}
diff --git a/src/menu/stylecontroller/index.scss b/src/menu/stylecontroller/index.scss
index 8940758..df5ab73 100644
--- a/src/menu/stylecontroller/index.scss
+++ b/src/menu/stylecontroller/index.scss
@@ -127,6 +127,22 @@
                   }
                 }
               }
+              .ant-checkbox-group {
+                margin-top: 10px;
+                .ant-checkbox-wrapper {
+                  color: rgba(255, 255, 255, 0.85);
+                  margin-right: 4px;
+                  margin-bottom: 2px;
+                  .ant-checkbox + span {
+                    padding-left: 6px;
+                  }
+                  .ant-checkbox:not(.ant-checkbox-checked) {
+                    .ant-checkbox-inner {
+                      background-color: rgba(255, 255, 255, 0.85);
+                    }
+                  }
+                }
+              }
             }
           }
         }
diff --git a/src/mob/components/topbar/normal-navbar/options.jsx b/src/mob/components/topbar/normal-navbar/options.jsx
index 33f0c7d..43cc169 100644
--- a/src/mob/components/topbar/normal-navbar/options.jsx
+++ b/src/mob/components/topbar/normal-navbar/options.jsx
@@ -184,7 +184,7 @@
       field: 'prefix',
       label: '鍓嶇紑',
       initval: wrap.prefix || '',
-      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid寮�澶淬��',
+      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid锛�:鎴�,锛夊紑澶达紝mkbid锛�:鎴�,锛夎烦杞悗灏嗚鍘婚櫎銆備緥濡傦細mkbid:123456 璺宠浆鍚庨〉闈ID涓� 123456銆�',
       required: false
     },
     {
diff --git a/src/mob/header/index.jsx b/src/mob/header/index.jsx
index 38c5863..6d61f1f 100644
--- a/src/mob/header/index.jsx
+++ b/src/mob/header/index.jsx
@@ -7,13 +7,16 @@
 class MobHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   render () {
+    const { logo } = this.state
+
     return (
       <header className="mob-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="header-user">
           <img src={this.state.avatar} alt=""/>
           <span>
diff --git a/src/tabviews/basetable/index.jsx b/src/tabviews/basetable/index.jsx
index 83f496c..56d1f89 100644
--- a/src/tabviews/basetable/index.jsx
+++ b/src/tabviews/basetable/index.jsx
@@ -213,18 +213,6 @@
       config.components.forEach(component => {
         if (component.type === 'tabs') return
 
-        if (param.$searchkey) {
-          component.search = component.search.map(item => {
-            if (['text', 'select', 'link', 'checkcard'].includes(item.type) && param.$searchkey === item.field) {
-              item.initval = param.$searchval
-            }
-  
-            return item
-          })
-
-          component.$searches = Utils.initMainSearch(component.search)
-        }
-
         if (component.$searches.length) {
           component.$main = true
           
@@ -358,6 +346,14 @@
       // 鎼滅储鏉′欢鍒濆鍖�
       Utils.initSearchVal(item)
 
+      if (urlparam.$searchkey) {
+        item.search.forEach(cell => {
+          if (urlparam.$searchkey === cell.field.toLowerCase() && ['text', 'select', 'link', 'checkcard'].includes(cell.type)) {
+            cell.initval = urlparam.$searchval
+          }
+        })
+      }
+
       item.$searches = Utils.initMainSearch(item.search)
 
       let statFields = []
@@ -397,7 +393,7 @@
                   cell = this.getPrinter(cell, item.uuid)
                 }
 
-                return skip || permAction[cell.uuid]
+                return skip || permAction[cell.uuid] || cell.permission === 'false'
               } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
                 if (!cell.height) {
                   cell.innerHeight = 'auto'
@@ -410,8 +406,19 @@
                 }
               }
 
+              if (cell.linkmenu && cell.linkmenu.length > 0) {
+                let menu_id = cell.linkmenu.pop()
+                cell.linkThdMenu = window.GLOB.mkThdMenus.get(menu_id) || ''
+                if (!cell.linkThdMenu) {
+                  cell.link = ''
+                }
+              }
+
               if (cell.marks && cell.marks.length === 0) {
                 cell.marks = null
+              }
+              if (cell.anchors && cell.anchors.length === 0) {
+                cell.anchors = null
               }
 
               return true
@@ -453,7 +460,7 @@
             cell = this.getPrinter(cell, item.uuid)
           }
 
-          return skip || permAction[cell.uuid]
+          return skip || permAction[cell.uuid] || cell.permission === 'false'
         })
       }
       
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index 78fd480..41afdfd 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -209,7 +209,7 @@
 
       // 瀛楁閫忚鍙婂繀濉爣蹇�
       config.search = config.search.map(item => {
-        if (['text', 'select', 'link', 'checkcard'].includes(item.type) && param && param.$searchkey === item.field) {
+        if (['text', 'select', 'link', 'checkcard'].includes(item.type) && param && param.$searchkey === item.field.toLowerCase()) {
           item.initval = param.$searchval
         }
         return item
@@ -295,6 +295,7 @@
 
       let _actions = []      // 宸ュ叿鏍忔寜閽�
       let _operations = []   // 鎿嶄綔鍒楁寜閽紙瀛樺湪鏃讹級
+      let colors = { primary: '#1890ff', yellow: '#c49f47', orange: 'orange', danger: '#ff4d4f', green: '#26C281', dgreen: '#32c5d2', purple: '#8E44AD', cyan: '#13c2c2', gray: '#E7E7EF', default: 'rgba(0, 0, 0, 0.65)' }
 
       config.action.forEach(item => {
         item.logLabel = MenuName + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
@@ -345,11 +346,26 @@
             item.controlVals = [(item.controlVal || '')]
           }
         }
-        
+
+        item.show = 'button'
+
+        let _c = item.class ? item.class.replace('border-', '') : ''
+        let color = colors[_c] || '#1890ff'
+
         if (item.position === 'toolbar') {
           item.$toolbtn = true
+
+          if (item.class === 'default') {
+            item.style = {color: 'rgba(0, 0, 0, 0.65)', backgroundColor: '#fff', borderColor: '#d9d9d9', marginRight: '15px'}
+          } else if (item.class.indexOf('border') > -1) {
+            item.style = {color: color, backgroundColor: '#fff', borderColor: color, marginRight: '15px'}
+          } else {
+            item.style = {color: item.class === 'gray' ? 'rgba(0, 0, 0, 0.65)' : '#fff', backgroundColor: color, borderColor: color, marginRight: '15px'}
+          }
+
           _actions.push(item)
         } else if (item.position === 'grid') {
+          item.style = {color: color, backgroundColor: 'transparent', borderColor: 'transparent'}
           _operations.push(item)
         }
       })
@@ -587,6 +603,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, search, _orderBy, pageIndex, pageSize, BID)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
 
     this.getStatFieldsValue()
@@ -678,6 +696,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, search, _orderBy, pageIndex, pageSize, BID, id)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
     if (result.status) {
       let data = fromJS(this.state.data).toJS()
diff --git a/src/tabviews/custom/components/calendar/index.jsx b/src/tabviews/custom/components/calendar/index.jsx
index 764dd9b..adda59d 100644
--- a/src/tabviews/custom/components/calendar/index.jsx
+++ b/src/tabviews/custom/components/calendar/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Modal } from 'antd'
+import { Spin } from 'antd'
 
 import Api from '@/api'
 import asyncComponent from '@/utils/asyncComponent'
@@ -264,36 +264,13 @@
         loading: false
       })
       
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/card/balcony/index.jsx b/src/tabviews/custom/components/card/balcony/index.jsx
index d3b0ce0..717fa6d 100644
--- a/src/tabviews/custom/components/card/balcony/index.jsx
+++ b/src/tabviews/custom/components/card/balcony/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Checkbox, Modal } from 'antd'
+import { Spin, Checkbox } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -413,37 +413,14 @@
         }
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 7e16f86..0926a50 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -8,6 +8,7 @@
 import asyncComponent from '@/utils/asyncComponent'
 import { getMark } from '@/utils/utils.js'
 import MkIcon from '@/components/mk-icon'
+import MKEmitter from '@/utils/events.js'
 import Encrypts from '@/components/encrypts'
 import './index.scss'
 
@@ -93,16 +94,45 @@
   openNewView = (e, card) => {
     const { cardCell, data, cards } = this.props
 
-    if (data.$disabled) return
+    e.stopPropagation()
 
-    if (card.anchors && card.anchors.length > 0) {
+    if (card.anchors) {
       let id = card.anchors[card.anchors.length - 1]
       let node = document.getElementById('anchor' + id)
       node && node.scrollIntoView({behavior: 'smooth', block: 'center', inline: 'nearest'})
     }
 
-    if (!card.link || (card.linkType === 'qywx' || card.linkType === 'linkmenu')) return
-    e.stopPropagation()
+    if (card.linkType === 'qywx') return
+    if (card.linkType === 'linkmenu') {
+      if (card.linkThdMenu) {
+        let __param = {
+          $BID: data.$$uuid
+        }
+  
+        if (card.field) {
+          __param.$searchkey = card.field.toLowerCase()
+          __param.$searchval = data[card.field] || ''
+        }
+      
+        if (card.joint === 'true' && card.linkThdMenu.urlFields) {
+          let lower = {}
+          Object.keys(data).forEach(key => {
+            lower[key.toLowerCase()] = data[key]
+          })
+
+          card.linkThdMenu.urlFields.split(',').forEach(field => {
+            __param[field] = lower[field.toLowerCase()] || ''
+          })
+        }
+
+        let tabmenu = card.linkThdMenu
+    
+        tabmenu.param = __param
+    
+        MKEmitter.emit('modifyTabs', tabmenu, true)
+      }
+      return
+    }
     
     let url = ''
 
@@ -433,7 +463,7 @@
           }
 
           if (card.copyable === 'true') {
-            if (card.link || (card.anchors && card.anchors.length > 0)) {
+            if (card.link || card.anchors) {
               let url = orival
 
               if (card.link === 'static') {
@@ -473,23 +503,31 @@
           }
           className = mark.signType
         }
-  
-        if (card.link || (card.anchors && card.anchors.length > 0)) {
-          _style.cursor = 'pointer'
-        }
     
         if (card.bgImage && data[card.bgImage]) {
           _style.backgroundImage = `url('${data[card.bgImage]}')`
         }
-  
-        contents.push(
-          <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)}}>
-              {card.alignItems ? <TextCell card={card} className={'ant-mk-text line' + (card.height || '') + className} value={val}/> : 
-              <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight}}>{val}</div>}
+
+        if (!data.$disabled && (card.link || card.anchors)) {
+          _style.cursor = 'pointer'
+          contents.push(
+            <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)}}>
+                {card.alignItems ? <TextCell card={card} className={'ant-mk-text line' + (card.height || '') + className} value={val}/> : 
+                <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight}}>{val}</div>}
+              </div>
             </div>
-          </div>
-        )
+          )
+        } else {
+          contents.push(
+            <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
+              <div style={_style}>
+                {card.alignItems ? <TextCell card={card} className={'ant-mk-text line' + (card.height || '') + className} value={val}/> : 
+                <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight}}>{val}</div>}
+              </div>
+            </div>
+          )
+        }
       } else if (card.eleType === 'number') {
         let val = ''
         let _style = {...card.style}
@@ -687,24 +725,31 @@
         _imagestyle.backgroundPosition = _style.backgroundPosition || 'center'
         _imagestyle.backgroundRepeat = _style.backgroundRepeat || 'no-repeat'
   
-        if (card.link) {
-          _style.cursor = 'pointer'
-        }
-
         if (_style.position === 'absolute') {
           _style.width = '100%'
         }
-  
+        
         let scale = url && card.scale === 'true'
         let urls = url ? url.split(',').filter(Boolean) : ['']
-
-        urls.forEach((u, i) => {
-          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} lostTip={card.lostTip !== 'false'} scale={scale} url={u} urls={urls}/>
-            </div>
-          </div>)
-        })
+        
+        if (card.link && !data.$disabled) {
+          _style.cursor = 'pointer'
+          urls.forEach((u, i) => {
+            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} lostTip={card.lostTip !== 'false'} scale={scale} url={u} urls={urls}/>
+              </div>
+            </div>)
+          })
+        } else {
+          urls.forEach((u, i) => {
+            contents.push(<div className={'ant-col ant-col-' + card.width} key={card.uuid + i} style={_style_} span={card.width}>
+              <div style={_style}>
+                <MkPicture style={_imagestyle} lostTip={card.lostTip !== 'false'} scale={scale} url={u} urls={urls}/>
+              </div>
+            </div>)
+          })
+        }
       } else if (card.eleType === 'splitline') {
         let _borderWidth = card.borderWidth === undefined ? 1 : card.borderWidth
         _style_ = _style_ || {}
@@ -821,14 +866,64 @@
             _data = [data]
           }
 
+          let _val = card.formula
+          if (/@username@|@fullName@|@bid@/ig.test(_val)) {
+            _val = _val.replace(/@username@/ig, sessionStorage.getItem('User_Name') || '').replace(/@fullName@/ig, sessionStorage.getItem('Full_Name') || '').replace(/@bid@/ig, data.$$BID || '')
+          }
+
           try {
             // eslint-disable-next-line
-            let func = new Function('data', card.formula)
+            let func = new Function('data', _val)
             val = func(_data)
           } catch (e) {
             console.warn(e)
             val = ''
           }
+
+          if (!val && card.noValue === 'hide') { // 绌哄�奸殣钘�
+            return null
+          } else if (typeof(val) === 'object' && val.type === 'linkmenu') {
+            // type: 'linkmenu', linkThdMenu: null, menuId: '', value: ``, defaultValue: '', onclick: 'inner'
+            let item = {linkType: 'linkmenu', linkThdMenu: val.linkThdMenu}
+            let _val_ = val.value || ''
+
+            if (!item.linkThdMenu && val.menuId) {
+              item.linkThdMenu = window.GLOB.mkThdMenus.get(val.menuId) || ''
+            }
+            if (!item.linkThdMenu && val.defaultValue) {
+              _val_ = val.defaultValue
+            }
+
+            if (val.onclick === 'inner') {
+              contents.push(
+                <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 || '')} style={{height: card.innerHeight}}>
+                      <span onClick={(e) => {this.openNewView(e, item)}} dangerouslySetInnerHTML={{__html: _val_}}></span>
+                    </div>
+                  </div>
+                </div>
+              )
+            } else {
+              _style.cursor = 'pointer'
+              contents.push(
+                <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
+                  <div style={_style} onClick={(e) => {this.openNewView(e, item)}}>
+                    <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight}} dangerouslySetInnerHTML={{__html: _val_}}></div>
+                  </div>
+                </div>
+              )
+            }
+          } else {
+            contents.push(
+              <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 || '')} style={{height: card.innerHeight}} dangerouslySetInnerHTML={{__html: val}}></div>
+                </div>
+              </div>
+            )
+          }
+          return
         } else if (card.$sync) {
           if (card.eval === 'false') {
             val = ''
@@ -858,6 +953,9 @@
           val = ''
         } else if (data) {
           let _val = card.formula
+          if (/@username@|@fullName@|@bid@/ig.test(_val)) {
+            _val = _val.replace(/@username@/ig, sessionStorage.getItem('User_Name') || '').replace(/@fullName@/ig, sessionStorage.getItem('Full_Name') || '').replace(/@bid@/ig, data.$$BID || '')
+          }
           Object.keys(data).forEach(key => {
             let reg = new RegExp('@' + key + '@', 'ig')
             _val = _val.replace(reg, data[key])
@@ -879,15 +977,6 @@
 
         if (!val && card.noValue === 'hide') { // 绌哄�奸殣钘�
           return null
-        } else if (card.eval === 'func') {
-          contents.push(
-            <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 || '')} style={{height: card.innerHeight}} dangerouslySetInnerHTML={{__html: val}}></div>
-              </div>
-            </div>
-          )
-          return
         }
 
         if (card.round && typeof(val) === 'number') {
@@ -946,6 +1035,56 @@
             </div>
           </div>
         )
+      } else if (card.eleType === 'tag') {
+        let vals = ''
+  
+        if (card.datatype === 'static') {
+          vals = card.value
+        } else {
+          vals = data[card.field] || ''
+        }
+  
+        if (!vals && card.noValue === 'hide') { // 绌哄�奸殣钘�
+          return null
+        }
+
+        vals = vals.split(',').filter(Boolean)
+  
+        if (card.signs) {
+          vals = vals.map(val => {
+            let sign = card.signs.filter(s => s.value === val)[0]
+            let cell = {value: val, style: {...card.style}}
+
+            if (sign) {
+              cell.style.backgroundColor = sign.background
+              cell.style.color = sign.color
+              cell.style.borderColor = sign.border
+
+              // delete cell.style.borderTopColor
+              // delete cell.style.borderBottomColor
+              // delete cell.style.borderLeftColor
+              // delete cell.style.borderRightColor
+            }
+
+            return cell
+          })
+
+          contents.push(
+            <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
+              <div className="ant-mk-tag">
+                {vals.map((item, index) => <span key={index} className="tag-item" style={item.style}>{item.value}</span>)}
+              </div>
+            </div>
+          )
+        } else {
+          contents.push(
+            <div className={'ant-col ant-col-' + card.width} key={card.uuid} style={_style_} span={card.width}>
+              <div className="ant-mk-tag">
+                {vals.map((val, index) => <span key={index} className="tag-item" style={card.style}>{val}</span>)}
+              </div>
+            </div>
+          )
+        }
       } else if (card.eleType === 'color') {
         let color = ''
   
@@ -1005,6 +1144,10 @@
         } else if (data.$$empty) {
           _data = []
         }
+        let name = ''
+        if (card.showName) {
+          name = data[card.showName] || ' '
+        }
 
         _style_ = _style_ || {}
         if (card.wrapStyle) {
@@ -1016,6 +1159,7 @@
         if (['exec', 'prompt', 'pop', 'form'].includes(card.OpenType)) {
           MkButton = <NormalButton
             btn={card}
+            name={name}
             BID={data.$$BID}
             BData={data.$$BData || ''}
             disabled={_disabled}
@@ -1044,6 +1188,7 @@
         } else if (card.OpenType === 'popview') {
           MkButton = <PopupButton
             btn={card}
+            name={name}
             BID={data.$$BID}
             BData={data.$$BData || ''}
             disabled={_disabled}
@@ -1053,6 +1198,7 @@
         } else if (card.OpenType === 'tab') {
           MkButton = <TabButton
             btn={card}
+            name={name}
             BID={data.$$BID}
             BData={data.$$BData || ''}
             disabled={_disabled}
@@ -1061,6 +1207,7 @@
         } else if (card.OpenType === 'innerpage') {
           MkButton = <NewPageButton
             btn={card}
+            name={name}
             BID={data.$$BID}
             BData={data.$$BData || ''}
             disabled={_disabled}
diff --git a/src/tabviews/custom/components/card/cardcellList/index.scss b/src/tabviews/custom/components/card/cardcellList/index.scss
index fbd7791..ff8997c 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.scss
+++ b/src/tabviews/custom/components/card/cardcellList/index.scss
@@ -3,6 +3,10 @@
   position: relative;
   line-height: 1.5;
   
+  .ant-col-0:not(.mk-cell-btn) {
+    display: block;
+    float: left;
+  }
   .ant-btn {
     padding: 0;
   }
@@ -17,6 +21,7 @@
     font-style: inherit;
     font-weight: inherit;
     text-decoration: inherit;
+    font-family: inherit;
     color: inherit;
     .anticon-copy {
       color: var(--mk-sys-color);
@@ -26,6 +31,7 @@
     font-style: inherit;
     font-weight: inherit;
     text-decoration: inherit;
+    font-family: inherit;
     .sequence-wrap {
       display: inline-block;
       width: 21px;
@@ -41,6 +47,7 @@
       font-style: inherit;
       font-weight: inherit;
       text-decoration: inherit;
+      font-family: inherit;
     }
   }
   .ant-mk-text:not(.line1):not(.line) {
@@ -88,6 +95,7 @@
     background-size: cover;
   }
   .mk-cell-btn {
+    text-align: center;
     min-height: 0px;
     > div {width: 100%;max-width: 100%;}
     button:not(.ant-switch) {
@@ -97,6 +105,7 @@
       min-height: 28px;
       padding: 0;
       overflow: hidden;
+      text-align: inherit;
     }
     .ant-checkbox-wrapper:not(.square) {
       .ant-checkbox-inner, .ant-checkbox-checked::after {
@@ -154,6 +163,12 @@
     border-left: 0;
     border-right: 0;
   }
+  .ant-mk-tag {
+    .tag-item {
+      display: inline-block;
+      vertical-align: top;
+    }
+  }
   .ant-mk-check {
     white-space: nowrap;
     overflow: hidden;
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index de3f1a8..95c8bb2 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Empty, notification, message, Row, Col, Pagination, Modal, Switch } from 'antd'
+import { Spin, Empty, message, Row, Col, Pagination, Switch } from 'antd'
 import { DownOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -42,12 +42,11 @@
     precards: [],
     nextcards: [],
     selected: 'false',
-    supNodes: [],
-    supComs: null,
     pickup: false
   }
 
   loaded = false
+  supModules = []
 
   UNSAFE_componentWillMount () {
     const { config } = this.props
@@ -124,17 +123,12 @@
       _config.wrap.selected = 'false'
     }
 
-    let supComs = null
-    if (_config.wrap.supType === 'multi') {
-      supComs = _config.supNodes.map(item => item.componentId)
-    }
-
     _config.wrap.selStyle = _config.wrap.selStyle || 'active'
     _config.wrap.pagestyle = _config.wrap.pagestyle || 'page'
     _config.wrap.scale = _config.wrap.scale === 'true' ? 'scale' : ''
     _config.wrap.layout = (_config.wrap.layout || 'grid') + '-layout float-' + (_config.wrap.cardFloat || 'left')
 
-    _config.wrap.wrapClass = `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale}`
+    _config.wrap.wrapClass = `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale} ${config.wrap.hover === 'true' ? 'mk-hover' : ''}`
 
     if (_config.wrap.shifting === 'true') {
       _config.wrap.shifting = 'shifting'
@@ -197,7 +191,6 @@
     this.setState({
       pageSize: _config.setting.pageSize || 10,
       pageOptions,
-      supComs,
       selected,
       precards,
       nextcards,
@@ -412,14 +405,14 @@
    * @param {*} btn        // 鎵ц鐨勬寜閽�
    */
   refreshByButtonResult = (menuId, position, btn, id = '', lines) => {
-    const { config, BID, supComs, supNodes } = this.state
+    const { config, BID } = this.state
 
     if (config.uuid !== menuId) return
 
-    if (supComs) {
-      if (position === 'mainline' || position === 'popclose') { // 涓昏〃鍒锋柊锛屽幓闄ゅ悓姝ュ埛鏂扮粍浠�
-        let supNode = supNodes[supNodes.length - 1]
-        supComs.forEach((item, i) => {
+    if (config.supNodes) {
+      if (position === 'mainline' || position === 'popclose') {
+        let supNode = this.supModules[this.supModules.length - 1]
+        config.supNodes.forEach((item, i) => {
           setTimeout(() => {
             if (supNode && supNode.key === item) {
               MKEmitter.emit('reloadData', item, supNode.value)
@@ -678,28 +671,26 @@
   }
 
   resetParentParam = (MenuID, id, data) => {
-    const { config, supComs } = this.state
+    const { config } = this.state
 
-    if (supComs) {
-      if (!supComs.includes(MenuID)) return
-      let supNodes = this.state.supNodes.filter(item => item.key !== MenuID)
+    if (config.supNodes) {
+      if (!config.supNodes.includes(MenuID)) return
+      this.supModules = this.supModules.filter(item => item.key !== MenuID)
       let bid = ''
       let _data = null
 
       if (id) {
-        supNodes.push({key: MenuID, value: id, data})
+        this.supModules.push({key: MenuID, value: id, data})
       }
-      if (supNodes.length > 0) {
-        bid = supNodes[supNodes.length - 1].value
-        _data = supNodes[supNodes.length - 1].data
+      if (this.supModules.length > 0) {
+        bid = this.supModules[this.supModules.length - 1].value
+        _data = this.supModules[this.supModules.length - 1].data
       }
 
       if (bid !== this.state.BID || bid !== '') {
-        this.setState({ BID: bid, BData: _data, pageIndex: 1, supNodes }, () => {
+        this.setState({ BID: bid, BData: _data, pageIndex: 1 }, () => {
           this.loadData()
         })
-      } else {
-        this.setState({ supNodes })
       }
     } else {
       if (!config.setting.supModule || config.setting.supModule !== MenuID) return
@@ -755,13 +746,9 @@
         loading: false
       })
       
-      if (selected !== 'false' || (id && config.wrap.selected !== 'false')) {
-        this.prevCheck(id)
-      } else {
-        MKEmitter.emit('resetSelectLine', config.uuid, '', '')
-        if (config.setting.$hasSyncModule) {
-          MKEmitter.emit('syncBalconyData', config.uuid, [], false)
-        }
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      if (config.setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
       }
       return
     }
@@ -871,37 +858,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
 
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -1043,11 +1008,8 @@
       this.setState({
         loading: false
       })
-      notification.error({
-        top: 92,
-        message: result.message,
-        duration: 10
-      })
+      
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -1251,7 +1213,7 @@
               let className = 'mk-card '
               if (config.wrap.parity === 'true') {
                 if (index % 2 === 1) {
-                  className += 'mk-parity-bg '
+                  className += 'mk-even-line '
                 }
               }
               if (item.$disabled) {
diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss
index b2def5d..e26e385 100644
--- a/src/tabviews/custom/components/card/data-card/index.scss
+++ b/src/tabviews/custom/components/card/data-card/index.scss
@@ -38,8 +38,15 @@
         }
       }
     }
-    .mk-parity-bg {
+    .mk-even-line {
       .card-item-box {
+        background-color: #fafafa;
+      }
+    }
+  }
+  .data-zoom.mk-hover {
+    .mk-card {
+      .card-item-box:hover {
         background-color: var(--mk-sys-color1);
       }
     }
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 4903092..bc0cd42 100644
--- a/src/tabviews/custom/components/card/double-data-card/index.jsx
+++ b/src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Empty, notification, Row, Col, Pagination, Modal, Switch } from 'antd'
+import { Spin, Empty, Row, Col, Pagination, Switch } from 'antd'
 import { DownOutlined, UpOutlined, PlusSquareOutlined, MinusSquareOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -595,17 +595,8 @@
         total: 0,
         loading: false
       })
-      
-      if (selected !== 'false' || (id && config.wrap.selected !== 'false')) {
-        setTimeout(() => {
-          this.checkTopLine(id)
-        }, 10)
-        if (selected === 'init') {
-          this.setState({selected: 'false'})
-        }
-      } else {
-        MKEmitter.emit('resetSelectLine', config.uuid, '', '')
-      }
+
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
       return
     }
 
@@ -771,37 +762,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
 
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -959,11 +928,8 @@
       this.setState({
         loading: false
       })
-      notification.error({
-        top: 92,
-        message: result.message,
-        duration: 10
-      })
+      
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/card/double-data-card/index.scss b/src/tabviews/custom/components/card/double-data-card/index.scss
index 4d27218..3f19dd4 100644
--- a/src/tabviews/custom/components/card/double-data-card/index.scss
+++ b/src/tabviews/custom/components/card/double-data-card/index.scss
@@ -194,14 +194,14 @@
     >.card-row-list {
       >.ant-col:not(.extend-card) {
         .card-item-box:hover {
-          background-color: var(--mk-sys-color2);
+          background-color: var(--mk-sys-color1);
         }
       }
     }
     .sub-card-wrap.mk-parity-bg {
       .ant-col:nth-child(even){
         .card-item-box:not(:hover) {
-          background-color: var(--mk-sys-color1);
+          background-color: #fafafa;
         }
       }
     }
@@ -270,7 +270,7 @@
     .sub-card-wrap.mk-parity-bg {
       .ant-col:nth-child(even){
         .card-item-box {
-          background-color: var(--mk-sys-color1);
+          background-color: #fafafa;
         }
       }
     }
diff --git a/src/tabviews/custom/components/card/prop-card/index.jsx b/src/tabviews/custom/components/card/prop-card/index.jsx
index 1319e6d..7885b03 100644
--- a/src/tabviews/custom/components/card/prop-card/index.jsx
+++ b/src/tabviews/custom/components/card/prop-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Col, Row, Modal } from 'antd'
+import { Spin, Col, Row } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -76,6 +76,14 @@
 
     _data.$$BID = BID || ''
     _data.$$BData = BData || ''
+
+    if (_config.wrap.datatype === 'static' && BData) {
+      Object.keys(BData).forEach(key => {
+        if (/\$/.test(key)) return
+        _data[key] = BData[key]
+      })
+    }
+
     if (_config.setting.primaryKey) {
       _data.$$uuid = _data[_config.setting.primaryKey] || ''
     }
@@ -494,8 +502,16 @@
     }
     
     if (config.wrap.datatype === 'static') {
+      let _data = {$$BID: BID || '', $$BData: BData, $$empty: true, $$time: new Date().getTime()}
+      if (BData) {
+        Object.keys(BData).forEach(key => {
+          if (/\$/.test(key)) return
+          _data[key] = BData[key]
+        })
+      }
+
       this.setState({
-        data: {$$BID: BID || '', $$BData: BData, $$empty: true, $$time: new Date().getTime()},
+        data: _data,
       })
 
       if (!btn) {
@@ -573,37 +589,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
 
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/card/table-card/index.jsx b/src/tabviews/custom/components/card/table-card/index.jsx
index 8dcb134..231e066 100644
--- a/src/tabviews/custom/components/card/table-card/index.jsx
+++ b/src/tabviews/custom/components/card/table-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Row, Col, Empty, Pagination, Modal } from 'antd'
+import { Spin, Row, Col, Empty, Pagination } from 'antd'
 import { DownOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -12,6 +12,7 @@
 import './index.scss'
 
 const CardCellComponent = asyncComponent(() => import('../cardcellList'))
+const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
 const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
 
 class TableCard extends Component {
@@ -20,13 +21,14 @@
   }
 
   state = {
-    BID: '',                   // 涓婄骇ID
-    config: null,              // 鍥捐〃閰嶇疆淇℃伅
-    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
-    search: null,              // 鎼滅储鏉′欢
-    pageIndex: 1,              // 椤电爜
-    total: 0,                  // 鎬绘暟
-    data: null,                // 鏁版嵁
+    BID: '',
+    config: null,
+    loading: false,
+    search: null,
+    pageIndex: 1,
+    total: 0,
+    data: null,
+    precards: [],
     BData: ''
   }
 
@@ -94,12 +96,22 @@
       }
     }
 
+    let precards = []
+    _config.subcards = _config.subcards.filter(item => {
+      if (item.setting.condition === 'title') {
+        precards.push(item)
+        return false
+      }
+      return true
+    })
+
     this.setState({
       BID: BID || '',
       BData: BData || '',
       data: _data,
       config: _config,
-      search: _config.$searches
+      search: _config.$searches,
+      precards
     })
   }
 
@@ -417,37 +429,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -507,13 +497,14 @@
     }
   }
 
-  getLines = (data) => {
+  getLines = (data, lindex) => {
     const { config } = this.state
 
     let line = []
 
     config.subcards.forEach((item, index) => {
       let display = item.setting.condition !== 'true'
+      let className = ''
 
       if (!display && item.setting.controlField) {
         let val = data[item.setting.controlField]
@@ -531,12 +522,20 @@
         } else if (item.setting.controlType === '<' && val < item.setting.controlValue) {
           display = true
         }
+
+        className = 'mk_line_' + val
       }
 
       if (!display) return
 
+      if (config.wrap.parity === 'true') {
+        if (lindex % 2 === 1) {
+          className += ' mk-even-line'
+        }
+      }
+
       line.push(
-        <Col key={index} span={24}>
+        <Col key={index} className={className} span={24}>
           <div className="card-item-box" style={item.style} onClick={() => {this.openView(item, data)}}>
             <CardCellComponent data={data} cards={config} cardCell={item} elements={item.elements}/>
           </div>
@@ -571,7 +570,7 @@
   }
 
   render() {
-    const { config, loading, data, BID, pageIndex, total } = this.state
+    const { config, loading, data, BID, pageIndex, total, BData, precards } = this.state
 
     if (config.wrap.empty === 'hidden' && (!data || data.length === 0)) return null
     
@@ -584,12 +583,27 @@
           </div> : null
         }
         <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
-        {data && data.length > 0 ? <Row className={'card-row-list' + (config.wrap.parity === 'true' ? ' mk-parity' : '')} style={{height: config.wrap.contentHeight}}>
-          {data.map(item => this.getLines(item))}
-        </Row> : null}
-        {data && data.length === 0 ? <div className="card-row-list" style={{height: config.wrap.contentHeight}}>
-          <Empty description={false}/>
-        </div> : null}
+        {config.action && config.action.length > 0 ?
+          <MainAction
+            BID={BID}
+            BData={BData}
+            setting={config.setting}
+            actions={config.action}
+            columns={config.columns}
+            selectedData={[]}
+          /> : null
+        }
+        <Row className={`card-row-list ${config.wrap.hover === 'true' ? 'mk-hover' : ''}`} style={{height: config.wrap.contentHeight}}>
+          {precards.map((item, index) => (
+            <Col key={index} className="extend-card" span={24}>
+              <div className="card-item-box" style={item.style}>
+                <CardCellComponent data={data && data[0] ? data[0] : {}} cards={config} cardCell={item} elements={item.elements}/>
+              </div>
+            </Col>
+          ))}
+          {data && data.length > 0 ? data.map((item, index) => this.getLines(item, index)) : null}
+          {data && data.length === 0 ? <Empty description={false}/> : null}
+        </Row>
         {config.wrap.pagestyle === 'page' ? <Pagination size="small" current={pageIndex} total={total} onChange={this.changePageIndex} /> : null}
         {config.wrap.pagestyle === 'more' && data && data.length > 0 ? <div className={'mk-more' + (config.setting.pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>鏌ョ湅鏇村<DownOutlined/></div> : null}
       </div>
diff --git a/src/tabviews/custom/components/card/table-card/index.scss b/src/tabviews/custom/components/card/table-card/index.scss
index 088083a..10fb9be 100644
--- a/src/tabviews/custom/components/card/table-card/index.scss
+++ b/src/tabviews/custom/components/card/table-card/index.scss
@@ -33,13 +33,6 @@
     clear: both;
   }
 
-  .mk-parity {
-    >.ant-col:nth-child(even) {
-      .card-item-box {
-        background-color: var(--mk-sys-color1);
-      }
-    }
-  }
   .card-row-list {
     overflow-y: auto;
     .card-item-box {
@@ -47,9 +40,17 @@
       background-color: #ffffff;
       transition: all 0.3s;
     }
-    >.active >.card-item-box {
-      border-color: #1890ff!important;
-      box-shadow: 0 0 3px #1890ff;
+    .mk-even-line {
+      .card-item-box {
+        background-color: #fafafa;
+      }
+    }
+  }
+  .card-row-list.mk-hover {
+    >.ant-col:not(.extend-card) {
+      .card-item-box:hover {
+        background-color: var(--mk-sys-color1);
+      }
     }
   }
   .card-row-list::-webkit-scrollbar {
diff --git a/src/tabviews/custom/components/carousel/data-card/index.jsx b/src/tabviews/custom/components/carousel/data-card/index.jsx
index 45a3656..b2be453 100644
--- a/src/tabviews/custom/components/carousel/data-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/data-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Empty, notification, Carousel, Modal, Checkbox, Button } from 'antd'
+import { Spin, Empty, Carousel, Modal, Checkbox, Button } from 'antd'
 import { LeftOutlined, RightOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -379,37 +379,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/carousel/prop-card/index.jsx b/src/tabviews/custom/components/carousel/prop-card/index.jsx
index 572b869..d1808aa 100644
--- a/src/tabviews/custom/components/carousel/prop-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/prop-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Carousel, Modal, Checkbox, Button } from 'antd'
+import { Spin, Carousel, Modal, Checkbox, Button } from 'antd'
 import { LeftOutlined, RightOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -382,37 +382,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/antv-G6/index.jsx b/src/tabviews/custom/components/chart/antv-G6/index.jsx
index 64536d5..c7dd705 100644
--- a/src/tabviews/custom/components/chart/antv-G6/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-G6/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, notification, Spin, Empty } from 'antd'
+import { Spin, Empty } from 'antd'
 import G6 from '@antv/g6'
 
 import Api from '@/api'
@@ -1167,36 +1167,14 @@
         this.data = result.data || []
         this.handleData()
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/antv-X6/index.jsx b/src/tabviews/custom/components/chart/antv-X6/index.jsx
index faedfd9..08990ce 100644
--- a/src/tabviews/custom/components/chart/antv-X6/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-X6/index.jsx
@@ -1,8 +1,8 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Tooltip, message, Modal, notification, Switch } from 'antd'
-import { UndoOutlined, RedoOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined, SaveOutlined, ZoomInOutlined, ZoomOutOutlined, OneToOneOutlined, QuestionCircleOutlined, ClearOutlined } from '@ant-design/icons'
+import { Spin, Tooltip, message, Modal, notification, Switch, Button } from 'antd'
+import { UndoOutlined, RedoOutlined, VerticalAlignTopOutlined, VerticalAlignBottomOutlined, ZoomInOutlined, ZoomOutOutlined, OneToOneOutlined, QuestionCircleOutlined, ClearOutlined } from '@ant-design/icons'
 import { Graph, Shape } from '@antv/x6'
 import { Stencil } from '@antv/x6-plugin-stencil'
 import { Transform } from '@antv/x6-plugin-transform'
@@ -388,7 +388,8 @@
     status: 0,
     flowname: '',
     flowcode: '',
-    orgs: []
+    orgs: [],
+    empty: true
   }
 
   selectNode = null
@@ -526,6 +527,7 @@
                     worker_id: work.worker_id || '',
                     workercode: work.workercode || '',
                     workername: work.workername || '',
+                    job_type: job.job_type || '',
                     parentIds: [com.OrgCode, dep.co_pro_code, job.jobcode],
                     parentNames: [com.OrgName, dep.co_pro_name, job.jobname]
                   }
@@ -553,6 +555,7 @@
                     worker_id: work.worker_id || '',
                     workercode: work.workercode || '',
                     workername: work.workername || '',
+                    job_type: job.job_type || '',
                     parentIds: [com.OrgCode, dep.co_pro_code, job.jobcode, group.work_group],
                     parentNames: [com.OrgName, dep.co_pro_name, job.jobname, group.work_group]
                   }
@@ -590,8 +593,8 @@
     const { BID } = this.state
 
     if (!BID) {
+      this.cells = []
       if (!is(fromJS(this.data), fromJS([]))) {
-        this.cells = []
         this.handleData()
       }
       this.setState({empty: true})
@@ -624,7 +627,8 @@
         status: item.status || 0,
         flowname: item.works_flow_name || '',
         flowcode: item.works_flow_code || '',
-        loading: false
+        loading: false,
+        empty: cells.length === 0
       })
 
       if (result.message) {
@@ -994,6 +998,18 @@
 
       graph.clearTransformWidgets()
     })
+
+    graph.on('node:dblclick', () => {
+      setTimeout(() => {
+        MKEmitter.emit('mk-x6-dbclick')
+      }, 100)
+    })
+    graph.on('edge:dblclick', () => {
+      setTimeout(() => {
+        MKEmitter.emit('mk-x6-dbclick')
+      }, 100)
+    })
+
     graph.on('blank:click', () => {
       this.selectNode = null
       
@@ -1003,8 +1019,19 @@
       if (!isNew) return
 
       let target = edge.getTargetCell()
+      let source = edge.getSourceCell()
 
-      if (!target) return
+      if (!target || !source) return
+
+      if (source.prop('mknode') === 'end') {
+        notification.warning({
+          top: 92,
+          message: '缁撴潫鑺傜偣涓嶅彲娣诲姞鍒嗘敮锛�',
+          duration: 2
+        })
+        graph.removeCells([edge])
+        return
+      }
 
       let mkdata = target.prop('mkdata')
 
@@ -1012,6 +1039,8 @@
         edge.prop('mknode', 'endEdge')
       } else if (target.prop('mknode') === 'start') {
         edge.prop('mknode', 'startEdge')
+      } else if (source.prop('mknode') === 'start') {
+        edge.prop('mknode', 'firstEdge')
       }
       if (mkdata) {
         edge.prop('mkdata', {status: mkdata.status, statusName: mkdata.statusName})
@@ -1544,6 +1573,26 @@
     this.mkGraph.zoomTo(1)
   }
 
+  close = () => {
+    const { config } = this.state
+
+    let nodes = this.mkGraph.toJSON()
+
+    if (!is(fromJS(nodes.cells), fromJS(this.cells))) {
+      confirm({
+        title: '娴佺▼鍥惧凡淇敼锛岀‘瀹氬叧闂悧?',
+        okText: '纭畾',
+        cancelText: '鍙栨秷',
+        onOk() {
+          MKEmitter.emit('closeTabView', config.$pageId)
+        },
+        onCancel() {}
+      })
+    } else {
+      MKEmitter.emit('closeTabView', config.$pageId)
+    }
+  }
+
   save = () => {
     const { BID, plot, status, flowname, flowcode } = this.state
 
@@ -1596,7 +1645,7 @@
         }
       })
 
-      if (start_num !== 1 || end_num !== 1 || unvalid) {
+      if (start_num !== 1 || end_num === 0 || unvalid) {
         _status = 0
       }
     }
@@ -1638,6 +1687,7 @@
                   loading: false,
                   status: _status
                 })
+                this.cells = nodes.cells
               } else {
                 notification.error({
                   top: 92,
@@ -1659,6 +1709,7 @@
               loading: false,
               status: _status
             })
+            this.cells = nodes.cells
           }
         } else {
           notification.error({
@@ -2080,12 +2131,12 @@
           message: '璇锋坊鍔犵粨鏉熻妭鐐癸紒',
           duration: 2
         })
-      } else if (end_num > 1) {
-        notification.warning({
-          top: 92,
-          message: '缁撴潫鑺傜偣涓嶅彲娣诲姞澶氫釜锛�',
-          duration: 2
-        })
+      // } else if (end_num > 1) {
+      //   notification.warning({
+      //     top: 92,
+      //     message: '缁撴潫鑺傜偣涓嶅彲娣诲姞澶氫釜锛�',
+      //     duration: 2
+      //   })
       } else if (emptyNode) {
         let errmsg = '閮ㄥ垎鑺傜偣鏈缃熀鏈俊鎭��'
         if (emptyNode.attrs && emptyNode.attrs.text && emptyNode.attrs.text.text) {
@@ -2202,12 +2253,12 @@
   }
 
   render() {
-    const { loading, config, node, orgs, status, flowname } = this.state
+    const { loading, config, node, orgs, status, flowname, empty } = this.state
 
     let style = {...config.style}
 
     if (config.plot.function === 'show') {
-      if (config.plot.empty === 'hidden' && this.cells.length === 0) {
+      if (config.plot.empty === 'hidden' && empty) {
         style.position = 'absolute'
         style.width = '100%'
         style.zIndex = -1
@@ -2264,18 +2315,15 @@
             <Tooltip title="娓呯┖">
               <ClearOutlined onClick={this.clearNode}/>
             </Tooltip>
-            <Tooltip overlayStyle={{maxWidth: 260}} title="蹇嵎閿細澶嶅埗锛坈trl+c锛夈�佸壀鍒囷紙ctrl+x锛夈�佺矘璐达紙ctrl+v锛夈�佸悗閫�锛坈trl+z锛夈�佸墠杩涳紙ctrl+shift+z锛夈�佸垹闄わ紙backspace 鎴� delete锛�">
+            <Tooltip overlayStyle={{maxWidth: 310}} title="蹇嵎閿細澶嶅埗锛坈trl+c锛夈�佸壀鍒囷紙ctrl+x锛夈�佺矘璐达紙ctrl+v锛夈�佸悗閫�锛坈trl+z锛夈�佸墠杩涳紙ctrl+shift+z锛夈�佸垹闄わ紙backspace 鎴� delete锛夛紱鍙屽嚮鑺傜偣鎴栬繛绾垮彲缂栬緫鑷畾涔変俊鎭��">
               <QuestionCircleOutlined />
             </Tooltip>
           </div>
           <div className="flow-name">{flowname}</div>
           <div className="right-tool">
-            <Tooltip title="鍚敤/鍋滅敤">
-              <Switch size="small" style={{marginRight: '10px'}} checked={status === 10} onChange={this.changeStatus} />
-            </Tooltip>
-            <Tooltip title="淇濆瓨">
-              <SaveOutlined style={{marginRight: '10px'}} onClick={this.save}/>
-            </Tooltip>
+            <Switch size="large" checked={status === 10} checkedChildren="鍚�" unCheckedChildren="鍋�" onChange={this.changeStatus} />
+            <Button className="save" onClick={this.save}>淇濆瓨</Button>
+            <Button className="close" onClick={this.close}>鍏抽棴</Button>
           </div>
         </div>
         <div className="canvas" style={{width: '100%', minHeight: config.plot.height, height: config.plot.height}} id={config.uuid + 'canvas'}>
diff --git a/src/tabviews/custom/components/chart/antv-X6/index.scss b/src/tabviews/custom/components/chart/antv-X6/index.scss
index ccaccfb..5fc7c62 100644
--- a/src/tabviews/custom/components/chart/antv-X6/index.scss
+++ b/src/tabviews/custom/components/chart/antv-X6/index.scss
@@ -32,10 +32,34 @@
     .right-tool {
       float: right;
       line-height: 40px;
-      .anticon {
-        margin: 0 10px;
-        font-size: 16px;
-        cursor: pointer;
+
+      .ant-switch {
+        min-width: 60px;
+        height: 28px;
+        line-height: 28px;
+        margin-top: -2px;
+        .ant-switch-inner {
+          font-size: 14px;
+        }
+      }
+      .ant-switch:after {
+        width: 24px;
+        height: 24px;
+      }
+      .save, .save:hover, .save:active, .save:focus {
+        border-color: var(--mk-sys-color);
+        background-color: var(--mk-sys-color);
+        color: #ffffff;
+        margin: 0 15px;
+        height: 30px;
+      }
+      .close {
+        margin-right: 15px;
+      }
+      .close:hover, .close:active, .close:focus {
+        border-color: var(--mk-sys-color);
+        color: var(--mk-sys-color);
+        height: 30px;
       }
     }
   }
diff --git a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx
index 9ff4eb4..91c6cee 100644
--- a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.jsx
@@ -6,6 +6,7 @@
 
 import ColorSketch from '@/tabviews/zshare/mutilform/mkColor'
 import NodeForm from './nodeform'
+import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 const { TextArea } = Input
@@ -30,6 +31,10 @@
     })
   }
 
+  componentDidMount () {
+    MKEmitter.addListener('mk-x6-dbclick', this.trigger)
+  }
+
   UNSAFE_componentWillReceiveProps(nextProps) {
     if (!is(fromJS(this.props.node), fromJS(nextProps.node))) {
       this.setState({
@@ -42,6 +47,25 @@
         })
       })
     }
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+
+    MKEmitter.removeListener('mk-x6-dbclick', this.trigger)
+  }
+
+  trigger = () => {
+    const { formlist } = this.state
+
+    if (!formlist || formlist.findIndex(item => item.type === 'other') === -1) return
+
+    this.setState({visible: true})
   }
 
   getFormList = (node) => {
@@ -496,10 +520,12 @@
         </Form>
         <Modal
           title={mknode && mknode.shape === 'edge' ? '杩炵嚎缂栬緫' : '鑺傜偣缂栬緫'}
+          wrapClassName="mk-x6-modal"
           visible={visible}
           closable={false}
           maskClosable={false}
           width={1050}
+          centered={true}
           onOk={this.confirm}
           onCancel={() => this.setState({visible: false})}
           destroyOnClose
diff --git a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss
index a161a64..f8b1118 100644
--- a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss
+++ b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/index.scss
@@ -110,6 +110,7 @@
 }
 
 .normal-node-form {
+  padding: 0 24px;
   >.ant-row >.ant-col-24 {
     .ant-form-item-label {
       width: 16%;
@@ -117,6 +118,12 @@
     .ant-form-item-control-wrapper {
       width: 84%;
     }
+  }
+  .mk-split {
+    color: var(--mk-sys-color);
+    border-bottom: 1px solid #e8e8e8;
+    padding-left: 15px;
+    padding-bottom: 5px;
   }
   .member-input {
     display: inline-block;
@@ -179,7 +186,26 @@
     }
   }
 }
-
+.mk-x6-modal {
+  .ant-modal-body {
+    max-height: calc(100vh - 170px);
+    overflow-y: auto;
+  }
+  .ant-modal-body::-webkit-scrollbar {
+    width: 7px;
+  }
+  .ant-modal-body::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+    background: rgba(0, 0, 0, 0.13);
+  }
+  .ant-modal-body::-webkit-scrollbar-track {
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+    border-radius: 3px;
+    border: 1px solid rgba(0, 0, 0, 0.07);
+    background: rgba(0, 0, 0, 0);
+  }
+}
 .member-modal {
   .ant-modal {
     top: 50px;
diff --git a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx
index a400204..7980951 100644
--- a/src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx
+++ b/src/tabviews/custom/components/chart/antv-X6/nodeupdate/nodeform.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, Tooltip, InputNumber, Switch } from 'antd'
+import { Form, Row, Col, Input, Radio, Tooltip, InputNumber, Switch, notification } from 'antd'
 import { QuestionCircleOutlined } from '@ant-design/icons'
 
 import MemberForm from './memberform'
@@ -10,18 +10,62 @@
   static propTpyes = {
     node: PropTypes.any,
     data: PropTypes.any,
-    orgs: PropTypes.array
+    orgs: PropTypes.array,
+    handleSubmit: PropTypes.func
   }
 
   state = {
-    flowType: this.props.data.flowType || 'approval',
-    execCondition: this.props.data.execCondition === 'open',
+    flowType: 'approval',
+    execCondition: false,
+    approvalMethod: 'orsign',
+    readOnly: false,
+    options: []
+  }
+
+  UNSAFE_componentWillMount() {
+    const { node, data } = this.props
+
+    let options = []
+    let readOnly = false
+
+    if (node.mknode === 'start') {
+      readOnly = true
+    } else if (node.mknode === 'end') {
+
+    } else if (node.mknode === 'endEdge') {
+      options = ['approvalMethod']
+    } else if (node.mknode === 'startEdge') {
+      readOnly = true
+    } else if (node.mknode === 'firstEdge') {
+      options = ['approver', 'members', 'copys']
+    } else if (node.shape !== 'edge') { // node
+      options = ['sign']
+    } else {
+      options = ['flowType', 'approvalMethod', 'approver', 'members', 'copys', 'execCondition']
+    }
+
+    this.setState({
+      flowType: data.flowType || 'approval',
+      execCondition: options.includes('execCondition') && data.execCondition === 'open',
+      approvalMethod: data.approvalMethod || 'orsign',
+      options,
+      readOnly
+    })
   }
 
   handleConfirm = () => {
     return new Promise((resolve, reject) => {
       this.props.form.validateFieldsAndScroll((err, values) => {
         if (!err) {
+          if (values.approvalMethod === 'countersign' && values.members.length > 5) {
+            notification.warning({
+              top: 92,
+              message: '浼氱鏃跺鎵逛汉涓嶅彲瓒呰繃5浜猴紒',
+              duration: 10
+            })
+            return
+          }
+
           if (values.execCondition === true) {
             values.execCondition = 'open'
           } else if (values.execCondition === false) {
@@ -40,9 +84,9 @@
   }
 
   render() {
-    const { node, orgs } = this.props
+    const { orgs } = this.props
     const { getFieldDecorator } = this.props.form
-    const { flowType, execCondition } = this.state
+    const { flowType, execCondition, approvalMethod, readOnly, options } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -54,32 +98,22 @@
       }
     }
     let data = this.props.data || {}
-    let nodetype = node.shape !== 'edge' ? 'node' : 'edge'
-    if (node.mknode === 'start') {
-      nodetype = 'start'
-    } else if (node.mknode === 'end') {
-      nodetype = 'end'
-    } else if (node.mknode === 'endEdge') {
-      nodetype = 'endEdge'
-    } else if (node.mknode === 'startEdge') {
-      nodetype = 'startEdge'
-    }
 
     return (
       <Form {...formItemLayout} className="normal-node-form">
         <Row gutter={24}>
+          {options.includes('approver') ? <Col span={24}>
+            <p className="mk-split">鎸夐挳鎵ц鍛戒护</p>
+          </Col> : null}
           <Col span={12}>
             <Form.Item label="鐘舵�佸��">
               {getFieldDecorator('status', {
                 initialValue: data.status,
                 rules: [
-                  {
-                    required: true,
-                    message: '璇疯緭鍏ョ姸鎬佸��!'
-                  }
+                  { required: true, message: '璇疯緭鍏ョ姸鎬佸��!' }
                 ]
               })(
-                <InputNumber readOnly={nodetype !== 'node' && nodetype !== 'edge'} precision={0}/>
+                <InputNumber readOnly={readOnly} precision={0} onPressEnter={() => this.props.handleSubmit()}/>
               )}
             </Form.Item>
           </Col>
@@ -88,11 +122,11 @@
               {getFieldDecorator('statusName', {
                 initialValue: data.statusName || ''
               })(
-                <Input placeholder="" autoComplete="off"/>
+                <Input autoComplete="off" onPressEnter={() => this.props.handleSubmit()}/>
               )}
             </Form.Item>
           </Col>
-          {nodetype === 'node' ? <Col span={12}>
+          {options.includes('sign') ? <Col span={12}>
             <Form.Item label={
               <Tooltip placement="topLeft" title="鏍囪灏嗕綔涓鸿妭鐐笽D">
                 <QuestionCircleOutlined className="mk-form-tip" />
@@ -102,11 +136,11 @@
               {getFieldDecorator('sign', {
                 initialValue: data.sign || ''
               })(
-                <Input placeholder="" autoComplete="off"/>
+                <Input autoComplete="off" onPressEnter={() => this.props.handleSubmit()}/>
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' ? <Col span={12}>
+          {options.includes('flowType') ? <Col span={12}>
             <Form.Item label="鎿嶄綔绫诲瀷">
               {getFieldDecorator('flowType', {
                 initialValue: flowType
@@ -118,7 +152,48 @@
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' ? <Col span={12}>
+          {options.includes('approvalMethod') && flowType !== 'reject' ? <Col span={12}>
+            <Form.Item label="瀹℃壒鏂瑰紡">
+              {getFieldDecorator('approvalMethod', {
+                initialValue: approvalMethod
+              })(
+                <Radio.Group onChange={(e) => this.setState({approvalMethod: e.target.value})}>
+                  <Radio value="orsign">鎴栫</Radio>
+                  <Radio value="countersign">浼氱</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {options.includes('approvalMethod') && flowType !== 'reject' && approvalMethod === 'countersign' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="绀轰緥锛氣�滆储鍔$粡鐞嗗紶鎬诲凡瀹℃牳鈥濓紝鍏朵腑鈥滃凡瀹℃牳鈥濅负浼氱鏍囪銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                浼氱鏍囪
+              </Tooltip>
+            }>
+              {getFieldDecorator('mark', {
+                initialValue: data.mark || '宸插鏍�',
+                rules: [
+                  { required: true, message: '璇疯緭鍏ヤ細绛炬爣璁�!' }
+                ]
+              })(
+                <Input autoComplete="off" onPressEnter={() => this.props.handleSubmit()}/>
+              )}
+            </Form.Item>
+          </Col> : null}
+          <Col span={24}>
+            <Form.Item label="澶囨敞">
+              {getFieldDecorator('remark', {
+                initialValue: data.remark || ''
+              })(
+                <TextArea rows={2}/>
+              )}
+            </Form.Item>
+          </Col>
+          {options.includes('approver') ? <Col span={24}>
+            <p className="mk-split">涓嬩竴姝ュ鎵规潈闄�</p>
+          </Col> : null}
+          {options.includes('approver') ? <Col span={12}>
             <Form.Item label="璁剧疆瀹℃壒浜�">
               {getFieldDecorator('approver', {
                 initialValue: data.approver || 'member'
@@ -131,32 +206,19 @@
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' && flowType !== 'reject' ? <Col span={12}>
-            <Form.Item label="瀹℃壒鏂瑰紡">
-              {getFieldDecorator('approvalMethod', {
-                initialValue: data.approvalMethod || 'orsign'
-              })(
-                <Radio.Group>
-                  <Radio value="countersign">浼氱</Radio>
-                  <Radio value="orsign">鎴栫</Radio>
-                </Radio.Group>
-              )}
-            </Form.Item>
-          </Col> : null}
-          {nodetype === 'edge' ? <Col span={12}>
+          {options.includes('members') ? <Col span={12}>
             <Form.Item label="瀹℃壒浜�">
               {getFieldDecorator('members', {
                 initialValue: data.members || [],
-                rules: [{
-                  required: true,
-                  message: '璇锋坊鍔犲鎵逛汉!'
-                }]
+                rules: [
+                  { required: true, message: '璇锋坊鍔犲鎵逛汉!' }
+                ]
               })(
                 <MemberForm orgs={orgs} title="瀹℃壒浜�"/>
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' ? <Col span={12}>
+          {options.includes('copys') ? <Col span={12}>
             <Form.Item label="鎶勯�佷汉">
               {getFieldDecorator('copys', {
                 initialValue: data.copys || []
@@ -165,7 +227,10 @@
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' && flowType !== 'reject' ? <Col span={12}>
+          {options.includes('execCondition') && flowType !== 'reject' ? <Col span={24}>
+            <p className="mk-split">鍒嗘敮鎵ц鏉′欢</p>
+          </Col> : null}
+          {options.includes('execCondition') && flowType !== 'reject' ? <Col span={12}>
             <Form.Item label="鎵ц鏉′欢">
               {getFieldDecorator('execCondition', {
                 valuePropName: 'checked',
@@ -175,7 +240,7 @@
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' && flowType !== 'reject' && execCondition ? <Col span={12}>
+          {flowType !== 'reject' && execCondition ? <Col span={12}>
             <Form.Item label="瀵规瘮鏂瑰紡">
               {getFieldDecorator('match', {
                 initialValue: data.match || '='
@@ -191,7 +256,7 @@
               )}
             </Form.Item>
           </Col> : null}
-          {nodetype === 'edge' && flowType !== 'reject' && execCondition ? <Col span={12}>
+          {flowType !== 'reject' && execCondition ? <Col span={12}>
             <Form.Item label={
               <Tooltip placement="topLeft" title="瀵规瘮鍊间腑涓嶅彲鍖呭惈鍒惰〃绗︺�佺┖鏍笺�佹崲琛岀绛夈��">
                 <QuestionCircleOutlined className="mk-form-tip" />
@@ -201,19 +266,10 @@
               {getFieldDecorator('matchVal', {
                 initialValue: data.matchVal || ''
               })(
-                <Input placeholder="" autoComplete="off"/>
+                <Input autoComplete="off" onPressEnter={() => this.props.handleSubmit()}/>
               )}
             </Form.Item>
           </Col> : null}
-          <Col span={24}>
-            <Form.Item label="澶囨敞">
-              {getFieldDecorator('remark', {
-                initialValue: data.remark || ''
-              })(
-                <TextArea rows={2}/>
-              )}
-            </Form.Item>
-          </Col>
         </Row>
       </Form>
     )
diff --git a/src/tabviews/custom/components/chart/antv-bar-line/index.jsx b/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
index 75a01b7..38923d3 100644
--- a/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -3,7 +3,7 @@
 import { is, fromJS } from 'immutable'
 import { Chart } from '@antv/g2'
 import DataSet from '@antv/data-set'
-import { Spin, Empty, notification, Modal } from 'antd'
+import { Spin, Empty } from 'antd'
 import { DownloadOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -662,37 +662,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
index 15cf833..a9a530a 100644
--- a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { Chart, registerShape } from '@antv/g2'
-import { Spin, notification, Modal } from 'antd'
+import { Spin } from 'antd'
 // import { DownloadOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -368,37 +368,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/antv-pie/index.jsx b/src/tabviews/custom/components/chart/antv-pie/index.jsx
index 44ed1cc..bc32406 100644
--- a/src/tabviews/custom/components/chart/antv-pie/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -3,7 +3,7 @@
 import { is, fromJS } from 'immutable'
 import { Chart } from '@antv/g2'
 import DataSet, { DataView } from '@antv/data-set'
-import { Spin, Empty, notification, Modal } from 'antd'
+import { Spin, Empty } from 'antd'
 // import { DownloadOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -316,37 +316,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/antv-scatter/index.jsx b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
index f4751c8..891181e 100644
--- a/src/tabviews/custom/components/chart/antv-scatter/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { Chart } from '@antv/g2'
-import { Spin, Empty, notification, Modal } from 'antd'
+import { Spin, Empty } from 'antd'
 import { DownloadOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -347,37 +347,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/chart/custom-chart/index.jsx b/src/tabviews/custom/components/chart/custom-chart/index.jsx
index 1fcd7c8..747e2fc 100644
--- a/src/tabviews/custom/components/chart/custom-chart/index.jsx
+++ b/src/tabviews/custom/components/chart/custom-chart/index.jsx
@@ -4,7 +4,7 @@
 import { Chart } from '@antv/g2'
 import DataSet from '@antv/data-set'
 import * as echarts from 'echarts'
-import { Spin, Empty, notification, Modal } from 'antd'
+import { Spin, Empty, notification } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -340,37 +340,15 @@
           this.timer && this.timer.stop()
         }
       }
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/code/sand-box/index.jsx b/src/tabviews/custom/components/code/sand-box/index.jsx
index bc158d3..c460bcc 100644
--- a/src/tabviews/custom/components/code/sand-box/index.jsx
+++ b/src/tabviews/custom/components/code/sand-box/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Modal } from 'antd'
+import { Spin, notification } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -261,36 +261,14 @@
         loading: false
       })
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
 
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/editor/braft-editor/index.jsx b/src/tabviews/custom/components/editor/braft-editor/index.jsx
index ccb80cd..0b6db75 100644
--- a/src/tabviews/custom/components/editor/braft-editor/index.jsx
+++ b/src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Modal } from 'antd'
+import { Spin } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
 import Api from '@/api'
@@ -211,37 +211,14 @@
         data: _data,
         loading: false
       })
-
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/form/simple-form/index.jsx b/src/tabviews/custom/components/form/simple-form/index.jsx
index b9928e1..9954a82 100644
--- a/src/tabviews/custom/components/form/simple-form/index.jsx
+++ b/src/tabviews/custom/components/form/simple-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Modal, Button } from 'antd'
+import { Spin, Button } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -387,36 +387,13 @@
 
       MKEmitter.emit('resetSelectLine', config.uuid, _data.$$uuid, _data)
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false,
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/form/step-form/index.jsx b/src/tabviews/custom/components/form/step-form/index.jsx
index b22dba9..50e227b 100644
--- a/src/tabviews/custom/components/form/step-form/index.jsx
+++ b/src/tabviews/custom/components/form/step-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Button, Modal } from 'antd'
+import { Spin, Button } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -405,36 +405,13 @@
 
       MKEmitter.emit('resetSelectLine', config.uuid, _data.$$uuid, _data)
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false,
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/form/tab-form/index.jsx b/src/tabviews/custom/components/form/tab-form/index.jsx
index da36b3c..15fe9d4 100644
--- a/src/tabviews/custom/components/form/tab-form/index.jsx
+++ b/src/tabviews/custom/components/form/tab-form/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Modal } from 'antd'
+import { Spin } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -339,36 +339,13 @@
 
       MKEmitter.emit('resetSelectLine', config.uuid, _data.$$uuid, _data)
       
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false,
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index 5a87122..3868f59 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
@@ -8,23 +9,32 @@
 
 class NormalGroup extends Component {
   static propTpyes = {
-    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    config: PropTypes.object
   }
 
-  state = {}
+  state = {
+    visible: true,
+    mergeAble: this.props.config.setting.mergeAble === 'true'
+  }
 
   render() {
-    const { config } = this.props
+    const { config, style } = this.props
+    const { visible, mergeAble } = this.state
 
-    if (config.components.length === 0) return (<div style={config.style}></div>)
+    if (config.components.length === 0) return (<div className={'ant-col ant-col-' + config.width} style={style}><div style={config.style}></div></div>)
     
     return (
-      <div className={'normal-group-wrap ' + (config.setting.layout || '')} id={'anchor' + config.uuid} style={config.style}>
-        {config.setting && config.setting.title ? <div className="group-header" style={config.headerStyle}>
-          <span className="title">{config.setting.title}</span>
-        </div> : null}
-        <TabTransfer config={config}/>
-        {/* <Row className="component-wrap">{this.getComponents()}</Row> */}
+      <div className={`ant-col ant-col-${config.width} ${mergeAble ? ' mk-merge-able mk-ctrl-' + (config.setting.ctrlNumber || 1) : ''} ${visible ? '' : ' close'}`} style={style}>
+        <div className={'normal-group-wrap ' + (config.setting.layout || '')} id={'anchor' + config.uuid} style={config.style}>
+          <div className="mk-control">
+            <DoubleLeftOutlined onClick={() => this.setState({visible: false})}/>
+            <DoubleRightOutlined onClick={() => this.setState({visible: true})}/>
+          </div>
+          {config.setting && config.setting.title ? <div className="group-header" style={config.headerStyle}>
+            <span className="title">{config.setting.title}</span>
+          </div> : null}
+          <TabTransfer config={config}/>
+        </div>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/group/normal-group/index.scss b/src/tabviews/custom/components/group/normal-group/index.scss
index 3869386..a67276f 100644
--- a/src/tabviews/custom/components/group/normal-group/index.scss
+++ b/src/tabviews/custom/components/group/normal-group/index.scss
@@ -13,11 +13,28 @@
       text-decoration: inherit;
       font-weight: inherit;
       font-style: inherit;
+      font-family: inherit;
       float: left;
       line-height: inherit;
       margin-left: 10px;
       position: relative;
       z-index: 1;
+    }
+  }
+
+  .mk-control {
+    display: none;
+    position: absolute;
+    top: 0px;
+    right: 0px;
+    z-index: 2;
+    background: #ffffff;
+    box-shadow: 0px 0px 2px #d8d8d8;
+    transition: all 0.2s;
+
+    .anticon {
+      padding: 5px;
+      cursor: pointer;
     }
   }
 }
@@ -37,4 +54,90 @@
       width: 5%;
     }
   }
+}
+
+.mk-merge-able {
+  transition: all 0.2s;
+
+  .normal-group-wrap {
+    position: relative;
+    transition: all 0.2s;
+  }
+  .mk-control {
+    display: inline-block;
+
+    .anticon-double-left {
+      display: inline-block;
+    }
+    .anticon-double-right {
+      display: none;
+    }
+  }
+}
+
+.mk-merge-able.close {
+  width: 25px;
+  .normal-group-wrap {
+    width: 0px;
+    margin: 0px!important;
+    border-width: 0px!important;
+    box-shadow: none!important;
+  }
+  .mk-control {
+    display: inline-block;
+    right: -24px;
+
+    .anticon-double-left {
+      display: none;
+    }
+    .anticon-double-right {
+      display: inline-block;
+    }
+  }
+}
+
+.mk-merge-able + .ant-col,
+.mk-merge-able + .ant-col + .ant-col,
+.mk-merge-able + .ant-col + .ant-col + .ant-col,
+.mk-merge-able + .ant-col + .ant-col + .ant-col + .ant-col,
+.mk-merge-able + .ant-col + .ant-col + .ant-col + .ant-col + .ant-col {
+  transition: all 0.2s;
+}
+
+.mk-merge-able.close + .ant-col {
+  width: calc(100% - 25px);
+}
+
+.mk-merge-able.close.mk-ctrl-2 + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+
+.mk-merge-able.close.mk-ctrl-3 + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-3 + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+
+.mk-merge-able.close.mk-ctrl-4 + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-4 + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-4 + .ant-col + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+
+.mk-merge-able.close.mk-ctrl-5 + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-5 + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-5 + .ant-col + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
+}
+.mk-merge-able.close.mk-ctrl-5 + .ant-col + .ant-col + .ant-col + .ant-col + .ant-col {
+  width: calc(100% - 25px);
 }
\ No newline at end of file
diff --git a/src/tabviews/custom/components/iframe/index.jsx b/src/tabviews/custom/components/iframe/index.jsx
index 3737715..7e544be 100644
--- a/src/tabviews/custom/components/iframe/index.jsx
+++ b/src/tabviews/custom/components/iframe/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Input, Modal, notification, Empty, Spin } from 'antd'
+import { Input, Empty, Spin } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -212,32 +212,9 @@
         data: _data
       })
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/iframe/index.scss b/src/tabviews/custom/components/iframe/index.scss
index 3e97448..d24ee24 100644
--- a/src/tabviews/custom/components/iframe/index.scss
+++ b/src/tabviews/custom/components/iframe/index.scss
@@ -22,6 +22,7 @@
       font-weight: inherit;
       font-style: inherit;
       line-height: inherit;
+      font-family: inherit;
       margin-left: 10px;
       position: relative;
       z-index: 1;
diff --git a/src/tabviews/custom/components/interfaces/interItem/index.jsx b/src/tabviews/custom/components/interfaces/interItem/index.jsx
index 185a5a6..87e0bd9 100644
--- a/src/tabviews/custom/components/interfaces/interItem/index.jsx
+++ b/src/tabviews/custom/components/interfaces/interItem/index.jsx
@@ -1,6 +1,5 @@
 import {Component} from 'react'
 import PropTypes from 'prop-types'
-import { notification, Modal } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -153,39 +152,16 @@
         MKEmitter.emit('interFinish', config.MenuID, config.uuid)
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.loading = false
       this.timer && this.timer.stop()
-      
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
 
       if (config.setting.loadlevel === 'init') {
         MKEmitter.emit('interFinish', config.MenuID, config.uuid)
       }
+
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/module/account/index.jsx b/src/tabviews/custom/components/module/account/index.jsx
index 234db66..eec9ca5 100644
--- a/src/tabviews/custom/components/module/account/index.jsx
+++ b/src/tabviews/custom/components/module/account/index.jsx
@@ -81,6 +81,9 @@
         map.set(item.id, true)
 
         if (item.selected === 'true' && !activeItem) {
+          if (res.invoice_type) {
+            item.invoice_type = res.invoice_type.map(cell => ({value: cell.invoice_type_code, label: cell.invoice_type_name}))
+          }
           activeItem = item
         }
         if (item.months) {
diff --git a/src/tabviews/custom/components/module/account/index.scss b/src/tabviews/custom/components/module/account/index.scss
index 1821b31..68b9ba8 100644
--- a/src/tabviews/custom/components/module/account/index.scss
+++ b/src/tabviews/custom/components/module/account/index.scss
@@ -8,8 +8,7 @@
   color: #000000;
 
   .ant-select {
-    min-width: 250px;
-    max-width: 300px;
+    width: 270px;
     color: #000000;
   }
 
diff --git a/src/tabviews/custom/components/module/invoice/index.jsx b/src/tabviews/custom/components/module/invoice/index.jsx
new file mode 100644
index 0000000..363794d
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/index.jsx
@@ -0,0 +1,757 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Select, Form, Input, Button, Modal, Spin, notification } from 'antd'
+import { EllipsisOutlined } from '@ant-design/icons'
+import moment from 'moment'
+
+import Api from '@/api'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import InvoiceTable from './invoiceTable'
+import SubTable from './subTable'
+import './index.scss'
+
+class InvoiceModule extends Component {
+  static propTpyes = {
+    config: PropTypes.object
+  }
+
+  state = {
+    BID: '',
+    ID: Utils.getuuid(),
+    io: '',
+    invTypes: [
+      {value: '1', label: '鐢靛瓙鍙戠エ锛堝鍊肩◣涓撶敤鍙戠エ锛�'},
+      {value: '2', label: '鐢靛瓙鍙戠エ锛堟櫘閫氬彂绁級'},
+      {value: '3', label: '澧炲�肩◣绾歌川涓撶敤鍙戠エ'},
+      {value: '4', label: '澧炲�肩◣绾歌川鏅�氬彂绁�'},
+      {value: '5', label: '澧炲�肩◣鐢靛瓙鏅�氬彂绁�'},
+      {value: '6', label: '澧炲�肩◣鐢靛瓙涓撶敤鍙戠エ'},
+    ],
+    invoice_type: '',
+    date: moment().format('YYYY骞碝M鏈圖D鏃�'),
+    from_to_name: '',
+    from_to_tax_no: '',
+    from_to_addr: '',
+    from_to_tel: '',
+    from_to_bank_name: '',
+    from_to_account_no: '',
+    from_to_mob: '',
+    from_to_email: '',
+    from_to_code: '',
+    orgname: '',
+    tax_no: '',
+    addr: '',
+    tel: '',
+    bank_name: '',
+    account_no: '',
+    remark: '',
+    payee: '',
+    reviewer: '',
+    drawer: '',
+    details: [],
+    oriDetails: [],
+    book: null,
+    loading: false,
+    saveType: '',
+    tax_type: '',
+    reqfields: [],
+    requireds: []
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    let _config = fromJS(config).toJS()
+    let BID = ''
+    let BData = ''
+
+    if (_config.setting.supModule) {
+      BData = window.GLOB.CacheData.get(_config.setting.supModule)
+    } else {
+      BData = window.GLOB.CacheData.get(_config.$pageId)
+    }
+    if (BData) {
+      BID = BData.$BID || ''
+    }
+
+    if (_config.wrap.invColor) {
+      _config.style['--inv-color'] = _config.wrap.invColor
+    }
+
+    _config.buyer = this.formatSetting(_config.buyer, 'buyer')
+    _config.detail = this.formatSetting(_config.detail, 'detail')
+
+    let book = null
+    let pas = {}
+    if (config.wrap.supBook) {
+      book = window.GLOB.CacheData.get(config.wrap.supBook) || null
+
+      if (book) {
+        pas = this.resetParam(book)
+      }
+    }
+
+    this.setState({
+      BID: BID || '',
+      config: _config,
+      book,
+      ...pas
+    })
+  }
+
+  componentDidMount () {
+    const { config } = this.props
+
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+
+    if (config.wrap.datatype === 'dynamic' && config.setting.onload === 'true') {
+      setTimeout(() => {
+        this.loadData()
+      }, config.setting.delay || 0)
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+  }
+
+  formatSetting = (item, type) => {
+    item.setting.arr_field = item.columns.map(col => col.field).join(',')
+    item.setting.laypage = item.setting.laypage === 'true'
+
+    if (type === 'buyer') {
+      item.columns = item.columns.map(cell => {
+        if (['from_to_tel', 'from_to_account_no', 'from_to_code'].includes(cell.field)) {
+          cell.Hide = 'true'
+        } else if (['from_to_email', 'from_to_mob'].includes(cell.field)) {
+          cell.Width = 80
+        }
+        return cell
+      })
+    } else {
+      item.columns = item.columns.map(cell => {
+        if (cell.field === 'general_tax_rate') {
+          cell.field = 'tax_rate'
+          cell.label = '绋庣巼'
+        }
+        if (['Description', 'id', 'small_tax_rate', 'free_tax_mark', 'vat_special_management'].includes(cell.field)) {
+          cell.Hide = 'true'
+        } else if (['spec'].includes(cell.field)) {
+          cell.Width = 150
+        } else if (['unit', 'unitprice', 'tax_rate'].includes(cell.field)) {
+          cell.Width = 80
+        }
+
+        return cell
+      })
+    }
+
+    if (item.setting.interType !== 'system') {
+      item.setting.dataresource = ''
+      return item
+    }
+
+    let regs = [
+      { reg: /@userName@/ig, value: `'${sessionStorage.getItem('User_Name') || ''}'` },
+      { reg: /@fullName@/ig, value: `'${sessionStorage.getItem('Full_Name') || ''}'` }
+    ]
+    
+    if (window.GLOB.externalDatabase !== null) {
+      regs.push({
+        reg: /@db@/ig,
+        value: window.GLOB.externalDatabase
+      })
+    }
+
+    let _customScript = ''
+    let _tailScript = ''
+    item.scripts && item.scripts.forEach(script => {
+      if (script.status === 'false') return
+      if (script.position !== 'back') {
+        _customScript += `
+        ${script.sql}
+        `
+      } else {
+        _tailScript += `
+        ${script.sql}
+        `
+      }
+    })
+    delete item.scripts
+
+    item.setting.execute = item.setting.execute !== 'false'
+    
+    if (!item.setting.execute) {
+      item.setting.dataresource = ''
+    }
+    if (/\s/.test(item.setting.dataresource)) {
+      item.setting.dataresource = '(' + item.setting.dataresource + ') tb'
+    }
+
+    if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
+      item.setting.dataresource = item.setting.dataresource.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
+      _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
+      _tailScript = _tailScript.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, '\'Y\'')
+    } else {
+      item.setting.dataresource = item.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
+      _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
+      _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
+    }
+
+    regs.forEach(cell => {
+      item.setting.dataresource = item.setting.dataresource.replace(cell.reg, cell.value)
+      _customScript = _customScript.replace(cell.reg, cell.value)
+      _tailScript = _tailScript.replace(cell.reg, cell.value)
+    })
+
+    item.setting.customScript = _customScript // 鏁寸悊鍚庤嚜瀹氫箟鑴氭湰
+    item.setting.tailScript = _tailScript     // 鍚庣疆鑷畾涔夎剼鏈�
+
+    item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
+
+    return item
+  }
+
+  resetParentParam = (MenuID, id, data) => {
+    const { config } = this.state
+
+    if (config.wrap.supBook === MenuID) {
+      let pas = this.resetParam(data)
+
+      this.setState({ book: data, ...pas }, () => {
+        this.loadData()
+      })
+      return
+    }
+
+    if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
+    if (id !== this.state.BID || id !== '') {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  resetParam = (book) => {
+    let invTypes = book.invoice_type || []
+    let invoice_type = sessionStorage.getItem('pre_invoice_type') || ''
+    if (invoice_type && invTypes.findIndex(item => item.value === invoice_type) === -1) {
+      invoice_type = ''
+    }
+
+    this.getRequired(invoice_type)
+
+    return {
+      invoice_type,
+      invTypes: invTypes,
+      orgname: book.orgname || '',
+      tax_no: book.tax_no || '',
+      addr: book.addr || '',
+      tel: book.tel || '',
+      bank_name: book.bank_name || '',
+      account_no: book.account_no || '',
+      payee: book.payee || '',
+      reviewer: book.reviewer || '',
+      drawer: book.drawer || '',
+      tax_type: book.tax_type || ''
+    }
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+    
+    if (config.uuid !== menuId) return
+
+    this.loadData()
+  }
+
+  async loadData() {
+    const { config, BID } = this.state
+
+    if (config.wrap.datatype !== 'dynamic') return
+
+    let param = UtilsDM.getQueryDataParams(config.setting, [], config.setting.order, 1, 1, BID)
+
+    this.setState({
+      loading: true
+    })
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+
+      this.setState({
+        ID: result.data[0][config.setting.primaryKey] || Utils.getuuid(),
+        io: '',
+        details: [],
+        oriDetails: [],
+        loading: false
+      })
+
+      UtilsDM.querySuccess(result)
+    } else {
+      this.setState({
+        loading: false
+      })
+      this.timer && this.timer.stop()
+
+      UtilsDM.queryFail(result)
+    }
+  }
+
+  changeType = (val) => {
+    sessionStorage.setItem('pre_invoice_type', val)
+    this.setState({invoice_type: val})
+    this.getRequired(val)
+  }
+
+  getRequired = (invoice_type) => {
+    if (!invoice_type) return
+
+    let reqfields = []
+    let requireds = []
+    let rds = [
+      {value: 'from_to_name', label: '璐拱鏂瑰悕绉�'},
+      {value: 'from_to_tax_no', label: '璐拱鏂圭撼绋庝汉璇嗗埆鍙�'},
+      {value: 'from_to_addr', label: '璐拱鏂瑰湴鍧�'},
+      {value: 'from_to_tel', label: '璐拱鏂圭數璇�'},
+      {value: 'from_to_bank_name', label: '璐拱鏂瑰紑鎴疯'},
+      {value: 'from_to_account_no', label: '璐拱鏂硅处鍙�'},
+      {value: 'from_to_mob', label: '璐拱鏂规墜鏈哄彿'},
+      {value: 'from_to_email', label: '璐拱鏂归偖绠�'},
+
+      {value: 'orgname', label: '閿�鍞柟鍚嶇О'},
+      {value: 'tax_no', label: '閿�鍞柟绾崇◣浜鸿瘑鍒彿'},
+      {value: 'addr', label: '閿�鍞柟鍦板潃'},
+      {value: 'tel', label: '閿�鍞柟鐢佃瘽'},
+      {value: 'bank_name', label: '閿�鍞柟寮�鎴疯'},
+      {value: 'account_no', label: '閿�鍞柟璐﹀彿'},
+    ]
+    if (invoice_type === 'e_general') {
+      reqfields = ['from_to_name', 'from_to_tax_no', 'orgname', 'tax_no']
+      rds.forEach(item => {
+        if (reqfields.includes(item.value)) {
+          requireds.push(item)
+        }
+      })
+    } else if (invoice_type === 'e_special') {
+      reqfields = ['from_to_name', 'from_to_tax_no', 'from_to_addr', 'from_to_tel', 'from_to_bank_name', 'from_to_account_no', 'orgname', 'tax_no', 'addr', 'tel', 'bank_name', 'account_no']
+      rds.forEach(item => {
+        if (reqfields.includes(item.value)) {
+          requireds.push(item)
+        }
+      })
+    }
+    
+    this.setState({
+      reqfields,
+      requireds
+    })
+  }
+
+  saveBill = () => {
+    const { config, book, saveType } = this.state
+
+    if (saveType) return
+
+    setTimeout(() => {
+      this.getBillMsg().then(() => {
+        let sql = this.getPreSql(config.billSaveBtn)
+  
+        let param = {
+          func: 'sPC_TableData_InUpDe',
+          LText: sql,
+          exec_type: window.GLOB.execType || 'y',
+          timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+          BID: book.id
+        }
+  
+        param.secretkey = Utils.encrypt('', param.timestamp)
+        param.LText = Utils.formatOptions(param.LText, param.exec_type)
+
+        this.setState({
+          saveType: 'bill'
+        })
+
+        Api.genericInterface(param).then(res => {
+          if (res.status) {
+            notification.success({
+              top: 92,
+              message: '淇濆瓨鎴愬姛銆�',
+              duration: 5
+            })
+          } else {
+            notification.warning({
+              top: 92,
+              message: res.message,
+              duration: 5
+            })
+          }
+          this.setState({
+            saveType: ''
+          })
+        })
+      }, (error) => {
+        notification.warning({
+          top: 92,
+          message: error,
+          duration: 5
+        })
+        return
+      })
+    }, 20)
+  }
+
+  outBill = () => {
+    const { config, book, saveType } = this.state
+
+    if (saveType) return
+
+    setTimeout(() => {
+      this.getBillMsg().then(() => {
+        let sql = this.getPreSql(config.billOutBtn)
+  
+        let param = {
+          func: 'sPC_TableData_InUpDe',
+          LText: sql,
+          key_back_type: 'Y',
+          exec_type: window.GLOB.execType || 'y',
+          timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+          BID: book.id
+        }
+  
+        param.secretkey = Utils.encrypt('', param.timestamp)
+        param.LText = Utils.formatOptions(param.LText, param.exec_type)
+
+        console.info(sql)
+      }, (error) => {
+        notification.warning({
+          top: 92,
+          message: error,
+          duration: 5
+        })
+        return
+      })
+    })
+  }
+
+  getPreSql = (btn) => {
+    const { book, ID, io, details, oriDetails, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, from_to_code, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee } = this.state
+
+    let BID = book.id
+    let userName = sessionStorage.getItem('User_Name') || '' 
+    let fullName = sessionStorage.getItem('Full_Name') || ''
+    let RoleID = sessionStorage.getItem('role_id') || ''
+    let departmentcode = sessionStorage.getItem('departmentcode') || ''
+    let organization = sessionStorage.getItem('organization') || ''
+    let mk_user_type = sessionStorage.getItem('mk_user_type') || ''
+    let nation = sessionStorage.getItem('nation') || ''
+    let province = sessionStorage.getItem('province') || ''
+    let city = sessionStorage.getItem('city') || ''
+    let district = sessionStorage.getItem('district') || ''
+    let address = sessionStorage.getItem('address') || ''
+    let options = fromJS(oriDetails).toJS()
+    let price = 0
+    let tax = 0
+
+    let lines = details.map(line => {
+      let _sql = `Select '${line.productcode}', '${line.productname}', '${line.spec}', '${line.unit}', ${line.bill_count}, ${line.unitprice}, ${line.amount_line}, '${line.tax_classify_code}', '${line.tax_classify_name}', ${line.tax_rate}, ${line.tax_amount}, '${line.free_tax_mark || ''}', '${line.vat_special_management || ''}', '${line.invoice_lp || ''}', '${line.uuid}'`
+      let data_type = 'add'
+
+      price += line.amount_line * 100
+      tax += line.tax_amount * 100
+
+      if (options.length) {
+        options = options.filter(option => {
+          if (option.uuid === line.uuid) {
+            data_type = 'upt'
+            return false
+          }
+          return true
+        })
+      }
+
+      return _sql + `, '${data_type}'`
+    })
+
+    let _total = (price - tax) / 100
+    price = price / 100
+    tax = tax / 100
+
+    if (options.length) {
+      options.forEach(line => {
+        lines.push(`Select '${line.productcode}', '${line.productname}', '${line.spec}', '${line.unit}', ${line.bill_count}, ${line.unitprice}, ${line.amount_line}, '${line.tax_classify_code}', '${line.tax_classify_name}', ${line.tax_rate}, ${line.tax_amount}, '${line.free_tax_mark || ''}', '${line.vat_special_management || ''}', '${line.invoice_lp || ''}', '${line.uuid}', 'del'`)
+      })
+    }
+
+    lines = lines.join(' union all ')
+
+    let _script = ''
+    btn.scripts.forEach(item => {
+      if (item.status === 'false') return
+      _script += `
+      ${item.sql}
+      `
+    })
+
+    let sql = `/* 绯荤粺瀛楁 */
+      Declare @UserName nvarchar(50), @FullName nvarchar(50), @RoleID nvarchar(512), @mk_departmentcode nvarchar(512), @mk_organization nvarchar(512), @mk_user_type nvarchar(20), @mk_nation nvarchar(50), @mk_province nvarchar(50), @mk_city nvarchar(50), @mk_district nvarchar(50), @mk_address nvarchar(100), @ErrorCode nvarchar(50), @retmsg nvarchar(4000), @account_id nvarchar(50), @account_year_id nvarchar(50), @account_code nvarchar(50), @account_year_code nvarchar(50), @bid nvarchar(50), @tbid nvarchar(50)
+
+      Select @UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}', @ErrorCode='', @retmsg='', @account_id='${book.account_id || ''}', @account_year_id='${book.account_year_id || ''}', @account_code='${book.account_code || ''}', @account_year_code='${book.account_year_code || ''}', @bid=''
+
+      /* 鍙戠エ涓昏〃瀛楁 */
+      Declare @invoice_type Nvarchar(50), @from_to_name Nvarchar(50), @from_to_tax_no Nvarchar(50), @from_to_addr Nvarchar(100), @from_to_tel Nvarchar(50), @from_to_bank_name Nvarchar(50), @from_to_account_no Nvarchar(50), @from_to_mob Nvarchar(50), @from_to_email Nvarchar(50), @from_to_code Nvarchar(50), @orgname Nvarchar(50), @tax_no Nvarchar(50), @addr Nvarchar(100), @tel Nvarchar(50), @bank_name Nvarchar(50), @account_no Nvarchar(50), @remark Nvarchar(512), @payee Nvarchar(50), @reviewer Nvarchar(50), @drawer Nvarchar(50), @io Nvarchar(50), @orgcode Nvarchar(50), @total_net_amount Decimal(18,2), @total_tax Decimal(18,2), @total_amount Decimal(18,2)
+
+      Select @invoice_type='${invoice_type}', @from_to_name='${from_to_name}', @from_to_tax_no='${from_to_tax_no}', @from_to_addr='${from_to_addr}', @from_to_tel='${from_to_tel}', @from_to_bank_name='${from_to_bank_name}', @from_to_account_no='${from_to_account_no}', @from_to_mob='${from_to_mob}', @from_to_email='${from_to_email}', @from_to_code='${from_to_code}', @orgname='${orgname}', @tax_no='${tax_no}', @addr='${addr}', @tel='${tel}', @bank_name='${bank_name}', @account_no='${account_no}', @remark='${remark}', @payee='${payee}', @reviewer='${reviewer}', @drawer='${drawer}', @io='${io}', @orgcode='${book.orgcode || ''}', @total_net_amount=${_total}, @total_tax=${tax}, @total_amount=${price}
+
+      /* 鍙戠エ鏄庣粏涓存椂琛� */
+
+      Declare @details_list table (productcode Nvarchar(50), productname Nvarchar(50), spec Nvarchar(50), unit Nvarchar(50), bill_count Decimal(18,10), unitprice Decimal(18,10), amount_line Decimal(18,2), tax_classify_code Nvarchar(50), tax_classify_name Nvarchar(50), tax_rate Decimal(18,2), tax_amount Decimal(18,2), free_tax_mark Nvarchar(50), vat_special_management Nvarchar(50), invoice_lp Nvarchar(50), jskey Nvarchar(50), data_type Nvarchar(50))
+
+      Insert into @details_list (productcode, productname, spec, unit, bill_count, unitprice, amount_line, tax_classify_code, tax_classify_name, tax_rate, tax_amount, free_tax_mark, vat_special_management, invoice_lp, jskey, data_type)
+
+      ${lines}
+
+      /* 鑷畾涔夎剼鏈� */
+      ${_script}
+
+      aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
+
+    sql = sql.replace(/@ID@/ig, `'${ID}'`)
+    sql = sql.replace(/@BID@/ig, `'${BID}'`)
+    sql = sql.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
+    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
+    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
+    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    sql = sql.replace(/@typename@/ig, `'admin'`)
+
+    if (window.GLOB.externalDatabase !== null) {
+      sql = sql.replace(/@db@/ig, window.GLOB.externalDatabase)
+    }
+
+    if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
+      sql = sql.replace(/\$@/ig, '/*').replace(/@\$/ig, '*/').replace(/@datam@/ig, `'Y'`)
+    } else {
+      sql = sql.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, `''`)
+    }
+
+    if (window.GLOB.debugger === true) {
+      console.info(sql.replace(/\n\s{6}/ig, '\n'))
+    }
+
+    return sql
+  }
+
+  getBillMsg = () => {
+    const { requireds, invoice_type, details, remark, from_to_addr, addr } = this.state
+
+    return new Promise((resolve, reject) => {
+      let error = ''
+
+      if (!invoice_type) {
+        error = '璇烽�夋嫨鍙戠エ绫诲瀷锛�'
+      }
+      
+      if (!error) {
+        requireds.forEach(item => {
+          if (!this.state[item.value] && !error) {
+            error = '璇疯緭鍏�' + item.label + '锛�'
+          }
+        })
+      }
+
+      if (!error && remark.length > 512) {
+        error = '澶囨敞涓嶅彲瓒呰繃512涓瓧绗︼紒'
+      }
+      if (!error && from_to_addr.length > 100) {
+        error = '璐拱鏂瑰湴鍧�涓嶅彲瓒呰繃100涓瓧绗︼紒'
+      }
+      if (!error && addr.length > 100) {
+        error = '閿�鍞柟鍦板潃涓嶅彲瓒呰繃100涓瓧绗︼紒'
+      }
+
+      if (!error) {
+        if (details.length === 0) {
+          error = '璇锋坊鍔犳槑缁嗭紒'
+        } else {
+          details.forEach((line, index) => {
+            if (error) return
+            if (line.productcode) {
+              if (!line.bill_count) {
+                error = '鏄庣粏绗�' + (index + 1) + '琛岋紝璇疯緭鍏ユ暟閲忥紒'
+              } else if (!line.unitprice) {
+                error = '鏄庣粏绗�' + (index + 1) + '琛岋紝璇疯緭鍏ュ崟浠凤紒'
+              }
+            } else {
+              error = '鏄庣粏绗�' + (index + 1) + '琛岋紝璇烽�夋嫨璐х墿鎴栧簲绋庡姵鍔°�佹湇鍔″悕绉帮紒'
+            }
+          })
+        }
+      }
+
+      if (error) {
+        reject(error)
+      } else {
+        resolve()
+      }
+    })
+  }
+
+  changeBuyer = (item) => {
+    this.setState({
+      visible: false,
+      from_to_name: item.from_to_name || '',
+      from_to_tax_no: item.from_to_tax_no || '',
+      from_to_addr: item.from_to_addr || '',
+      from_to_tel: item.from_to_tel || '',
+      from_to_bank_name: item.from_to_bank_name || '',
+      from_to_account_no: item.from_to_account_no || '',
+      from_to_mob: item.from_to_mob || '',
+      from_to_email: item.from_to_email || '',
+      from_to_code: item.from_to_code || '',
+    })
+  }
+
+  render() {
+    const { config, book, loading, invTypes, reqfields, saveType, date, invoice_type, from_to_name, from_to_tax_no, from_to_addr, from_to_tel, from_to_bank_name, from_to_account_no, from_to_mob, from_to_email, orgname, tax_no, addr, tel, bank_name, account_no, remark, reviewer, drawer, payee, details, visible, tax_type } = this.state
+
+    if (!book || (config.wrap.datatype === 'dynamic' && !tax_no)) {
+      return <div className="menu-invoice-wrap" style={config.style}>
+        <div className="loading-mask">
+          <div className="ant-spin-blur"></div>
+          <Spin />
+        </div>
+      </div>
+    }
+
+    return (
+      <div className="menu-invoice-wrap" style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        <div className="inv-action">
+          <Button className="mk-bill" loading={saveType === 'bill'} onClick={this.saveBill}>淇濆瓨鍗曟嵁</Button>
+          <Button className="mk-submit" loading={saveType === 'out'} onClick={this.outBill}>鎻愪氦寮�绁�</Button>
+        </div>
+        <div className="inv-header">
+          {invoice_type ? <Select defaultValue={invoice_type} onChange={this.changeType} dropdownClassName="inv-type-select">
+            {invTypes.map(item => (
+              <Select.Option key={item.value} value={item.value}>{item.label}</Select.Option>
+            ))}
+          </Select> : <Select placeholder="璇烽�夋嫨鍙戠エ绉嶇被" onChange={this.changeType} dropdownClassName="inv-type-select">
+            {invTypes.map(item => (
+              <Select.Option key={item.value} value={item.value}>{item.label}</Select.Option>
+            ))}
+          </Select>}
+          <div className="date">寮�绁ㄦ棩鏈燂細{date}</div>
+        </div>
+        <div className="inv-body">
+          <div className="inv-main-content">
+            <div className="inv-buyer">
+              <div className="inv-label">璐拱鏂�</div>
+              <div className="inv-content">
+                <Form.Item required={reqfields.includes('from_to_name')} label={<>鍚�<span></span>绉�</>} extra={<EllipsisOutlined onClick={() => this.setState({visible: true})}/>}>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟鍚嶇О" allowClear value={from_to_name} autoComplete="off" onChange={(e) => this.setState({from_to_name: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('from_to_tax_no')} label="绾崇◣浜鸿瘑鍒彿">
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟绾崇◣浜鸿瘑鍒彿" allowClear value={from_to_tax_no} autoComplete="off" onChange={(e) => this.setState({from_to_tax_no: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('from_to_addr')} className="mutil-input" label={<>鍦�<span></span>鍧�<span></span>銆�<span></span>鐢�<span></span>璇�</>}>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟鍦板潃" allowClear value={from_to_addr} autoComplete="off" onChange={(e) => this.setState({from_to_addr: e.target.value})}/>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟鐢佃瘽" allowClear value={from_to_tel} autoComplete="off" onChange={(e) => this.setState({from_to_tel: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('from_to_bank_name')} className="mutil-input" label="寮�鎴疯鍙婅处鍙�">
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟寮�鎴疯" allowClear value={from_to_bank_name} autoComplete="off" onChange={(e) => this.setState({from_to_bank_name: e.target.value})}/>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟璐﹀彿" allowClear value={from_to_account_no} autoComplete="off" onChange={(e) => this.setState({from_to_account_no: e.target.value})}/>
+                </Form.Item>
+              </div>
+            </div>
+            <div className="inv-notice">
+              <div className="inv-label">閫氱煡鍒�</div>
+              <div className="inv-content">
+                <Form.Item required={reqfields.includes('from_to_mob')} label={<>鎵�<span></span>鏈�<span></span>鍙�</>}>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟鎵嬫満鍙�" allowClear value={from_to_mob} autoComplete="off" onChange={(e) => this.setState({from_to_mob: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('from_to_email')} label={<>閭�<span></span>绠�</>}>
+                  <Input placeholder="璇疯緭鍏ヨ喘涔版柟閭" allowClear value={from_to_email} autoComplete="off" onChange={(e) => this.setState({from_to_email: e.target.value})}/>
+                </Form.Item>
+              </div>
+            </div>
+          </div>
+          <div className="inv-details">
+            <InvoiceTable data={details} config={config.detail} tax_type={tax_type} onChange={(details) => this.setState({details})}/>
+          </div>
+          <div className="inv-main-content">
+            <div className="inv-buyer">
+              <div className="inv-label">閿�鍞柟</div>
+              <div className="inv-content">
+                <Form.Item required={reqfields.includes('orgname')} label={<>鍚�<span></span>绉�</>}>
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟鍚嶇О" value={orgname} autoComplete="off" onChange={(e) => this.setState({orgname: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('tax_no')} label="绾崇◣浜鸿瘑鍒彿">
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟绾崇◣浜鸿瘑鍒彿" disabled value={tax_no} autoComplete="off"/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('addr')} className="mutil-input" label={<>鍦�<span></span>鍧�<span></span>銆�<span></span>鐢�<span></span>璇�</>}>
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟鍦板潃" value={addr} autoComplete="off" onChange={(e) => this.setState({addr: e.target.value})}/>
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟鐢佃瘽" value={tel} autoComplete="off" onChange={(e) => this.setState({tel: e.target.value})}/>
+                </Form.Item>
+                <Form.Item required={reqfields.includes('bank_name')} className="mutil-input" label="寮�鎴疯鍙婅处鍙�">
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟寮�鎴疯" value={bank_name} autoComplete="off" onChange={(e) => this.setState({bank_name: e.target.value})}/>
+                  <Input placeholder="璇疯緭鍏ラ攢鍞柟璐﹀彿" value={account_no} autoComplete="off" onChange={(e) => this.setState({account_no: e.target.value})}/>
+                </Form.Item>
+              </div>
+            </div>
+            <div className="inv-notice">
+              <div className="inv-label">澶囨敞</div>
+              <div className="inv-content" style={{paddingTop: '30px'}}>
+                <Form.Item label="">
+                  <Input.TextArea placeholder="璇疯緭鍏ュ娉�" autoSize={{ minRows: 4, maxRows: 4 }} value={remark} autoComplete="off" onChange={(e) => this.setState({remark: e.target.value})}/>
+                </Form.Item>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div className="inv-tail">
+          <Form.Item label="鏀舵浜�">
+            <Input placeholder="鏀舵浜�" value={payee} autoComplete="off" onChange={(e) => this.setState({payee: e.target.value})}/>
+          </Form.Item>
+          <Form.Item label="澶嶆牳浜�">
+            <Input placeholder="澶嶆牳浜�" value={reviewer} autoComplete="off" onChange={(e) => this.setState({reviewer: e.target.value})}/>
+          </Form.Item>
+          <Form.Item label="寮�绁ㄤ汉">
+            <Input placeholder="寮�绁ㄤ汉" value={drawer} autoComplete="off" onChange={(e) => this.setState({drawer: e.target.value})}/>
+          </Form.Item>
+        </div>
+        <Modal
+          title="瀹㈡埛淇℃伅"
+          visible={visible}
+          width="70vw"
+          maskClosable={false}
+          onCancel={() => { this.setState({ visible: false }) }}
+          footer={null}
+        >
+          <SubTable config={config.buyer} onChange={this.changeBuyer}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default InvoiceModule
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/invoice/index.scss b/src/tabviews/custom/components/module/invoice/index.scss
new file mode 100644
index 0000000..2d09086
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/index.scss
@@ -0,0 +1,292 @@
+.menu-invoice-wrap {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  color: #000000;
+  min-height: 500px;
+  --inv-color: #13509c;
+
+  .inv-action {
+    text-align: right;
+    margin-right: 30px;
+    .ant-btn {
+      margin-left: 15px;
+      margin-bottom: 5px;
+      height: 30px;
+    }
+    .mk-bill:hover, .mk-bill:active, .mk-bill:focus {
+      color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+    }
+    .mk-submit, .mk-submit:hover, .mk-submit:active, .mk-submit:focus {
+      color: #fff;
+      background-color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+    }
+  }
+  .inv-header {
+    text-align: center;
+    position: relative;
+    height: 70px;
+    margin-right: 30px;
+    .ant-select {
+      width: 390px;
+      border: none;
+      .ant-select-selection {
+        border: none;
+        box-shadow: none;
+        font-size: 25px;
+        text-align: center;
+        background-color: transparent;
+
+        .ant-select-selection-selected-value {
+          float: none;
+          text-align: center;
+          font-family: kaiti;
+          color: var(--inv-color, #13509c);
+        }
+        .ant-select-selection__placeholder {
+          text-align: center;
+          font-family: kaiti;
+          height: 30px;
+          line-height: 30px;
+          margin-top: -12px;
+        }
+      }
+    }
+    .ant-select::before, .ant-select::after {
+      content: '';
+      display: block;
+      width: 100%;
+      position: absolute;
+      border-top: var(--inv-color, #13509c) 1px solid;
+      border-bottom: var(--inv-color, #13509c) 1px solid;
+      height: 1px;
+    }
+    .ant-select::before {
+      bottom: -10px;
+    }
+    .ant-select::after {
+      bottom: -15px;
+    }
+    .date {
+      position: absolute;
+      right: 100px;
+      top: 5px;
+      color: var(--inv-color, #13509c);
+    }
+  }
+
+  .ant-input {
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    box-shadow: none!important;
+    height: 28px;
+    font-size: 13px;
+    background: transparent;
+  }
+  .ant-input:hover, .ant-input:active, .ant-input:focus {
+    border-color: var(--inv-color, #13509c)!important;
+  }
+  .ant-input.ant-input-disabled {
+    cursor: text;
+    color: rgba(0, 0, 0, 0.85);
+    background: transparent!important;
+  }
+
+  .ant-input-number {
+    border-top: none;
+    border-left: none;
+    border-right: none;
+    border-radius: 0;
+    box-shadow: none!important;
+    height: 28px;
+    font-size: 13px;
+    .ant-input-number-handler-wrap {
+      display: none;
+    }
+  }
+  .ant-input-number:hover, .ant-input-number:active, .ant-input-number:focus {
+    border-color: var(--inv-color, #13509c)!important;
+  }
+
+  .inv-body {
+    border: var(--inv-color, #13509c) 1px solid;
+    font-size: 13px;
+    margin-right: 30px;
+
+    .inv-main-content {
+      display: flex;
+
+      .inv-buyer, .inv-notice {
+        width: 50%;
+        display: flex;
+        .inv-label {
+          color: var(--inv-color, #13509c);
+          width: 6.25%;
+          display: flex;
+          flex-direction: column;
+          writing-mode: vertical-rl;
+          justify-content: center;
+          align-items: center;
+          letter-spacing: 5px;
+          border-right: var(--inv-color, #13509c) 1px solid;
+        }
+        .inv-content {
+          flex: 1;
+          padding: 6px 0;
+
+          .ant-form-item {
+            display: flex;
+            padding: 0 5px 0 15px;
+            font-size: 13px;
+            margin-bottom: 5px;
+            
+            .ant-form-item-label {
+              line-height: 30px;
+              text-align: justify;
+              label {
+                display: flex;
+                color: var(--inv-color, #13509c);
+                span {
+                  display: inline-block;
+                  flex: 1;
+                }
+              }
+            }
+            .ant-form-item-control-wrapper {
+              width: 100%;
+
+              .ant-form-item-control {
+                line-height: 30px;
+                .ant-form-extra {
+                  position: absolute;
+                  top: 1px;
+                  right: 10px;
+                  font-size: 16px;
+                  .anticon {
+                    cursor: pointer;
+                  }
+                }
+                .ant-input-affix-wrapper:not(:hover) {
+                  .ant-input-suffix {
+                    opacity: 0;
+                  }
+                }
+              }
+            }
+          }
+          .ant-form-item.mutil-input {
+            .ant-form-item-children {
+              display: flex;
+            }
+          }
+        }
+      }
+      .inv-buyer {
+        border-right: var(--inv-color, #13509c) 1px solid;
+        .ant-form-item-label {
+          width: 103px;
+          min-width: 103px;
+          label:not(.ant-form-item-required) {
+            padding-left: 11px;
+          }
+          .ant-form-item-required::before {
+            line-height: 30px;
+          }
+        }
+      }
+      .inv-notice {
+        .inv-content {
+          padding-top: 45px;
+        }
+        .ant-form-item-label {
+          width: 75px;
+          min-width: 75px;
+        }
+      }
+    }
+
+    .inv-details {
+      border-top: var(--inv-color, #13509c) 1px solid;
+      border-bottom: var(--inv-color, #13509c) 1px solid;
+    }
+  }
+  .inv-tail {
+    display: flex;
+    padding-top: 10px;
+    margin-right: 30px;
+    .ant-form-item {
+      flex: 1;
+      display: flex;
+      font-size: 13px;
+      .ant-form-item-label, .ant-form-item-control-wrapper {
+        width: 40%;
+      }
+    }
+  }
+
+  .loading-mask {
+    position: absolute;
+    left: 0px;
+    top: 0;
+    right: 0px;
+    bottom: 0px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: justify;
+    z-index: 1;
+
+    .ant-spin-blur {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      opacity: 0.5;
+      background: #ffffff;
+    }
+  }
+}
+.inv-table {
+  .ant-table .ant-table-tbody tr:hover td {
+    background-color: var(--mk-sys-color1);
+  }
+}
+.tb-search-wrap {
+  .search-item {
+    display: flex;
+    float: left;
+    width: 350px;
+    align-items: center;
+    justify-content: flex-end;
+
+    .ant-input {
+      width: 200px;
+    }
+  }
+  .ant-btn {
+    margin-bottom: 20px;
+    margin-left: 50px;
+    background-color: var(--mk-sys-color);
+    border-color: var(--mk-sys-color);
+    color: #ffffff;
+  }
+  .ant-btn:hover, .ant-btn:active {
+    background-color: var(--mk-sys-color);
+    border-color: var(--mk-sys-color);
+    color: #ffffff;
+    opacity: 0.9;
+  }
+}
+
+.inv-type-select {
+  .ant-select-dropdown-menu-item {
+    text-align: center;
+  }
+}
+
diff --git a/src/tabviews/custom/components/module/invoice/invoiceTable/index.jsx b/src/tabviews/custom/components/module/invoice/invoiceTable/index.jsx
new file mode 100644
index 0000000..310b26f
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/invoiceTable/index.jsx
@@ -0,0 +1,420 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Input, InputNumber, notification, Modal } from 'antd'
+import { EllipsisOutlined } from '@ant-design/icons'
+
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import SubTable from '../subTable'
+import './index.scss'
+
+class DetailLine extends React.Component {
+  state = {
+    bill_count: 0,
+    unitprice: 0,
+    amount_line: 0,
+    visible: false
+  }
+
+  UNSAFE_componentWillMount() {
+    let { line } = this.props
+
+    this.setState({
+      bill_count: line.bill_count || '',
+      unitprice: line.unitprice || '',
+      amount_line: line.amount_line || ''
+    })
+  }
+
+  onChange = (value, key) => {
+    let line = {...this.props.line}
+
+    if (['bill_count', 'unitprice', 'amount_line'].includes(key)) {
+      line[key] = value || 0
+      if (isNaN(line[key])) {
+        line[key] = 0
+      }
+      if (line[key]) {
+        if (key === 'bill_count') {
+          line[key] = Math.round(line[key] * 10000000000) / 10000000000
+          if (line.unitprice) {
+            line.amount_line = Math.round(line.unitprice * line.bill_count * 100) / 100
+          }
+        } else if (key === 'unitprice') {
+          line[key] = Math.round(line[key] * 10000000000) / 10000000000
+          if (line.bill_count) {
+            line.amount_line = Math.round(line.unitprice * line.bill_count * 100) / 100
+          }
+        } else if (key === 'amount_line') {
+          line[key] = Math.round(line[key] * 100) / 100
+          if (line.bill_count) {
+            line.unitprice = Math.round(line.amount_line / line.bill_count * 10000000000) / 10000000000
+          } else if (line.unitprice) {
+            line.bill_count = Math.round(line.amount_line / line.unitprice * 10000000000) / 10000000000
+          }
+        }
+      } else if (key === 'amount_line') {
+        line.bill_count = 0
+      }
+
+      if (line.amount_line) {
+        line.tax_amount = line.amount_line - line.amount_line / (line.tax_rate + 1)
+        line.tax_amount = Math.round(line.tax_amount * 100) / 100
+      } else {
+        line.tax_amount = 0
+      }
+    } else {
+      line[key] = value
+    }
+
+    this.setState({
+      bill_count: line.bill_count || '',
+      unitprice: line.unitprice || '',
+      amount_line: line.amount_line || ''
+    })
+
+    this.props.changeLine(line, key)
+  }
+
+  render() {
+    const { line, delLine, trigger } = this.props
+    const { bill_count, unitprice, amount_line } = this.state
+    
+    return <div className="mk-tr active">
+      <div className="mk-td">
+        <div className="mk-input">{line.productname || ''}<EllipsisOutlined onClick={trigger}/></div>
+      </div>
+      <div className="mk-td">
+        <Input defaultValue={line.spec || ''} onChange={(e) => this.onChange(e.target.value, 'spec')}/>
+      </div>
+      <div className="mk-td">
+        <Input defaultValue={line.unit || ''} onChange={(e) => this.onChange(e.target.value, 'unit')}/>
+      </div>
+      <div className="mk-td">
+        <InputNumber value={bill_count} formatter={value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/,*/g, '')} onChange={(val) => this.setState({bill_count: val})} onBlur={() => this.onChange(bill_count, 'bill_count')}/>
+      </div>
+      <div className="mk-td">
+        <InputNumber value={unitprice} formatter={value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/,*/g, '')} onChange={(val) => this.setState({unitprice: val})} onBlur={() => this.onChange(unitprice, 'unitprice')}/>
+      </div>
+      <div className="mk-td">
+        <InputNumber value={amount_line} formatter={value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/,*/g, '')} onChange={(val) => this.setState({amount_line: val})} onBlur={() => this.onChange(amount_line, 'amount_line')}/>
+      </div>
+      <div className="mk-td mk-right">{line.tax_name}</div>
+      <div className="mk-td mk-right">{line.tax_amount.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')} <span className="del-line" onClick={() => delLine(line.uuid)}></span> </div>
+    </div>
+  }
+}
+
+class InvoiceTable extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    data: PropTypes.any,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    data: [],
+    editKey: '',
+    total: {}
+  }
+
+  UNSAFE_componentWillMount () {
+    const { data } = this.props
+
+    let _data = fromJS(data).toJS()
+    if (!_data.length) {
+      _data = [{uuid: Utils.getguid(), productname: '', spec: '', unit: '', bill_count: '', unitprice: 0, amount_line: 0, tax_rate: '', tax_name: '', tax_amount: 0}]
+    }
+
+    this.setState({
+      data: _data
+    }, () => {
+      this.getTotal(_data)
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('resetDetails', this.resetDetails)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('resetDetails', this.resetDetails)
+  }
+  
+  changeMoneyToChinese = (money) => {
+    let cnNums = ['闆�', '澹�', '璐�', '鍙�', '鑲�', '浼�', '闄�', '鏌�', '鎹�', '鐜�']
+    let cnIntRadice = ['', '鎷�', '浣�', '浠�']
+    let cnIntUnits = ['', '涓�', '浜�', '鍏�']
+    let cnDecUnits = ['瑙�', '鍒�', '姣�', '鍘�']
+    let cnInteger = '鏁�'
+    let cnIntLast = '鍏�'
+    let maxNum = 999999999999999.9999 // 鏈�澶у鐞嗙殑鏁板瓧
+    let IntegerNum = null
+    let DecimalNum = null
+    let ChineseStr = ''
+    let parts = null // 鍒嗙閲戦鍚庣敤鐨勬暟缁勶紝棰勫畾涔�
+    let Symbol = ''  // 姝h礋鍊兼爣璁�
+
+    if (money === 0) return ''
+
+    if (money >= maxNum) return '瓒呭嚭鏈�澶у鐞嗘暟瀛�'
+
+    if(money < 0) {
+      money = -money
+      Symbol = '璐�'       
+    }
+    money = money.toString() // 杞崲涓哄瓧绗︿覆
+    if (money.indexOf('.') === -1) {
+      IntegerNum = money
+      DecimalNum = ''
+    } else {
+      parts = money.split('.')
+      IntegerNum = parts[0]
+      DecimalNum = parts[1].substr(0, 4)
+    }
+
+    if (parseInt(IntegerNum, 10) > 0) { // 鑾峰彇鏁村瀷閮ㄥ垎杞崲
+      let zeroCount = 0
+      let IntLen = IntegerNum.length
+      for (let i = 0; i < IntLen; i++) {
+        let n = IntegerNum.substr(i, 1)
+        let p = IntLen - i - 1
+        let q = p / 4
+        let m = p % 4
+        
+        if (n === '0') {
+          zeroCount++
+        } else {
+          if (zeroCount > 0) {
+            ChineseStr += cnNums[0]
+          }
+          zeroCount = 0 // 褰掗浂
+          ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
+        }
+
+        if (m === 0 && zeroCount < 4) {
+          ChineseStr += cnIntUnits[q]
+        }
+      }
+      ChineseStr += cnIntLast
+    }
+
+    if (DecimalNum !== '') { // 灏忔暟閮ㄥ垎
+      let decLen = DecimalNum.length
+
+      for (let i = 0; i < decLen; i++) {
+        let n = DecimalNum.substr(i, 1)
+        if (n !== '0') {
+          ChineseStr += cnNums[Number(n)] + cnDecUnits[i]
+        }
+      }
+    }
+    if (ChineseStr === '') {
+      ChineseStr += cnNums[0] + cnIntLast + cnInteger
+    } else if (DecimalNum === '') {
+      ChineseStr += cnInteger
+    }
+
+    ChineseStr = Symbol + ChineseStr
+    
+    return ChineseStr
+  }
+
+  getTotal = (data) => {
+    let price = 0
+    let tax = 0
+
+    data.forEach(item => {
+      if (!item.productcode) return
+
+      price += item.amount_line * 100
+      tax += item.tax_amount * 100
+    })
+
+    price = price / 100
+    tax = tax / 100
+
+    this.setState({total: {price, tax, sum: price, sumName: this.changeMoneyToChinese(price)}})
+  }
+
+  resetDetails = (data) => {
+    let _data = fromJS(data).toJS()
+
+    if (!_data.length) {
+      _data = [{uuid: Utils.getguid(), productname: '', spec: '', unit: '', bill_count: '', unitprice: 0, amount_line: 0, tax_rate: '', tax_name: '', tax_amount: 0}]
+    }
+
+    this.setState({data: _data}, () => {
+      this.getTotal(_data)
+    })
+  }
+
+  addLine = () => {
+    const { data } = this.state
+
+    let line = {uuid: Utils.getguid(), productname: '', spec: '', unit: '', bill_count: '', unitprice: 0, amount_line: 0, tax_rate: '', tax_name: '', tax_amount: 0}
+
+    this.setState({data: [...data, line]})
+  }
+
+  delLine = () => {
+    const { editKey, data } = this.state
+
+    if (data.length === 1) {
+      notification.warning({
+        top: 92,
+        message: '鑷冲皯淇濈暀涓�琛屾槑缁嗭紒',
+        duration: 3
+      })
+      return
+    }
+
+    let _data = data.filter(item => item.uuid !== editKey)
+
+    this.setState({data: _data}, () => {
+      this.getTotal(_data)
+    })
+    this.props.onChange(_data)
+  }
+
+  changeLine = (record) => {
+    const { editKey, data } = this.state
+
+    let _data = data.map(item => {
+      if (item.uuid === editKey) {
+        return record
+      } else {
+        return item
+      }
+    })
+
+
+    this.setState({data: _data}, () => {
+      this.getTotal(_data)
+    })
+    this.props.onChange(_data)
+  }
+
+  checkLine = (uuid) => {
+    this.setState({editKey: uuid})
+  }
+
+  changeDetail = (prod) => {
+    const { editKey, data } = this.state
+
+    let _data = data.map(item => {
+      if (item.uuid === editKey) {
+        item.productname = prod.productname
+        item.spec = prod.spec
+        item.unit = prod.unit
+        item.unitprice = prod.unitprice
+        item.tax_rate = prod.tax_rate || 0
+        item.tax_name = prod.tax_rate * 100 + '%'
+        item.free_tax_mark = prod.free_tax_mark || ''
+        item.vat_special_management = prod.vat_special_management || ''
+
+        if (prod.vat_special_management && prod.free_tax_mark === 'true') {
+          item.tax_name = prod.vat_special_management
+        }
+
+        item.productcode = prod.productcode
+        item.Description = prod.Description
+        item.tax_classify_code = prod.tax_classify_code
+        item.tax_classify_name = prod.tax_classify_name
+
+        if (item.bill_count && item.unitprice) {
+          item.amount_line = Math.round(item.unitprice * item.bill_count * 100) / 100
+        }
+        if (item.amount_line) {
+          item.tax_amount = item.amount_line - item.amount_line / (item.tax_rate + 1)
+          item.tax_amount = Math.round(item.tax_amount * 100) / 100
+        } else {
+          item.tax_amount = 0
+        }
+      }
+
+      return item
+    })
+
+    this.setState({data: _data, editKey: '', visible: false}, () => {
+      this.setState({editKey: editKey})
+      this.getTotal(_data)
+    })
+    this.props.onChange(_data)
+  }
+
+  render() {
+    const { config, tax_type } = this.props
+    const { editKey, data, total, visible } = this.state
+
+    return (
+      <div className="detail-wrap">
+        <span className="plus-line" onClick={this.addLine}></span>
+        <div className="mk-th">
+          <div className="mk-td">璐х墿鎴栧簲绋庡姵鍔°�佹湇鍔″悕绉�</div>
+          <div className="mk-td">瑙勬牸鍨嬪彿</div>
+          <div className="mk-td">鍗曚綅</div>
+          <div className="mk-td">鏁伴噺</div>
+          <div className="mk-td">鍗曚环锛堝惈绋庯級</div>
+          <div className="mk-td">閲戦锛堝惈绋庯級</div>
+          <div className="mk-td">绋庣巼</div>
+          <div className="mk-td">绋庨</div>
+        </div>
+        {data.map(item => {
+          if (editKey === item.uuid) {
+            return <DetailLine key={item.uuid} line={item} changeLine={this.changeLine} delLine={this.delLine} trigger={() => this.setState({visible: true})}/>
+          }
+
+          return <div className="mk-tr" key={item.uuid} onClick={() => this.checkLine(item.uuid)}>
+            <div className="mk-td mk-left">{item.productname || ''}</div>
+            <div className="mk-td mk-left">{item.spec || ''}</div>
+            <div className="mk-td mk-left">{item.unit || ''}</div>
+            <div className="mk-td mk-right">{`${item.bill_count || ''}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+            <div className="mk-td mk-right">{`${item.unitprice || ''}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+            <div className="mk-td mk-right">{`${item.amount_line || ''}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+            <div className="mk-td mk-right">{item.tax_name}</div>
+            <div className="mk-td mk-right">{item.tax_amount.toFixed(2).replace(/\B(?=(\d{3})+(?!\d))/g, ',')}<span className="del-line" onClick={() => this.delLine(item.uuid)}></span></div>
+          </div>
+        })}
+        <div className="mk-total">
+          <div className="mk-td">鍚堣</div>
+          <div className="mk-td"></div>
+          <div className="mk-td"></div>
+          <div className="mk-td"></div>
+          <div className="mk-td"></div>
+          <div className="mk-td">锟`${total.price}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+          <div className="mk-td"></div>
+          <div className="mk-td">锟`${total.tax}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+        </div>
+        <div className="mk-upcase">
+          <div className="mk-td">浠风◣鍚堣锛堝ぇ鍐欙級</div>
+          <div className="mk-td">{total.sumName}</div>
+          <div className="mk-td">锛堝皬鍐欙級锟`${total.sum}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')}</div>
+        </div>
+        <Modal
+          title="鍟嗗搧淇℃伅"
+          visible={visible}
+          width="75vw"
+          maskClosable={false}
+          onCancel={() => { this.setState({ visible: false }) }}
+          footer={null}
+        >
+          <SubTable config={config} tax_type={tax_type} onChange={this.changeDetail}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default InvoiceTable
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/invoice/invoiceTable/index.scss b/src/tabviews/custom/components/module/invoice/invoiceTable/index.scss
new file mode 100644
index 0000000..2621d4a
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/invoiceTable/index.scss
@@ -0,0 +1,131 @@
+.detail-wrap {
+  position: relative;
+
+  .plus-line, .del-line {
+    position: absolute;
+    right: -40px;
+    top: 5px;
+    font-size: 26px;
+    border: 1px solid var(--inv-color, #13509c);
+    width: 30px;
+    height: 30px;
+    transition: all 0.3s;
+    cursor: pointer;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+  }
+  .plus-line::before, .del-line::before {
+    content: ' ';
+    position: absolute;
+    top: 13px;
+    width: 12px;
+    height: 1px;
+    background: var(--inv-color, #13509c);
+    transition: all 0.3s;
+  }
+  .plus-line::after {
+    content: ' ';
+    position: absolute;
+    top: 13px;
+    width: 12px;
+    height: 1px;
+    background: var(--inv-color, #13509c);
+    transform: rotate(90deg);
+    transition: all 0.3s;
+  }
+
+  .del-line {
+    display: none;
+  }
+  .mk-tr:hover {
+    .del-line {
+      display: flex;
+    }
+    .del-line::after {
+      content: ' ';
+      position: absolute;
+      top: -6px;
+      width: 12px;
+      height: 40px;
+      left: -12px;
+    }
+  }
+
+  .mk-th, .mk-tr, .mk-total {
+    position: relative;
+    display: flex;
+    border-bottom: var(--inv-color, #13509c) 1px solid;
+
+    .mk-td {
+      width: 10%;
+      height: 40px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      padding: 0 5px;
+    }
+    .mk-td:not(:last-child) {
+      border-right: var(--inv-color, #13509c) 1px solid;
+    }
+    .mk-td:first-child {
+      width: 20%;
+    }
+    .mk-td:nth-child(2), .mk-td:nth-child(6) {
+      width: 15%;
+    }
+
+    .mk-left {
+      justify-content: start;
+    }
+    .mk-right {
+      justify-content: end;
+    }
+
+    .mk-input {
+      position: relative;
+      height: 28px;
+      width: 100%;
+      background: #ffffff;
+      border-bottom: 1px solid #d9d9d9;
+      transition: all 0.3s;
+
+      .anticon-ellipsis {
+        position: absolute;
+        right: 0px;
+        padding: 5px 10px;
+        cursor: pointer;
+      }
+    }
+    .mk-input:hover {
+      border-color: var(--inv-color, #13509c);
+    }
+
+    .ant-input {
+      background: #ffffff;
+    }
+  }
+  .mk-tr.active, .mk-tr:hover {
+    background: var(--mk-sys-color1);
+  }
+  .mk-upcase {
+    display: flex;
+
+    .mk-td {
+      width: 40%;
+      height: 40px;
+      display: flex;
+      align-items: center;
+      padding: 0 20px;
+    }
+    .mk-td:first-child {
+      width: 20%;
+      padding: 0;
+      border-right: var(--inv-color, #13509c) 1px solid;
+      justify-content: center;
+    }
+    .mk-td:last-child {
+      justify-content: end;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/invoice/subTable/index.jsx b/src/tabviews/custom/components/module/invoice/subTable/index.jsx
new file mode 100644
index 0000000..953fbe3
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/subTable/index.jsx
@@ -0,0 +1,250 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Table, Input, Button } from 'antd'
+
+import Api from '@/api'
+import UtilsDM from '@/utils/utils-datamanage.js'
+// import './index.scss'
+
+class SearchWrap extends Component {
+  static propTpyes = {
+    search: PropTypes.array,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    search: []
+  }
+
+  UNSAFE_componentWillMount () {
+    const { search } = this.props
+
+    this.setState({
+      search: fromJS(search).toJS()
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  searchChange = (val, key) => {
+    const { search } = this.state
+
+    this.setState({search: search.map(item => {
+      if (item.field === key) {
+        item.value = val
+      }
+      return item
+    })})
+  }
+
+  trigger = () => {
+    const { search } = this.state
+
+    this.props.onChange(search)
+  }
+
+  render() {
+    const { search } = this.state
+
+    return (
+      <div className="tb-search-wrap">
+        {search.map(item => (
+          <div className="search-item" key={item.field}>
+            {item.label}锛�
+            <Input autoComplete="off" onChange={(e) => this.searchChange(e.target.value, item.field)}/>
+          </div>
+        ))}
+        <Button onClick={this.trigger}>鎼滅储</Button>
+      </div>
+    )
+  }
+}
+
+class SubTable extends Component {
+  static propTpyes = {
+    config: PropTypes.object
+  }
+
+  state = {
+    pageIndex: 1,         // 鍒濆椤甸潰绱㈠紩
+    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
+    columns: null,        // 鏄剧ず鍒�
+    pageOptions: [],
+    search: []
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    let _columns = []
+
+    config.columns.forEach(item => {
+      if (item.Hide === 'true') return
+      _columns.push({
+        align: 'center',
+        dataIndex: item.field,
+        title: item.label,
+        sorter: false,
+        width: item.Width || 120
+      })
+    })
+
+    let size = (config.setting.pageSize || 10) + ''
+    let pageOptions = ['10', '25', '50', '100', '500', '1000']
+
+    if (!pageOptions.includes(size)) {
+      pageOptions.push(size)
+      pageOptions = pageOptions.sort((a, b) => a - b)
+    }
+
+    this.setState({
+      pageSize: config.pageSize || 10,
+      pageOptions,
+      search: fromJS(config.search).toJS(),
+      columns: _columns
+    })
+  }
+
+  componentDidMount() {
+    const { config } = this.props
+
+    if (config.setting.onload === 'true') {
+      this.loadData()
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  /**
+   * @description 鏁版嵁鍔犺浇
+   */
+  async loadData () {
+    const { config, tax_type } = this.props
+    const { search, pageIndex, pageSize } = this.state
+
+    this.setState({
+      loading: true
+    })
+
+    let searches = search.map(item => ({
+      key: item.field,
+      match: item.match,
+      type: item.type,
+      value: item.value || ''
+    }))
+
+    let param = UtilsDM.getQueryDataParams(config.setting, searches, config.setting.order, pageIndex, pageSize, '')
+
+    this.requestId = config.uuid + new Date().getTime()
+
+    let result = await Api.genericInterface(param, config.setting.js_script, '', this.requestId)
+
+    if (result.status) {
+      if (result.$requestId && this.requestId !== result.$requestId) return
+
+      let start = pageSize * (pageIndex - 1) + 1
+
+      let data = result.data.map((item, index) => {
+        item.key = index
+        item.$Index = start + index + ''
+
+        if (tax_type) {
+          item.tax_rate = tax_type === 'special_invoice' ? item.general_tax_rate : item.small_tax_rate
+          item.tax_rate = isNaN(item.tax_rate) ? 0 : +item.tax_rate
+        }
+
+        return item
+      })
+
+      let total = result.total || 0
+      if (config.setting.custompage && data.length) {
+        total = data[data.length - 1].mk_total || 0
+      }
+
+      this.setState({
+        data: data,
+        total: total,
+        loading: false
+      })
+
+      UtilsDM.querySuccess(result)
+    } else {
+      this.setState({
+        loading: false
+      })
+      
+      UtilsDM.queryFail(result)
+    }
+  }
+
+  changeTable = (pagination) => {
+    this.setState({
+      pageIndex: pagination.current,
+      pageSize: pagination.pageSize,
+    }, () => {
+      this.loadData()
+    })
+  }
+
+  doubleClickLine = (record) => {
+    this.props.onChange(record)
+  }
+
+  searchChange = (search) => {
+    this.setState({search: search}, () => {
+      this.loadData()
+    })
+  }
+
+  render() {
+    const { pageIndex, pageSize, pageOptions, columns, total, loading, data, search } = this.state
+
+    return (
+      <>
+        <SearchWrap search={search} onChange={this.searchChange}/>
+        <Table
+          className="inv-table"
+          columns={columns}
+          dataSource={data}
+          bordered={true}
+          loading={loading}
+          onRow={(record) => {
+            return {
+              onDoubleClick: () => {this.doubleClickLine(record)}
+            }
+          }}
+          onChange={this.changeTable}
+          pagination={{
+            current: pageIndex,
+            pageSize: pageSize,
+            pageSizeOptions: pageOptions,
+            showSizeChanger: true,
+            total: total || 0,
+            showTotal: (total, range) => `${range[0]}-${range[1]} 鍏� ${total} 鏉
+          }}
+        />
+      </>
+    )
+  }
+}
+
+export default SubTable
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/invoice/subTable/index.scss b/src/tabviews/custom/components/module/invoice/subTable/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tabviews/custom/components/module/invoice/subTable/index.scss
diff --git a/src/tabviews/custom/components/module/voucher/index.jsx b/src/tabviews/custom/components/module/voucher/index.jsx
index 8c282b4..0fd7ac5 100644
--- a/src/tabviews/custom/components/module/voucher/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/index.jsx
@@ -12,10 +12,8 @@
 import ResetRemark from './resetRemark'
 import ResetAttach from './resetAttach'
 import LoadFromTemp from './loadFromTemp'
-import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
-const PrintVoucher = asyncComponent(() => import('./printVoucher'))
 const { confirm } = Modal
 
 class VoucherModule extends Component {
@@ -39,6 +37,8 @@
     username: sessionStorage.getItem('User_Name'),
     remark: '',
     attachments: 0,
+    vouAduited: false,
+    vouReadOnly: false,
     attachlist: [],
     oriAttachs: [],
     tempTypes: [],
@@ -304,6 +304,7 @@
 
       let data = []
       if (res.voucher) {
+        let disabled = res.voucher_status === 'true'
         data = res.voucher.map(line => {
           line.uuid = line.subject_id || ''
 
@@ -320,6 +321,7 @@
           line.exratename = line.foreign_exratename || ''
           line.local_currency = line.local_exratecode || ''
           line.foreign_currency_type = line.foreign_type || ''
+          line.$disabled = disabled
 
           if (line.sup) {
             line.supAccounts = line.sup.map(cell => {
@@ -351,7 +353,9 @@
           data: data,
           attachlist: files,
           vouDate: res.fibvoucherdate ? moment(res.fibvoucherdate, 'YYYY-MM-DD') : null,
-          charType: res.voucher_class,
+          charType: res.voucher_class || 'keeping',
+          vouAduited: res.voucher_status === 'true' || res.read_only === 'true',
+          vouReadOnly: res.read_only === 'true',
           charName: res.voucher_char,
           charInt: res.voucher_char_int,
           // orgcode: res.orgcode,
@@ -1059,10 +1063,6 @@
     this.setState({status: 'change', attachlist: vals, attachments: num})
   }
 
-  triggermore = () => {
-
-  }
-
   triggerclose = () => {
     const { config, status } = this.state
 
@@ -1139,72 +1139,233 @@
     })
   }
 
-  render() {
-    const { type, status, loading, config, orgcode, orgname, typeOptions, tempTypes, charType, charName, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass } = this.state
+  triggerPrint = () => {
+    const { config, BID } = this.state
 
-    return (
-      <div className="menu-voucher-wrap" style={config.style}>
-        {type === 'createVoucher' ? <div className="voucher-header">
-          <Button className="add-background header-btn" disabled={status === 'empty'} onClick={() => this.triggersave('add')}>淇濆瓨骞舵柊澧�</Button>
-          <Button className="add-background header-btn" disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>淇濆瓨</Button>
-          <PrintVoucher ID={config.uuid + 'print'} data={data} orgname={orgname} vouDate={vouDate} charName={charName} charInt={charInt} attachments={attachments} disabled={status !== 'saved'}/>
-          <Dropdown overlay={<div className="mk-voucher-dropdown-wrap">
-            <SaveAsTemp tempTypes={tempTypes} onChange={this.triggerTempsave}/>
-            <div className="split"></div>
-            <LoadFromTemp tempTypes={tempTypes} onChange={this.triggerTempLoad}/>
-          </div>} trigger={['click']}>
-            <Button className="out-background header-btn" onClick={this.triggermore}>鏇村</Button>
-          </Dropdown>
-        </div> : null}
-        {type === 'checkVoucher' ? <div className="voucher-header">
-          <Button className="add-background header-btn" disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>淇濆瓨</Button>
-          <PrintVoucher ID={config.uuid + 'print'} data={data} orgname={orgname} vouDate={vouDate} charName={charName} charInt={charInt} attachments={attachments} disabled={status !== 'saved'}/>
-          <Button className="out-background header-btn" onClick={this.triggerclose}>鍏抽棴</Button>
-        </div> : null}
-        <div className="voucher-body" style={{padding: `0px ${config.wrap.space || 0}px`}}>
-          {type === 'createVoucher' || type === 'checkVoucher' ? <div className="pre-wrap">
-            <div className="voucher-code">
-              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({status: 'change', charType: val, charName: option.props.charName, charInt: option.props.charint})}>
-                {typeOptions.map(option =>
-                  <Select.Option key={option.id} value={option.voucher_class} charName={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
-                )}
-              </Select>
-              <InputNumber precision={0} min={1} value={charInt} autoComplete="off" onChange={(val) => this.setState({status: 'change', charInt: val})}/> 鍙�
+    if (!config.wrap.printTemp) {
+      notification.warning({
+        top: 92,
+        message: '灏氭湭璁剧疆鎵撳嵃妯℃澘锛�',
+        duration: 5
+      })
+      return
+    }
+
+    window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: BID, tempId: config.wrap.printTemp, pageId: config.$pageId || '', dataM: sessionStorage.getItem('dataM') }))))
+  }
+
+  triggerAduit = () => {
+    const { book, BID, voucherCode, username } = this.state
+
+    if (!book) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨璐﹀锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let param = {
+      func: 's_fcc_voucher_sub',
+      ID: BID,
+      status: 10,
+      statusname: '宸插鏍�',
+      voucher_code: voucherCode || '',
+      username: username,
+      fullname: sessionStorage.getItem('Full_Name') || ''
+    }
+
+    const that = this
+
+    confirm({
+      content: '纭畾瑕佸鏍稿悧锛�',
+      onOk() {
+        Api.genericInterface(param).then(res => {
+          if (!res.status) {
+            notification.warning({
+              top: 92,
+              message: res.message,
+              duration: 5
+            })
+            return
+          }
+    
+          notification.success({
+            top: 92,
+            message: '宸茬粡閫氳繃瀹℃牳',
+            duration: 2
+          })
+
+          that.getVoucher()
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  triggerUnAduit = () => {
+    const { book, BID, voucherCode, username } = this.state
+
+    if (!book) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨璐﹀锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let param = {
+      func: 's_fcc_voucher_sub',
+      ID: BID,
+      status: 0,
+      statusname: '鍙栨秷瀹℃牳',
+      voucher_code: voucherCode || '',
+      username: username,
+      fullname: sessionStorage.getItem('Full_Name') || ''
+    }
+
+    const that = this
+
+    confirm({
+      content: '纭瑕佸彇娑堝鏍稿悧锛�',
+      onOk() {
+        Api.genericInterface(param).then(res => {
+          if (!res.status) {
+            notification.warning({
+              top: 92,
+              message: res.message,
+              duration: 5
+            })
+            return
+          }
+
+          notification.success({
+            top: 92,
+            message: '瀹℃牳宸插彇娑�',
+            duration: 2
+          })
+
+          that.getVoucher()
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  render() {
+    const { type, status, loading, config, orgcode, typeOptions, tempTypes, charType, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass, vouAduited, vouReadOnly, voucherCode } = this.state
+
+    if (type === 'checkVoucher') {
+      return (
+        <div className="menu-voucher-wrap" style={config.style}>
+          <div className="voucher-header" style={{padding: `10px ${config.wrap.space || 0}px`}}>
+            {!vouAduited ? <Button disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>淇濆瓨</Button> : null}
+            {/* <PrintVoucher ID={config.uuid + 'print'} data={data} orgname={orgname} vouDate={vouDate} charName={charName} charInt={charInt} attachments={attachments} disabled={status !== 'saved'}/> */}
+            <Button disabled={status !== 'saved'} onClick={this.triggerPrint}>鎵撳嵃</Button>
+            {vouAduited && !vouReadOnly ? <Button onClick={this.triggerUnAduit}>鍙栨秷瀹℃牳</Button> : null}
+            {!vouAduited && !vouReadOnly ? <Button onClick={this.triggerAduit}>瀹℃牳</Button> : null}
+            <Button onClick={this.triggerclose}>鍏抽棴</Button>
+          </div>
+          <div className="voucher-body" style={{padding: `0px ${config.wrap.space || 0}px`}}>
+            <div className="pre-wrap">
+              <div className="voucher-number">
+                鍑瘉鍙凤細{voucherCode}
+              </div>
+              <div className="voucher-code">
+                <Select value={charType} disabled={vouAduited} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({status: 'change', charType: val, charName: option.props.charname, charInt: option.props.charint})}>
+                  {typeOptions.map(option =>
+                    <Select.Option key={option.id} value={option.voucher_class} charname={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
+                  )}
+                </Select>
+                <InputNumber precision={0} min={1} disabled={vouAduited} value={charInt} autoComplete="off" onChange={(val) => this.setState({status: 'change', charInt: val})}/> 鍙�
+              </div>
+              <div className="voucher-date">
+                鏃ユ湡锛�<DatePicker value={vouDate} disabled={vouAduited} onChange={this.changeVouDate}/>
+              </div>
+              <div className="voucher-text">
+                <Input value={title} placeholder={vouAduited ? '' : '鍑瘉鏂囨湰'} disabled={vouAduited} autoComplete="off" onChange={(e) => this.setState({status: 'change', title: e.target.value})}/>
+              </div>
+              <div className="voucher-affix">
+                闄勫崟鎹� <InputNumber precision={0} disabled={vouAduited} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 寮�
+                <ResetAttach config={config} disabled={vouAduited} orgcode={orgcode} voucherCode={this.state.voucherCode} attachlist={attachlist} onChange={this.resetAttachList}/>
+                <ResetRemark remark={remark} disabled={vouAduited} ID={config.uuid + 'remark'} onChange={(val) => this.setState({status: 'change', remark: val})}/>
+              </div>
             </div>
-            <div className="voucher-date">
-              鏃ユ湡锛�<DatePicker value={vouDate} onChange={this.changeVouDate}/>
-            </div>
-            <div className="voucher-text">
-              <Input value={title} placeholder="鍑瘉鏂囨湰" autoComplete="off" onChange={(e) => this.setState({status: 'change', title: e.target.value})}/>
-            </div>
-            <div className="voucher-affix">
-              闄勫崟鎹� <InputNumber precision={0} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 寮�
-              <ResetAttach config={config} orgcode={orgcode} voucherCode={this.state.voucherCode} attachlist={attachlist} onChange={this.resetAttachList}/>
-              <ResetRemark remark={remark} ID={config.uuid + 'remark'} onChange={(val) => this.setState({status: 'change', remark: val})}/>
-            </div>
-          </div> : null}
-          {type === 'createTemp' || type === 'checkTemp' ? <div className="pre-temp-wrap">
-            <div className="temp-text">
-              <span>妯℃澘鍚嶇О锛�</span><Input value={title} placeholder="妯℃澘鍚嶇О" autoComplete="off" onChange={(e) => this.setState({title: e.target.value})}/>
-            </div>
-            <div className="temp-text">
-              <span>妯℃澘绫诲瀷锛�</span>
-              <Select value={tempTypeClass} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({tempTypeClass: val, tempTypeName: option.props.children})}>
-                {tempTypes.map(option =>
-                  <Select.Option key={option.data_code} value={option.data_code}>{option.data_name}</Select.Option>
-                )}
-              </Select>
-            </div>
-            <div className="temp-action">
-              <Button className="save-temp header-btn" onClick={() => this.triggerTempsave()}>淇濆瓨</Button>
-              <Button className="close-temp header-btn" onClick={this.triggerclose}>鍏抽棴</Button>
-            </div>
-          </div> : null}
-          <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+            <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+          </div>
+          <div className="user" style={{paddingLeft: `${config.wrap.space || 0}px`}}>鍒跺崟浜猴細{username}</div>
         </div>
-        {type === 'createVoucher' || type === 'checkVoucher' ? <div className="user">鍒跺崟浜猴細{username}</div> : null}
-      </div>
-    )
+      )
+    } else if (type === 'createVoucher') {
+      return (
+        <div className="menu-voucher-wrap" style={config.style}>
+          <div className="voucher-header" style={{padding: `10px ${config.wrap.space || 0}px`}}>
+            <Button disabled={status === 'empty'} onClick={() => this.triggersave('add')}>淇濆瓨骞舵柊澧�</Button>
+            <Button disabled={status === 'empty' || status === 'saved'} onClick={() => this.triggersave()}>淇濆瓨</Button>
+            <Button disabled={status !== 'saved'} onClick={this.triggerPrint}>鎵撳嵃</Button>
+            <Dropdown overlay={<div className="mk-voucher-dropdown-wrap">
+              <SaveAsTemp tempTypes={tempTypes} onChange={this.triggerTempsave}/>
+              <div className="split"></div>
+              <LoadFromTemp tempTypes={tempTypes} onChange={this.triggerTempLoad}/>
+            </div>} trigger={['hover']} placement="bottomCenter">
+              <Button>鏇村</Button>
+            </Dropdown>
+          </div>
+          <div className="voucher-body" style={{padding: `0px ${config.wrap.space || 0}px`}}>
+            <div className="pre-wrap">
+              <div className="voucher-code">
+                <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({status: 'change', charType: val, charName: option.props.charname, charInt: option.props.charint})}>
+                  {typeOptions.map(option =>
+                    <Select.Option key={option.id} value={option.voucher_class} charname={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
+                  )}
+                </Select>
+                <InputNumber precision={0} min={1} value={charInt} autoComplete="off" onChange={(val) => this.setState({status: 'change', charInt: val})}/> 鍙�
+              </div>
+              <div className="voucher-date">
+                鏃ユ湡锛�<DatePicker value={vouDate} onChange={this.changeVouDate}/>
+              </div>
+              <div className="voucher-text">
+                <Input value={title} placeholder="鍑瘉鏂囨湰" autoComplete="off" onChange={(e) => this.setState({status: 'change', title: e.target.value})}/>
+              </div>
+              <div className="voucher-affix">
+                闄勫崟鎹� <InputNumber precision={0} value={attachments || 0} autoComplete="off" onChange={this.changeAttach}/> 寮�
+                <ResetAttach config={config} orgcode={orgcode} voucherCode={this.state.voucherCode} attachlist={attachlist} onChange={this.resetAttachList}/>
+                <ResetRemark remark={remark} ID={config.uuid + 'remark'} onChange={(val) => this.setState({status: 'change', remark: val})}/>
+              </div>
+            </div>
+            <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+          </div>
+          <div className="user" style={{paddingLeft: `${config.wrap.space || 0}px`}}>鍒跺崟浜猴細{username}</div>
+        </div>
+      )
+    } else {
+      return (
+        <div className="menu-voucher-wrap" style={config.style}>
+          <div className="voucher-body" style={{padding: `0px ${config.wrap.space || 0}px`}}>
+            <div className="pre-temp-wrap">
+              <div className="temp-text">
+                <span>妯℃澘鍚嶇О锛�</span><Input value={title} placeholder="妯℃澘鍚嶇О" autoComplete="off" onChange={(e) => this.setState({title: e.target.value})}/>
+              </div>
+              <div className="temp-text">
+                <span>妯℃澘绫诲瀷锛�</span>
+                <Select value={tempTypeClass} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({tempTypeClass: val, tempTypeName: option.props.children})}>
+                  {tempTypes.map(option =>
+                    <Select.Option key={option.data_code} value={option.data_code}>{option.data_name}</Select.Option>
+                  )}
+                </Select>
+              </div>
+              <div className="temp-action">
+                <Button onClick={() => this.triggerTempsave()}>淇濆瓨</Button>
+                <Button onClick={this.triggerclose}>鍏抽棴</Button>
+              </div>
+            </div>
+            <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+          </div>
+        </div>
+      )
+    }
   }
 }
 
diff --git a/src/tabviews/custom/components/module/voucher/index.scss b/src/tabviews/custom/components/module/voucher/index.scss
index 4eec234..b3e1c34 100644
--- a/src/tabviews/custom/components/module/voucher/index.scss
+++ b/src/tabviews/custom/components/module/voucher/index.scss
@@ -14,13 +14,31 @@
     padding: 10px;
     border-bottom: 1px solid #eeeeee;
 
-    .header-btn {
+    .ant-btn {
       height: 28px;
       min-width: 80px;
       margin-right: 10px;
+      background-color: #ffffff;
+      border-color: #d8d8d8;
+      color: rgba(0, 0, 0, 0.65);
+    }
+    .ant-btn[disabled] {
+      background-color: #dadada!important;
+      border-color: #dadada!important;
+      color: #ffffff!important;
+    }
+    .ant-btn:not([disabled]):hover {
+      background-color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+      color: #ffffff;
     }
   }
   .voucher-body {
+    .voucher-number {
+      display: inline-block;
+      white-space: nowrap;
+      margin-right: 15px;
+    }
     .voucher-code {
       display: inline-block;
       width: 160px;
@@ -52,6 +70,10 @@
     }
     .pre-wrap {
       padding: 10px 0px;
+
+      .ant-input.ant-input-disabled, .ant-input-number.ant-input-number-disabled, .ant-select.ant-select-disabled {
+        color: rgba(0, 0, 0, 0.65);
+      }
     }
     .voucher-date {
       display: inline-block;
@@ -61,7 +83,7 @@
     }
     .voucher-text {
       display: inline-block;
-      width: calc(56% - 350px);
+      width: calc(68% - 545px);
       margin-left: 12px;
     }
     .voucher-affix {
@@ -91,42 +113,14 @@
         .ant-btn {
           margin-left: 15px;
         }
+        .ant-btn:hover {
+          color: var(--mk-sys-color);
+          border-color: var(--mk-sys-color);
+        }
       }
     }
   }
 
-  .add-background {
-    background: #26C281;
-    border-color: #26C281;
-    color: #ffffff;
-  }
-  .print-background {
-    background-color: #8E44AD;
-    border-color: #8E44AD;
-    color: #ffffff;
-  }
-  .out-background {
-    background-color: rgb(50, 197, 210);
-    border-color: rgb(50, 197, 210);
-    color: #ffffff;
-  }
-
-  .save-temp {
-    background-color: var(--mk-sys-color);
-    border-color: var(--mk-sys-color);
-    color: #ffffff;
-  }
-  .close-temp {
-    background-color: #ffffff;
-    border-color: #f5222d;
-    color: #f5222d;
-  }
-
-  .system-background {
-    background: var(--mk-sys-color);
-    border-color: var(--mk-sys-color);
-    color: #ffffff;
-  }
   .user {
     padding: 15px 30px 0px;
   }
@@ -145,10 +139,19 @@
   border: 1px solid #d8d8d8;
   border-radius: 4px;
   min-height: 66px;
+  overflow: hidden;
+
   .ant-btn {
     display: block;
     width: 100%;
     border: none;
+    color: rgba(0, 0, 0, 0.65);
+    border-radius: 0;
+  }
+  .ant-btn:not([disabled]):hover {
+    background-color: var(--mk-sys-color);
+    border-color: var(--mk-sys-color);
+    color: #ffffff;
   }
   .split {
     width: 100%;
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx b/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
index cbf864d..652b60d 100644
--- a/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
@@ -231,6 +231,7 @@
   }
 
   render() {
+    const { disabled } = this.props
     const { visible, upVisible, docVisible, files, list, documents, loading } = this.state
 
     return (
@@ -248,8 +249,8 @@
           destroyOnClose
         >
           {loading ? <Spin /> : null}
-          <Button type="link" className="attach-type-btn" disabled={loading} onClick={() => this.setState({upVisible: true})}>涓婁紶鏂版枃浠�</Button>
-          <Button type="link" className="attach-type-btn" disabled={loading} onClick={() => this.setState({docVisible: true, selectDocs: []})}>浠庝細璁$數瀛愭。妗堥�夋嫨</Button>
+          <Button type="link" className="attach-type-btn" disabled={loading || disabled} onClick={() => this.setState({upVisible: true})}>涓婁紶鏂版枃浠�</Button>
+          <Button type="link" className="attach-type-btn" disabled={loading || disabled} onClick={() => this.setState({docVisible: true, selectDocs: []})}>浠庝細璁$數瀛愭。妗堥�夋嫨</Button>
           <div className="attach-selected-list">
             {list.map(item => {
               return <div className="attach-item" key={item.id}>
@@ -259,7 +260,7 @@
                   <div>{item.data_name ? item.data_name + ' / ' : ''}{item.attachments_title}</div>
                 </div>
                 <div>
-                  <DeleteOutlined onClick={() => this.deleteFile(item.id)}/>
+                  {!disabled ? <DeleteOutlined onClick={() => this.deleteFile(item.id)}/> : null}
                 </div>
               </div>
             })}
diff --git a/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx b/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx
index a2a28b9..53af62e 100644
--- a/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx
@@ -37,7 +37,7 @@
   }
 
   render() {
-    const { ID } = this.props
+    const { ID, disabled } = this.props
     const { visible, remark } = this.state
 
     return (
@@ -52,7 +52,7 @@
           onCancel={() => { this.setState({ visible: false })}}
           destroyOnClose
         >
-          <TextArea id={ID} defaultValue={remark} rows={6}/>
+          <TextArea id={ID} disabled={disabled} defaultValue={remark} rows={6}/>
         </Modal>
       </>
     )
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
index ba436ea..6edc5b7 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
@@ -712,7 +712,9 @@
       if (record.type === 'total') {
         children = <div className="content-wrap" style={{lineHeight: '60px'}}>鍚堣: {val}</div>
         colSpan = 2
-      } else {
+      } else if (record.$disabled) {
+        children = <div className="content-wrap">{val}</div>
+      } else  {
         extra = <PlusOutlined onClick={this.plusLine}/>
 
         if (editing) {
@@ -817,6 +819,17 @@
                   <span><InputNumber precision={4} className="inner-input" id={col.uuid + record.uuid + 'price'} defaultValue={record.net_unitprice || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.pricePress} onBlur={this.priceBlur}/></span>
                 </span>
               </div>
+            } else if (record.$disabled) {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}}>
+                  <span>鏁伴噺锛�</span>
+                  <span>{record.fcc_count || 0}</span>
+                </span>
+                <span>
+                  <span>鍗曚环锛�</span>
+                  <span>{record.net_unitprice || 0}</span>
+                </span>
+              </div>
             } else {
               countNode = <div className="count-wrap">
                 <span style={{marginRight: '5px'}} onClick={this.editCount}>
@@ -891,6 +904,21 @@
                   <span><InputNumber precision={2} className="inner-input" id={col.uuid + record.uuid + 'origin'} defaultValue={record.foreign_amount || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.originPress} onBlur={this.originBlur}/></span>
                 </span>
               </div>
+            } else if (record.$disabled) {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.foreign_amount || 0}</span>
+                </span>
+              </div>
             } else {
               currencyNode = <div className="count-wrap">
                 <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
@@ -909,11 +937,19 @@
             }
           }
 
-          children = <div className="content-wrap" onClick={this.focus}>
-            {val}
-            {countNode}
-            {currencyNode}
-          </div>
+          if (record.$disabled) {
+            children = <div className="content-wrap">
+              {val}
+              {countNode}
+              {currencyNode}
+            </div>
+          } else {
+            children = <div className="content-wrap" onClick={this.focus}>
+              {val}
+              {countNode}
+              {currencyNode}
+            </div>
+          }
         }
       }
     } else if (col.field === 'debit') {
@@ -930,13 +966,23 @@
           }
           vals = (val * 100).toFixed(0).split('').reverse()
         }
-        children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
-          <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
-          <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
-        </div>
+        
+        if (record.$disabled) {
+          children = <div className={'money-uint' + (down ? ' down' : '')}>
+            <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
+            <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
+          </div>
+        } else {
+          children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
+            <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
+            <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
+          </div>
+        }
       }
     } else if (col.field === 'credit') {
-      extra = <CloseOutlined onClick={this.delVoucher}/>
+      if (record.type !== 'total' && !record.$disabled) {
+        extra = <CloseOutlined onClick={this.delVoucher}/>
+      }
 
       if (editing) {
         children = <InputNumber id={col.uuid + record.uuid} precision={2} defaultValue={record.credit} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
@@ -951,10 +997,18 @@
           }
           vals = (val * 100).toFixed(0).split('').reverse()
         }
-        children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
-        <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
-        <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
-      </div>
+
+        if (record.$disabled) {
+          children = <div className={'money-uint' + (down ? ' down' : '')}>
+            <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
+            <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
+          </div>
+        } else {
+          children = <div className={'money-uint' + (down ? ' down' : '')} onClick={this.focus}>
+            <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
+            <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
+          </div>
+        }
       }
     }
 
@@ -966,17 +1020,17 @@
 
 class VoucherTable extends Component {
   static propTpyes = {
-    config: PropTypes.object,        // 鑿滃崟Id
-    data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
-    loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
-    onChange: PropTypes.func,        // 琛ㄦ牸鍙樺姩
+    config: PropTypes.object,
+    data: PropTypes.any,
+    loading: PropTypes.bool,
+    onChange: PropTypes.func
   }
 
   state = {
     data: [],
     edData: [],
-    tableId: '',          // 琛ㄦ牸ID
-    columns: null,        // 鏄剧ず鍒�
+    tableId: '',
+    columns: null,
   }
 
   UNSAFE_componentWillMount () {
@@ -1105,9 +1159,11 @@
       return item
     })
 
+    let disabled = _data[0] && _data[0].$disabled ? true : false
+
     if (_data.length < 4) {
       for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getguid(), index: i + 1, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''})
+        _data.push({uuid: Utils.getguid(), $disabled: disabled, index: i + 1, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''})
       }
     }
     return _data
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
index 131b529..b25955b 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
@@ -10,9 +10,8 @@
     position: absolute;
     bottom: 10px;
   }
-  >.ant-table-wrapper {
+  .ant-table-wrapper {
     position: relative;
-    z-index: 1;
   }
   .ant-table {
     color: inherit;
diff --git a/src/tabviews/custom/components/share/normalTable/index.jsx b/src/tabviews/custom/components/share/normalTable/index.jsx
index 66f8c96..04f091d 100644
--- a/src/tabviews/custom/components/share/normalTable/index.jsx
+++ b/src/tabviews/custom/components/share/normalTable/index.jsx
@@ -20,6 +20,63 @@
   '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
   '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
 }
+
+// 瀛楁閫忚
+const triggerLink = (e, item, record) => {
+  e.stopPropagation()
+
+  if (item.linkThdMenu) {
+    let __param = {
+      $BID: record.$$uuid
+    }
+
+    if (item.field) {
+      __param.$searchkey = item.field.toLowerCase()
+      __param.$searchval = record[item.field] || ''
+    }
+  
+    if (item.linkThdMenu.urlFields) {
+      let lower = {}
+      Object.keys(record).forEach(key => {
+        lower[key.toLowerCase()] = record[key]
+      })
+
+      item.linkThdMenu.urlFields.split(',').forEach(field => {
+        __param[field] = lower[field.toLowerCase()] || ''
+      })
+    } else if (item.linkfields && item.linkfields.length > 0) {
+      item.linkfields.forEach(field => {
+        __param[field] = record[field] || ''
+      })
+    }
+
+    let tabmenu = item.linkThdMenu
+
+    tabmenu.param = __param
+
+    MKEmitter.emit('modifyTabs', tabmenu, true)
+  } else if (item.linkurl) {
+    let src = item.linkurl
+
+    let con = '?'
+
+    if (/\?/ig.test(src)) {
+      con = '&'
+    }
+
+    if (item.linkfields && item.linkfields.length > 0) {
+      item.linkfields.forEach(field => {
+        if (field.toLowerCase() === 'id') return
+        con += `${field}=${record[field] || ''}&`
+      })
+    }
+    
+    src = src + `${con}id=${record.$$uuid}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}`
+
+    window.open(src)
+  }
+}
+
 class BodyRow extends React.Component {
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.props.data), fromJS(nextProps.data)) || this.props.className !== nextProps.className
@@ -107,7 +164,7 @@
   }
 
   render() {
-    let { col, config, record, className, style, triggerLink, ...resProps } = this.props
+    let { col, config, record, className, style, ...resProps } = this.props
 
     if (!col) return (<td {...resProps} className={className} style={style}/>)
 
@@ -169,10 +226,7 @@
       resProps.children = content
 
       if (!record.$disabled && (col.linkThdMenu || col.linkurl)) {
-        style = style || {}
-        style.cursor = 'pointer'
-
-        return (<td {...resProps} className={className} onDoubleClick={() => triggerLink(col, record)} style={style}/>)
+        return (<td {...resProps} className={className + ' clickable'} onClick={(e) => triggerLink(e, col, record)} style={style}/>)
       }
     } else if (col.type === 'number') {
       let content = ''
@@ -202,6 +256,7 @@
         }
   
         if (col.format === 'thdSeparator') {
+          content = content + ''
           content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
         }
   
@@ -243,10 +298,7 @@
       resProps.children = content
 
       if (!record.$disabled && (col.linkThdMenu || col.linkurl)) {
-        style = style || {}
-        style.cursor = 'pointer'
-
-        return (<td {...resProps} className={className} onDoubleClick={() => triggerLink(col, record)} style={style}/>)
+        return (<td {...resProps} className={className + ' clickable'} onClick={(e) => triggerLink(e, col, record)} style={style}/>)
       }
     } else if (col.type === 'picture') {
       let photos = ''
@@ -528,7 +580,6 @@
                 record,
                 col: item,
                 config: item.type === 'custom' ? {setting, columns: fields} : null,
-                triggerLink: this.triggerLink
               })
             }
           }
@@ -802,48 +853,6 @@
   
       MKEmitter.emit('resetSelectLine', MenuID, '', '')
       MKEmitter.emit('syncBalconyData', MenuID, [], false)
-    }
-  }
-
-  // 瀛楁閫忚
-  triggerLink = (item, record) => {
-    let __param = {
-      $searchkey: item.field,
-      $searchval: record[item.field] || '',
-      $BID: record.$$uuid
-    }
-
-    if (item.linkfields && item.linkfields.length > 0) {
-      item.linkfields.forEach(field => {
-        __param[field] = record[field] || ''
-      })
-    }
-
-    if (item.linkThdMenu) {
-      let tabmenu = item.linkThdMenu
-
-      tabmenu.param = __param
-
-      MKEmitter.emit('modifyTabs', tabmenu, true)
-    } else if (item.linkurl) {
-      let src = item.linkurl
-
-      let con = '?'
-
-      if (/\?/ig.test(src)) {
-        con = '&'
-      }
-
-      if (item.linkfields && item.linkfields.length > 0) {
-        item.linkfields.forEach(field => {
-          if (field.toLowerCase() === 'id') return
-          con += `${field}=${record[field] || ''}&`
-        })
-      }
-      
-      src = src + `${con}id=${record.$$uuid}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}`
-
-      window.open(src)
     }
   }
 
@@ -1159,7 +1168,7 @@
     }
 
     return (
-      <div className={`normal-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed}`} style={style}>
+      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed}`} style={style}>
         {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
           <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} /> : null
         }
diff --git a/src/tabviews/custom/components/share/normalTable/index.scss b/src/tabviews/custom/components/share/normalTable/index.scss
index 6dbd534..a7688af 100644
--- a/src/tabviews/custom/components/share/normalTable/index.scss
+++ b/src/tabviews/custom/components/share/normalTable/index.scss
@@ -24,13 +24,20 @@
     position: absolute;
     bottom: 10px;
   }
-  >.ant-table-wrapper {
+  .ant-table-wrapper {
     position: relative;
-    z-index: 1;
   }
   .ant-table {
     color: inherit;
     font-size: inherit;
+  }
+
+  .clickable {
+    color: var(--mk-sys-color);
+    cursor: pointer;
+  }
+  .clickable:hover {
+    text-decoration: underline;
   }
 
   .mk-disabled {
@@ -201,6 +208,11 @@
     color: var(--mk-table-color);
   }
 }
+.normal-custom-table.mk-parity {
+  .ant-table-tbody tr:nth-child(even) {
+    background: #fafafa;
+  }
+}
 .normal-custom-table:not(.ghost) {
   .ant-table-small > .ant-table-content .ant-table-thead > tr > th {
     background-color: #fafafa!important;
diff --git a/src/tabviews/custom/components/share/normalheader/index.scss b/src/tabviews/custom/components/share/normalheader/index.scss
index 8de5a23..eb5e5b9 100644
--- a/src/tabviews/custom/components/share/normalheader/index.scss
+++ b/src/tabviews/custom/components/share/normalheader/index.scss
@@ -12,6 +12,7 @@
     text-decoration: inherit;
     font-weight: inherit;
     font-style: inherit;
+    font-family: inherit;
     float: left;
     line-height: inherit;
     margin-left: 10px;
@@ -38,6 +39,9 @@
         .ant-input-search-button {
           height: 28px;
         }
+        .ant-form-explain {
+          display: none;
+        }
       }
     }
   }
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index 2523935..34289a8 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -294,9 +294,7 @@
         )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
-          <Col span={item.width} style={style} key={item.uuid}>
-            <NormalGroup config={item}/>
-          </Col>
+          <NormalGroup config={item} style={style} key={item.uuid}/>
         )
       } else if (item.type === 'form' && item.subtype === 'simpleform') {
         return (
diff --git a/src/tabviews/custom/components/table/base-table/index.jsx b/src/tabviews/custom/components/table/base-table/index.jsx
index ec29c8f..50dd7bc 100644
--- a/src/tabviews/custom/components/table/base-table/index.jsx
+++ b/src/tabviews/custom/components/table/base-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { notification, Modal } from 'antd'
+import { notification } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -143,6 +143,7 @@
     this.requestId = config.uuid + new Date().getTime()
 
     let result = await Api.genericInterface(param, setting.js_script, '', this.requestId)
+
     if (result.status) {
       if (result.$requestId && this.requestId !== result.$requestId) return
 
@@ -228,19 +229,7 @@
         }
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
@@ -250,18 +239,7 @@
         MKEmitter.emit('autoMaticError', config.MenuID)
       }
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -383,11 +361,8 @@
       this.setState({
         loading: false
       })
-      notification.error({
-        top: 92,
-        message: result.message,
-        duration: 10
-      })
+      
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/table/edit-table/index.jsx b/src/tabviews/custom/components/table/edit-table/index.jsx
index 14776ec..1987005 100644
--- a/src/tabviews/custom/components/table/edit-table/index.jsx
+++ b/src/tabviews/custom/components/table/edit-table/index.jsx
@@ -1,7 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { notification, Modal } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -355,36 +354,13 @@
 
       MKEmitter.emit('transferData' + setting.tableId, data)
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -487,11 +463,8 @@
       this.setState({
         loading: false
       })
-      notification.error({
-        top: 92,
-        message: result.message,
-        duration: 10
-      })
+      
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx b/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
index 4bcdb13..6909089 100644
--- a/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -866,6 +866,7 @@
         }
   
         if (col.format === 'thdSeparator') {
+          content = content + ''
           content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
         }
   
@@ -1190,6 +1191,7 @@
           }
     
           if (col.format === 'thdSeparator') {
+            content = content + ''
             content = content.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
           }
     
@@ -2652,7 +2654,7 @@
         {setting.hasSubmit && edData.length > 0 ? <div className="edit-custom-table-btn-wrap" style={submit.wrapStyle}>
           <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-table" type="link">鎻愪氦</Button>
         </div> : null}
-        <div className={`edit-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} style={style}>
+        <div className={`edit-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} style={style}>
           <Table
             rowKey="$$uuid"
             components={components}
diff --git a/src/tabviews/custom/components/table/edit-table/normalTable/index.scss b/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
index a3362b3..52f01f0 100644
--- a/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -7,9 +7,8 @@
   --mk-table-font-size: 14px;
   --mk-table-font-weight: normal;
 
-  >.ant-table-wrapper {
+  .ant-table-wrapper {
     position: relative;
-    // z-index: 1;
   }
   .ant-table-placeholder {
     border-top-color: var(--mk-table-border-color);
@@ -269,6 +268,11 @@
   //   }
   // }
 }
+.edit-custom-table.mk-parity {
+  .ant-table-tbody tr:nth-child(even) {
+    background: #fafafa;
+  }
+}
 .edit-custom-table.mk-edit-simple {
   table tbody tr td {
     min-height: 32px;
diff --git a/src/tabviews/custom/components/table/normal-table/index.jsx b/src/tabviews/custom/components/table/normal-table/index.jsx
index 92c7018..c2ba689 100644
--- a/src/tabviews/custom/components/table/normal-table/index.jsx
+++ b/src/tabviews/custom/components/table/normal-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { notification, Collapse, Modal } from 'antd'
+import { Collapse } from 'antd'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
@@ -43,6 +43,7 @@
   }
 
   loaded = false
+  supModules = []
 
   /**
    * @description 鍒濆鍖栧鐞�
@@ -529,37 +530,14 @@
         }
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -685,11 +663,8 @@
       this.setState({
         loading: false
       })
-      notification.error({
-        top: 92,
-        message: result.message,
-        duration: 10
-      })
+      
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -780,20 +755,41 @@
   }
 
   resetParentParam = (MenuID, id, data) => {
-    const { setting } = this.state
+    const { config, setting } = this.state
 
-    if (!setting.supModule || setting.supModule !== MenuID) return
+    if (config.supNodes) {
+      if (!config.supNodes.includes(MenuID)) return
+      this.supModules = this.supModules.filter(item => item.key !== MenuID)
+      let bid = ''
+      let _data = null
 
-    if (id !== this.state.BID || id !== '') {
-      this.setState({
-        pageIndex: 1,
-        BID: id,
-        BData: data
-      }, () => {
-        if (!setting.checkBid) {
+      if (id) {
+        this.supModules.push({key: MenuID, value: id, data})
+      }
+      if (this.supModules.length > 0) {
+        bid = this.supModules[this.supModules.length - 1].value
+        _data = this.supModules[this.supModules.length - 1].data
+      }
+
+      if (bid !== this.state.BID || bid !== '') {
+        this.setState({ BID: bid, BData: _data, pageIndex: 1 }, () => {
           this.loadmaindata(true, 'true')
-        }
-      })
+        })
+      }
+    } else {
+      if (!setting.supModule || setting.supModule !== MenuID) return
+  
+      if (id !== this.state.BID || id !== '') {
+        this.setState({
+          pageIndex: 1,
+          BID: id,
+          BData: data
+        }, () => {
+          if (!setting.checkBid) {
+            this.loadmaindata(true, 'true')
+          }
+        })
+      }
     }
   }
 
@@ -808,16 +804,41 @@
 
     if (config.uuid !== menuId) return
 
-    if (position === 'line' || position === 'line_grid') {
-      if (lines && lines.length === 1) {
-        this.loadLinedata(lines[0].$$uuid, position)
+    if (config.supNodes) {
+      if (position === 'mainline' || position === 'popclose') {
+        let supNode = this.supModules[this.supModules.length - 1]
+        config.supNodes.forEach((item, i) => {
+          setTimeout(() => {
+            if (supNode && supNode.key === item) {
+              MKEmitter.emit('reloadData', item, supNode.value)
+            } else {
+              MKEmitter.emit('reloadData', item)
+            }
+          }, i * 10)
+        })
+      } else {
+        if (position === 'line' || position === 'line_grid') {
+          if (lines && lines.length === 1) {
+            this.loadLinedata(lines[0].$$uuid, position)
+          } else {
+            this.reloadtable(btn, id)
+          }
+        } else {
+          this.reloadtable(btn, id)
+        }
+      }
+    } else {
+      if (position === 'line' || position === 'line_grid') {
+        if (lines && lines.length === 1) {
+          this.loadLinedata(lines[0].$$uuid, position)
+        } else {
+          this.reloadtable(btn, id)
+        }
+      } else if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) { // 鍒锋柊婧愮粍浠舵椂锛岄檮甯﹀埛鏂颁笂绾ц涓庡綋鍓嶇粍浠�
+        MKEmitter.emit('reloadData', config.setting.supModule, BID)
       } else {
         this.reloadtable(btn, id)
       }
-    } else if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) { // 鍒锋柊婧愮粍浠舵椂锛岄檮甯﹀埛鏂颁笂绾ц涓庡綋鍓嶇粍浠�
-      MKEmitter.emit('reloadData', config.setting.supModule, BID)
-    } else {
-      this.reloadtable(btn, id)
     }
   }
 
diff --git a/src/tabviews/custom/components/timeline/normal-timeline/index.jsx b/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
index 698328e..e2444f1 100644
--- a/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
+++ b/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Timeline, Empty, Modal } from 'antd'
+import { Spin, notification, Timeline, Empty } from 'antd'
 
 import Api from '@/api'
 import MkIcon from '@/components/mk-icon'
@@ -377,37 +377,14 @@
         }
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
diff --git a/src/tabviews/custom/components/tree/antd-tree/index.jsx b/src/tabviews/custom/components/tree/antd-tree/index.jsx
index 721d876..e218c48 100644
--- a/src/tabviews/custom/components/tree/antd-tree/index.jsx
+++ b/src/tabviews/custom/components/tree/antd-tree/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Empty, notification, Input, Tree, Modal, Dropdown } from 'antd'
+import { Spin, Empty, Input, Tree, Dropdown } from 'antd'
 import { FolderOpenOutlined, FolderOutlined, FileOutlined, MoreOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -31,6 +31,7 @@
     treeNodes: null,           // 鍒楄〃鏁版嵁闆�
     expandedKeys: [],          // 灞曞紑鐨勬爲鑺傜偣
     selectedKeys: [],          // 閫変腑鐨勬爲鑺傜偣
+    lineActions: [],
     selected: false            // 閫変腑棣栬
   }
 
@@ -71,13 +72,28 @@
       }
     }
 
+    let lineActions = []
+    _config.action = _config.action || []
+    _config.action = _config.action.filter(item => {
+      if (item.Ot === 'requiredSgl') {
+        lineActions.push(item)
+        return false
+      }
+      return true
+    })
+
     _config.wrap.contentHeight = config.wrap.title || config.wrap.searchable === 'true' ? 'calc(100% - 45px)' : '100%'
+
+    if (_config.wrap.lineHeight) {
+      _config.style['--mk-tree-line-height'] = _config.wrap.lineHeight + 'px'
+    }
 
     this.setState({
       selected: _config.wrap.selected === 'true',
       config: _config,
       data: _data,
-      BID: BID || ''
+      BID: BID || '',
+      lineActions
     })
   }
 
@@ -254,7 +270,7 @@
    * @param {*} position   // 鍒锋柊浣嶇疆
    * @param {*} btn        // 鎵ц鐨勬寜閽�
    */
-  refreshByButtonResult = (menuId, position, btn) => {
+  refreshByButtonResult = (menuId, position) => {
     const { config, BID } = this.state
 
     if (config.uuid !== menuId) return
@@ -321,37 +337,14 @@
         }
       }
 
-      if (result.message) {
-        if (result.ErrCode === 'Y') {
-          Modal.success({
-            title: result.message
-          })
-        } else if (result.ErrCode === 'S') {
-          notification.success({
-            top: 92,
-            message: result.message,
-            duration: 2
-          })
-        }
-      }
+      UtilsDM.querySuccess(result)
     } else {
       this.setState({
         loading: false
       })
       this.timer && this.timer.stop()
       
-      if (!result.message) return
-      if (result.ErrCode === 'N') {
-        Modal.error({
-          title: result.message,
-        })
-      } else if (result.ErrCode !== '-2') {
-        notification.error({
-          top: 92,
-          message: result.message,
-          duration: 10
-        })
-      }
+      UtilsDM.queryFail(result)
     }
   }
 
@@ -376,9 +369,9 @@
     let hasSelectKey = false
 
     data.forEach(item => {
-      let pval = item[config.wrap.parentField]
-      let val = item[config.wrap.valueField]
-      let uuid = item[config.setting.primaryKey] || ''
+      let pval = item[config.wrap.parentField] + ''
+      let val = item[config.wrap.valueField] + ''
+      let uuid = item[config.setting.primaryKey] + ''
 
       if (!val || logMap.has(val)) return
 
@@ -528,30 +521,45 @@
     })
   }
 
-  renderActionTreeNodes = (nodes) => {
+  renderActionTreeNodes = (nodes, actShow) => {
     return nodes.map(item => {
-      let title = <>
-        {item.$title}
-        <Dropdown overlay={
-          <div className="mk-tree-dropdown-wrap" onClick={(e) => e.stopPropagation()}>
-            <MainAction
-              BID={this.state.BID}
-              BData={this.state.BData}
-              setting={this.state.config.setting}
-              actions={this.state.config.action}
-              columns={this.state.config.columns}
-              selectedData={[{...item, children: ''}]}
-            />
-          </div>
-        } placement="bottomCenter" trigger={['hover']}>
-          <MoreOutlined onClick={(e) => e.stopPropagation()}/>
-        </Dropdown>
-      </>
+      let title = null
+      if (actShow === 'line') {
+        title = <>
+          {item.$title}
+          <MainAction
+            BID={this.state.BID}
+            BData={this.state.BData}
+            setting={this.state.config.setting}
+            actions={this.state.lineActions}
+            columns={this.state.config.columns}
+            selectedData={[{...item, children: ''}]}
+          />
+        </>
+      } else {
+        title = <>
+          {item.$title}
+          <Dropdown overlay={
+            <div className="mk-tree-dropdown-wrap" onClick={(e) => e.stopPropagation()}>
+              <MainAction
+                BID={this.state.BID}
+                BData={this.state.BData}
+                setting={this.state.config.setting}
+                actions={this.state.lineActions}
+                columns={this.state.config.columns}
+                selectedData={[{...item, children: ''}]}
+              />
+            </div>
+          } placement="bottomCenter" trigger={['hover']}>
+            <MoreOutlined onClick={(e) => e.stopPropagation()}/>
+          </Dropdown>
+        </>
+      }
 
       if (item.children) {
         return (
           <TreeNode icon={<span><FolderOpenOutlined /><FolderOutlined /></span>} title={title} key={item.$key} dataRef={item}>
-            {this.renderActionTreeNodes(item.children)}
+            {this.renderActionTreeNodes(item.children, actShow)}
           </TreeNode>
         )
       }
@@ -614,9 +622,7 @@
   }
 
   render() {
-    const { config, loading, treeNodes, expandedKeys, selectedKeys } = this.state
-
-    let extra = config.action && config.action.length > 0
+    const { BID, BData, config, loading, treeNodes, expandedKeys, selectedKeys, lineActions } = this.state
 
     return (
       <div className="custom-tree-box" id={'anchor' + config.uuid} style={config.style}>
@@ -630,18 +636,26 @@
           <span className={'title ' + (config.wrap.searchable !== 'true' ? 'search-unable' : '')}>{config.wrap.title}</span>
           {config.wrap.searchable === 'true' ? <Search allowClear onSearch={this.treeFilter} /> : null}
         </div> : null}
+        {config.action.length ? <MainAction
+          BID={BID}
+          setting={config.setting}
+          actions={config.action}
+          BData={BData}
+          columns={config.columns}
+          selectedData={[]}
+        /> : null}
         {treeNodes && treeNodes.length > 0 ? <div className="tree-box" style={{height: config.wrap.contentHeight}}>
           <Tree
             blockNode
             onSelect={this.selectTreeNode}
             expandedKeys={expandedKeys}
             selectedKeys={selectedKeys}
-            onRightClick={!extra ? this.changeExpandedAllKeys : null}
+            onRightClick={!lineActions.length ? this.changeExpandedAllKeys : null}
             onExpand={this.changeExpandedKeys}
             showIcon={config.wrap.showIcon === 'true'}
             showLine={config.wrap.showLine === 'true'}
           >
-            {!extra ? this.renderTreeNodes(treeNodes) : this.renderActionTreeNodes(treeNodes)}
+            {!lineActions.length ? this.renderTreeNodes(treeNodes) : this.renderActionTreeNodes(treeNodes, config.wrap.actShow)}
           </Tree>
         </div> : null}
         {treeNodes && treeNodes.length === 0 ? <Empty description={false}/> : null}
diff --git a/src/tabviews/custom/components/tree/antd-tree/index.scss b/src/tabviews/custom/components/tree/antd-tree/index.scss
index eb5df34..84d2037 100644
--- a/src/tabviews/custom/components/tree/antd-tree/index.scss
+++ b/src/tabviews/custom/components/tree/antd-tree/index.scss
@@ -5,6 +5,7 @@
   background-repeat: no-repeat;
   background-size: cover;
   min-height: 50px;
+  --mk-tree-line-height: 24px;
 
   .tree-header {
     position: relative;
@@ -18,6 +19,7 @@
       text-decoration: inherit;
       font-weight: inherit;
       font-style: inherit;
+      font-family: inherit;
       float: left;
       line-height: 45px;
       margin-left: 10px;
@@ -44,6 +46,39 @@
       }
     }
   }
+  .ant-tree-title {
+    .button-list.toolbar-button {
+      position: absolute;
+      right: 0px;
+      top: 0px;
+      padding: 0px;
+      min-height: 24px;
+      height: var(--mk-tree-line-height);
+
+      button {
+        min-width: 20px;
+        margin-bottom: 0px !important;
+        min-height: 24px;
+        border-width: 0px;
+        vertical-align: middle;
+      }
+    }
+  }
+  .ant-tree-node-content-wrapper {
+    .button-list.toolbar-button {
+      opacity: 0;
+      transition: all 0.3s;
+    }
+  }
+  .ant-tree-node-content-wrapper:hover {
+    .button-list.toolbar-button {
+      opacity: 1;
+    }
+  }
+  .ant-tree li .ant-tree-node-content-wrapper, .ant-tree li span.ant-tree-switcher, .ant-tree li span.ant-tree-iconEle {
+    height: var(--mk-tree-line-height);
+    line-height: var(--mk-tree-line-height);
+  }
   .tree-box {
     overflow: auto;
     padding-bottom: 10px;
@@ -61,6 +96,8 @@
         right: 0px;
         padding: 5px 10px;
         color: var(--mk-sys-color);
+        height: var(--mk-tree-line-height);
+        line-height: var(--mk-tree-line-height);
       }
     }
   }
@@ -117,21 +154,22 @@
 .mk-tree-dropdown-wrap {
   box-shadow: 0 0 2px #bcbcbc;
   background: #ffffff;
-  min-width: 85px;
+  min-width: 100px;
   .button-list.toolbar-button {
     padding: 0px;
+    min-height: 36px;
     button {
       display: block;
       margin: 0!important;
       width: 100%;
       border-radius: 0px;
-      padding-left: 15px!important;
-      .anticon {
-        display: none;
-      }
-      .anticon + span {
-        margin-left: 0px;
-      }
+      border: 0px !important;
+      // color: rgba(0, 0, 0, 0.85)!important;
+      // background: transparent !important;
+      min-height: 36px;
+    }
+    button:not(:last-child) {
+      border-bottom: 1px solid #d8d8d8 !important;
     }
   }
 }
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 983d3c3..da25be6 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -41,6 +41,7 @@
 const AntvX6 = asyncComponent(() => import('./components/chart/antv-X6'))
 const Voucher = asyncComponent(() => import('./components/module/voucher'))
 const Account = asyncComponent(() => import('./components/module/account'))
+const Invoice = asyncComponent(() => import('./components/module/invoice'))
 const Iframe = asyncComponent(() => import('./components/iframe'))
 const Calendar = asyncComponent(() => import('./components/calendar'))
 const DebugTable = asyncComponent(() => import('@/tabviews/debugtable'))
@@ -265,18 +266,6 @@
       // 瀛楁閫忚
       config.components.forEach(component => {
         if (component.type !== 'search') return
-
-        if (param.$searchkey) {
-          component.search = component.search.map(item => {
-            if (['text', 'select', 'link', 'checkcard'].includes(item.type) && param.$searchkey === item.field) {
-              item.initval = param.$searchval
-            }
-  
-            return item
-          })
-
-          component.$searches = Utils.initMainSearch(component.search)
-        }
 
         window.GLOB.SearchBox.set(MenuID, component.$searches)
 
@@ -565,8 +554,14 @@
         item.type = 'card'
       }
 
-      if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗″涓婄骇缁勪欢
-        item.setting.supModule = item.supNodes[0].componentId
+      if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗°�乼able澶氫笂绾х粍浠�
+        item.supNodes = item.supNodes.map(node => node.componentId)
+        if (item.supNodes[0]) {
+          item.setting.supModule = item.supNodes[0]
+        } else {
+          item.supNodes = null
+          item.setting.supModule = ''
+        }
       } else if (item.setting && item.setting.supModule && typeof(item.setting.supModule) !== 'string') {
         let pid = item.setting.supModule.pop()
         if (pid && pid !== 'empty') {
@@ -574,13 +569,33 @@
         } else {
           item.setting.supModule = ''
         }
+      } else if (item.type === 'search') {
+        if (item.wrap.supModule) {
+          item.wrap.supModule = item.wrap.supModule.pop()
+        }
       }
 
       // 鎼滅储鏉′欢鍒濆鍖�
       if (item.search) {
         Utils.initSearchVal(item)
 
+        if (urlparam.$searchkey) {
+          item.search.forEach(cell => {
+            if (urlparam.$searchkey === cell.field.toLowerCase() && ['text', 'select', 'link', 'checkcard'].includes(cell.type)) {
+              cell.initval = urlparam.$searchval
+            }
+          })
+        }
+
         item.$searches = Utils.initMainSearch(item.search)
+
+        if (item.type === 'search' && item.wrap.supModule) {
+          if (!item.checkBid) {
+            item.wrap.supModule = ''
+          } else {
+            window.GLOB.SearchBox.set(item.$searchId + 'checkBid', true)
+          }
+        }
       }
 
       let pass = skip
@@ -602,7 +617,7 @@
             cell = this.getPrinter(cell, item.uuid)
           }
 
-          return pass || permAction[cell.uuid]
+          return pass || permAction[cell.uuid] || cell.permission === 'false'
         })
       }
 
@@ -644,7 +659,7 @@
                     cell = this.getPrinter(cell, item.uuid)
                   }
 
-                  return pass || permAction[cell.uuid]
+                  return pass || permAction[cell.uuid] || cell.permission === 'false'
                 } else {
                   cell = this.resetElement(cell)
                 }
@@ -707,7 +722,7 @@
               cell = this.resetElement(cell)
             }
 
-            return cell.eleType !== 'button' || pass || permAction[cell.uuid]
+            return cell.eleType !== 'button' || pass || permAction[cell.uuid] || cell.permission === 'false'
           })
 
           if (card.setting.click === 'menus') {
@@ -749,7 +764,7 @@
               cell = this.resetElement(cell)
             }
 
-            return cell.eleType !== 'button' || pass || permAction[cell.uuid]
+            return cell.eleType !== 'button' || pass || permAction[cell.uuid] || cell.permission === 'false'
           })
         })
       } else if (item.type === 'balcony') {
@@ -773,7 +788,7 @@
             cell = this.resetElement(cell)
           }
 
-          return cell.eleType !== 'button' || pass || permAction[cell.uuid]
+          return cell.eleType !== 'button' || pass || permAction[cell.uuid] || cell.permission === 'false'
         })
       } else if (item.type === 'form') {
         item.subcards = item.subcards.map(group => {
@@ -945,7 +960,7 @@
     if (cell.syncComponentId) {
       if (cell.syncComponentId === item.setting.supModule) {
         cell.syncComponentId = ''
-        if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+        if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
           cell.execSuccess = 'mainline'
         }
       } else if (cell.syncComponentId === 'multiComponent') {
@@ -953,8 +968,17 @@
           return m.syncComId.pop() || ''
         })
 
-        if (item.setting.supModule && ids.includes(item.setting.supModule)) {
-          if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+        if (item.supNodes) {
+          item.supNodes.forEach(node => {
+            if (!ids.includes(node)) return
+
+            if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
+              cell.execSuccess = 'mainline'
+            }
+            ids = ids.filter(id => id !== node)
+          })
+        } else if (item.setting.supModule && ids.includes(item.setting.supModule)) {
+          if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
             cell.execSuccess = 'mainline'
           }
           ids = ids.filter(id => id !== item.setting.supModule)
@@ -980,6 +1004,17 @@
 
     if (cell.marks && cell.marks.length === 0) {
       cell.marks = null
+    }
+    if (cell.anchors && cell.anchors.length === 0) {
+      cell.anchors = null
+    }
+
+    if (cell.linkmenu && cell.linkmenu.length > 0) {
+      let menu_id = cell.linkmenu.pop()
+      cell.linkThdMenu = window.GLOB.mkThdMenus.get(menu_id) || ''
+      if (!cell.linkThdMenu) {
+        cell.link = ''
+      }
     }
 
     if (['text', 'number', 'formula'].includes(cell.eleType)) {
@@ -1071,8 +1106,14 @@
       if (component.setting.useMSearch) {
         if (!window.GLOB.SearchBox.has(component.$searchId)) {
           component.setting.useMSearch = false
-        } else if (window.GLOB.SearchBox.has(component.$searchId + 'required')) {
-          component.$s_req = true
+        } else {
+          if (window.GLOB.SearchBox.has(component.$searchId + 'required')) {
+            component.$s_req = true
+          }
+          if (window.GLOB.SearchBox.has(component.$searchId + 'checkBid')) {
+            component.checkBid = true
+            component.setting.checkBid = true
+          }
         }
       }
 
@@ -1613,9 +1654,7 @@
         )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
-          <Col span={item.width} style={style} key={item.uuid}>
-            <NormalGroup config={item}/>
-          </Col>
+          <NormalGroup config={item} style={style} key={item.uuid}/>
         )
       } else if (item.type === 'editor') {
         return (
@@ -1671,6 +1710,12 @@
             <Account config={item}/>
           </Col>
         )
+      } else if (item.type === 'module' && item.subtype === 'invoice') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <Invoice config={item}/>
+          </Col>
+        )
       } else if (item.type === 'iframe') {
         return (
           <Col span={item.width} style={style} key={item.uuid}>
diff --git a/src/tabviews/custom/popview/index.jsx b/src/tabviews/custom/popview/index.jsx
index ca70341..935f765 100644
--- a/src/tabviews/custom/popview/index.jsx
+++ b/src/tabviews/custom/popview/index.jsx
@@ -135,18 +135,6 @@
     config.components.forEach(component => {
       if (component.type !== 'search') return
 
-      if (param.$searchkey) {
-        component.search = component.search.map(item => {
-          if (['text', 'select', 'link', 'checkcard'].includes(item.type) && param.$searchkey === item.field) {
-            item.initval = param.$searchval
-          }
-
-          return item
-        })
-
-        component.$searches = Utils.initMainSearch(component.search)
-      }
-
       window.GLOB.SearchBox.set(Tab.uuid, component.$searches)
 
       if (component.$s_req) {
@@ -326,8 +314,14 @@
         }
       }
 
-      if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗″涓婄骇缁勪欢
-        item.setting.supModule = item.supNodes[0].componentId
+      if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗°�乼able澶氫笂绾х粍浠�
+        item.supNodes = item.supNodes.map(node => node.componentId)
+        if (item.supNodes[0]) {
+          item.setting.supModule = item.supNodes[0]
+        } else {
+          item.supNodes = null
+          item.setting.supModule = ''
+        }
       } else if (item.setting && item.setting.supModule && typeof(item.setting.supModule) !== 'string') {
         let pid = item.setting.supModule.pop()
         if (pid && pid !== 'empty') {
@@ -663,7 +657,7 @@
     if (cell.syncComponentId) {
       if (cell.syncComponentId === item.setting.supModule) {
         cell.syncComponentId = ''
-        if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+        if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
           cell.execSuccess = 'mainline'
         }
       } else if (cell.syncComponentId === 'multiComponent') {
@@ -671,8 +665,17 @@
           return m.syncComId.pop() || ''
         })
 
-        if (item.setting.supModule && ids.includes(item.setting.supModule)) {
-          if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+        if (item.supNodes) {
+          item.supNodes.forEach(node => {
+            if (!ids.includes(node)) return
+
+            if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
+              cell.execSuccess = 'mainline'
+            }
+            ids = ids.filter(id => id !== node)
+          })
+        } else if (item.setting.supModule && ids.includes(item.setting.supModule)) {
+          if (['line', 'grid', 'line_grid'].includes(cell.execSuccess)) {
             cell.execSuccess = 'mainline'
           }
           ids = ids.filter(id => id !== item.setting.supModule)
@@ -698,6 +701,17 @@
 
     if (cell.marks && cell.marks.length === 0) {
       cell.marks = null
+    }
+    if (cell.anchors && cell.anchors.length === 0) {
+      cell.anchors = null
+    }
+
+    if (cell.linkmenu && cell.linkmenu.length > 0) {
+      let menu_id = cell.linkmenu.pop()
+      cell.linkThdMenu = window.GLOB.mkThdMenus.get(menu_id) || ''
+      if (!cell.linkThdMenu) {
+        cell.link = ''
+      }
     }
 
     if (['text', 'number', 'formula'].includes(cell.eleType)) {
@@ -1121,9 +1135,7 @@
         )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
-          <Col span={item.width} style={style} key={item.uuid}>
-            <NormalGroup config={item}/>
-          </Col>
+          <NormalGroup config={item} style={style} key={item.uuid}/>
         )
       } else if (item.type === 'editor') {
         return (
diff --git a/src/tabviews/debugtable/index.jsx b/src/tabviews/debugtable/index.jsx
index 9f52daa..155332e 100644
--- a/src/tabviews/debugtable/index.jsx
+++ b/src/tabviews/debugtable/index.jsx
@@ -44,6 +44,8 @@
 
     let param = UtilsDM.getQueryDataParams(setting, [], 'sort', 1, 50, '')
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
 
     if (result.status) {
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index c10bc79..39cbb1d 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -221,6 +221,7 @@
 
       let _actions = []     // 宸ュ叿鏍忔寜閽�
       let _operations = []  // 鎿嶄綔鍒楁寜閽紙瀛樺湪鏃讹級
+      let colors = { primary: '#1890ff', yellow: '#c49f47', orange: 'orange', danger: '#ff4d4f', green: '#26C281', dgreen: '#32c5d2', purple: '#8E44AD', cyan: '#13c2c2', gray: '#E7E7EF', default: 'rgba(0, 0, 0, 0.65)' }
 
       config.action.forEach(item => {
         item.logLabel = Tab.label + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
@@ -270,10 +271,25 @@
           }
         }
         
+        item.show = 'button'
+
+        let _c = item.class ? item.class.replace('border-', '') : ''
+        let color = colors[_c] || '#1890ff'
+
         if (item.position === 'toolbar') {
           item.$toolbtn = true
+
+          if (item.class === 'default') {
+            item.style = {color: 'rgba(0, 0, 0, 0.65)', backgroundColor: '#fff', borderColor: '#d9d9d9', marginRight: '15px'}
+          } else if (item.class.indexOf('border') > -1) {
+            item.style = {color: color, backgroundColor: '#fff', borderColor: color, marginRight: '15px'}
+          } else {
+            item.style = {color: item.class === 'gray' ? 'rgba(0, 0, 0, 0.65)' : '#fff', backgroundColor: color, borderColor: color, marginRight: '15px'}
+          }
+
           _actions.push(item)
         } else if (item.position === 'grid') {
+          item.style = {color: color, backgroundColor: 'transparent', borderColor: 'transparent'}
           _operations.push(item)
         }
       })
@@ -464,6 +480,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, searches, _orderBy, pageIndex, pageSize, BID)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
 
     this.getStatFieldsValue(searches)
@@ -550,6 +568,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, searches, _orderBy, pageIndex, pageSize, BID, id)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
     if (result.status) {
       let data = fromJS(this.state.data).toJS()
diff --git a/src/tabviews/subtabtable/index.jsx b/src/tabviews/subtabtable/index.jsx
index 8ba9910..bc3c2db 100644
--- a/src/tabviews/subtabtable/index.jsx
+++ b/src/tabviews/subtabtable/index.jsx
@@ -192,6 +192,7 @@
 
       let _actions = []     // 宸ュ叿鏍忔寜閽�
       let _operations = []  // 鎿嶄綔鍒楁寜閽紙瀛樺湪鏃讹級
+      let colors = { primary: '#1890ff', yellow: '#c49f47', orange: 'orange', danger: '#ff4d4f', green: '#26C281', dgreen: '#32c5d2', purple: '#8E44AD', cyan: '#13c2c2', gray: '#E7E7EF', default: 'rgba(0, 0, 0, 0.65)' }
 
       config.action.forEach(item => {
         item.logLabel = Tab.label + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
@@ -228,10 +229,25 @@
           }
         }
 
+        item.show = 'button'
+
+        let _c = item.class ? item.class.replace('border-', '') : ''
+        let color = colors[_c] || '#1890ff'
+
         if (item.position === 'toolbar') {
           item.$toolbtn = true
+
+          if (item.class === 'default') {
+            item.style = {color: 'rgba(0, 0, 0, 0.65)', backgroundColor: '#fff', borderColor: '#d9d9d9', marginRight: '15px'}
+          } else if (item.class.indexOf('border') > -1) {
+            item.style = {color: color, backgroundColor: '#fff', borderColor: color, marginRight: '15px'}
+          } else {
+            item.style = {color: item.class === 'gray' ? 'rgba(0, 0, 0, 0.65)' : '#fff', backgroundColor: color, borderColor: color, marginRight: '15px'}
+          }
+
           _actions.push(item)
         } else if (item.position === 'grid') {
+          item.style = {color: color, backgroundColor: 'transparent', borderColor: 'transparent'}
           _operations.push(item)
         }
       })
@@ -398,6 +414,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, searches, _orderBy, pageIndex, pageSize, BID)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
 
     this.getStatFieldsValue(searches)
@@ -523,6 +541,8 @@
     let _orderBy = orderBy || setting.order
     let param = UtilsDM.getQueryDataParams(setting, searches, _orderBy, pageIndex, pageSize, BID, id)
 
+    delete param.s_version_up
+
     let result = await Api.genericInterface(param)
     if (result.status) {
       let data = fromJS(this.state.data).toJS()
diff --git a/src/tabviews/treepage/index.jsx b/src/tabviews/treepage/index.jsx
index 00b7d2f..6d08b71 100644
--- a/src/tabviews/treepage/index.jsx
+++ b/src/tabviews/treepage/index.jsx
@@ -265,6 +265,8 @@
 
     let param = UtilsDM.getQueryDataParams(setting, [], setting.order, '', '', BID)
 
+    delete param.s_version_up
+    
     let result = await Api.genericInterface(param)
     if (result.status) {
       let parentNodes = []
diff --git a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
index 8ceb5db..d1f4c8a 100644
--- a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -223,38 +223,23 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return (
       <Button
-        type={type}
+        type="link"
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         loading={loading}
         disabled={disabled}
         style={btn.style}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/editLine/index.jsx b/src/tabviews/zshare/actionList/editLine/index.jsx
index 142d977..2ce6835 100644
--- a/src/tabviews/zshare/actionList/editLine/index.jsx
+++ b/src/tabviews/zshare/actionList/editLine/index.jsx
@@ -109,37 +109,22 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <MkIcon type={btn.icon} />
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return (
       <Button
-        type={type}
+        type="link"
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         disabled={disabled}
         style={btn.style}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/excelInbutton/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
index bfc7d78..b14214d 100644
--- a/src/tabviews/zshare/actionList/excelInbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -408,6 +408,9 @@
         param.username = sessionStorage.getItem('User_Name') || ''
         param.fullname = sessionStorage.getItem('Full_Name') || ''
       }
+      if (btn.dataM === 'true') {
+        param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
+      }
 
       Api.genericInterface(param).then((res) => {
         if (res.status) {
@@ -534,39 +537,24 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || 'upload'
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return <>
       <Button
-        type={type}
+        type="link"
         id={'button' + btn.uuid}
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         loading={loading}
         disabled={disabled}
         style={btn.style}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
       <ExcelIn btn={btn} triggerExcelIn={() => this.setState({ loading: true })} returndata={this.getexceldata} ref="excelIn" />
diff --git a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
index 5db6635..f16a983 100644
--- a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -184,6 +184,9 @@
           param.username = sessionStorage.getItem('User_Name') || ''
           param.fullname = sessionStorage.getItem('Full_Name') || ''
         }
+        if (btn.dataM === 'true') {
+          param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
+        }
 
         Api.genericInterface(param).then(result => {
           if (result.status) {
@@ -387,6 +390,9 @@
         param.username = sessionStorage.getItem('User_Name') || ''
         param.fullname = sessionStorage.getItem('Full_Name') || ''
       }
+      if (btn.dataM === 'true') {
+        param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
+      }
 
     } else if (btn.intertype === 'outer' && !btn.innerFunc) { // 浣跨敤澶栭儴鍑芥暟
       param = this.getExcelCustomParam(viewParam.orderBy, viewParam.search, true, pageIndex, pageSize)
@@ -443,23 +449,70 @@
   /**
    * @description Excel 鐢熸垚
    */
-  exportExcel = (data, ErrCode, msg, search) => {
+  exportExcel = (data = [], ErrCode, msg, search) => {
     const { btn } = this.props
     
     let imgCol = false
-    let columns = btn.verify.columns.map(col => {
+    let merge = false
+    let styles = []
+    let letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+
+    let columns = btn.verify.columns.map((col, index) => {
       if (col.type === 'image') {
         imgCol = true
       }
+      if (btn.verify.merge === 'true' && /.+-.+/.test(col.Text)) {
+        merge = true
+      }
 
-      if (col.type === 'number' && (col.decimal || col.decimal === 0) ) {
-        col.round = Math.pow(10, col.decimal)
+      let i = Math.floor(index / 26)
+      let s = letters[i - 1] || ''
+      col.name = s + letters[index % 26]
+
+      if (col.type === 'number') {
+        if (col.decimal || col.decimal === 0) {
+          col.round = Math.pow(10, col.decimal)
+
+          if (col.format) {
+            let dec = Array(col.decimal).fill(0).join('')
+            dec = dec ? '.' + dec : ''
+            if (col.format === 'thdSeparator') {
+              col.z = '#,##0' + dec
+            } else if (col.format === 'thdSepPm') {
+              col.z = '#,##0' + dec + ';'
+              col.z = col.z + '[Red]-' + col.z
+            } else if (col.format === 'percent') {
+              let _dec = ''
+              if (col.decimal > 2) {
+                Array(col.decimal - 2).fill(0).join('')
+                _dec = _dec ? '.' + _dec : ''
+              }
+
+              col.z = '0' + _dec + '%'
+            }
+          }
+        }
+      } else if (col.type === 'text') {
+        if (col.wrapText === 'true') {
+          col.s = {alignment: { wrapText: true }}
+        }
+        if (col.textFormat) {
+          if (col.textFormat === 'YYYY-MM-DD') {
+            col.z = 'yyyy-mm-dd;@'
+          } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss') {
+            col.z = 'yyyy-mm-dd hh:mm:ss'
+          }
+        }
+      }
+
+      if (col.z || col.s) {
+        styles.push(col)
       }
 
       return col
     })
 
-    if (data && data[0]) {
+    if (data[0]) {
       let errors = []
       columns.forEach(col => {
         if (col.output === 'false') return
@@ -508,7 +561,7 @@
 
         let table = []
 
-        data && data.forEach((item, index) => {
+        data.forEach((item, index) => {
           let _row = {}
   
           item.$Index = index + 1 + ''
@@ -516,21 +569,48 @@
           columns.forEach((col, i) => {
             let val = item[col.Column]
             if (col.output === 'false') {
-              if (col.type === 'number') {
+              if (col.type === 'number' && col.noValue !== 'false') {
                 val = 0
               } else {
                 val = ''
               }
-            } else if (col.type === 'number' && typeof(val) === 'number') {
-              if (col.abs === 'true') {
-                val = Math.abs(val)
+            } else if (col.type === 'number') {
+              if (val && typeof(val) === 'string' && !isNaN(val)) {
+                val = +val
               }
-              if (col.round) {
-                val = Math.round(val * col.round) / col.round
-                // val = val.toFixed(col.decimal)
+              if (typeof(val) === 'number') {
+                if (col.abs === 'true') {
+                  val = Math.abs(val)
+                }
+                if (col.round) {
+                  val = Math.round(val * col.round) / col.round
+                }
+                if (col.noValue === 'false' && val === 0) {
+                  val = ''
+                }
               }
-              if (col.noValue === 'false' && val === 0) {
+            } else if (col.type === 'text') {
+              val = val + ''
+              
+              if (col.textFormat) {
+                if (col.textFormat === 'YYYY-MM-DD' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1])/.test(val)) {
+                  val = `${val.substr(0, 4)}-${val.substr(5, 2)}-${val.substr(8, 2)}`
+                } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/.test(val)) {
+                  val = `${val.substr(0, 4)}-${val.substr(5, 2)}-${val.substr(8, 2)} ${val.substr(11, 2)}:${val.substr(14, 2)}:${val.substr(17, 2)}`
+                }
+              }
+
+              if (col.noValue === 'false' && val < '1949-10-02') {
                 val = ''
+              }
+            }
+
+            if (val !== '') {
+              if (col.prefix) {
+                val = col.prefix + val
+              }
+              if (col.postfix) {
+                val = val + col.postfix
               }
             }
 
@@ -544,16 +624,6 @@
 
         this.execSuccess({ErrCode: ErrCode || 'S', message: msg || '瀵煎嚭鎴愬姛锛�'})
       } else {
-        let letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
-        let cols = []
-
-        for (let index = 0; index < columns.length; index++) {
-          let i = Math.floor(index / 26)
-          let s = letters[i - 1] || ''
-          
-          cols.push(s + letters[index % 26])
-        }
-
         let table = []
         let _header = []
         let _topRow = {}
@@ -561,16 +631,16 @@
         let requires = []
         let merges = []
 
-        columns.forEach((col, i) => {
+        columns.forEach(col => {
           _header.push(col.Column)
           _topRow[col.Column] = col.Text
           colwidth.push({wch: col.Width || 20})
           if (col.required === 'true') {
-            requires.push(i)
+            requires.push(col.name)
           }
         })
 
-        if (btn.verify.merge === 'true') {
+        if (merge) {
           let fLine = {}
           let sLine = {}
           let sign = ''
@@ -582,16 +652,16 @@
               sLine[col.Column] = _name
 
               if (sign === _sign) {
-                merges[merges.length - 1] = merges[merges.length - 1].split(':')[0] + `:${cols[i]}1`
+                merges[merges.length - 1] = merges[merges.length - 1].split(':')[0] + `:${col.name}1`
               } else {
-                merges.push(`${cols[i]}1:${cols[i]}2`)
+                merges.push(`${col.name}1:${col.name}2`)
                 sign = _sign
               }
             } else {
               fLine[col.Column] = col.Text
               sLine[col.Column] = col.Text
               sign = ''
-              merges.push(`${cols[i]}1:${cols[i]}2`)
+              merges.push(`${col.name}1:${col.name}2`)
             }
           })
 
@@ -601,7 +671,7 @@
           table.push(_topRow)
         }
   
-        data && data.forEach((item, index) => {
+        data.forEach((item, index) => {
           let _row = {}
   
           item.$Index = index + 1 + ''
@@ -610,21 +680,48 @@
             let val = item[col.Column]
 
             if (col.output === 'false') {
-              if (col.type === 'number') {
+              if (col.type === 'number' && col.noValue !== 'false') {
                 val = 0
               } else {
                 val = ''
               }
-            } else if (col.type === 'number' && typeof(val) === 'number') {
-              if (col.abs === 'true') {
-                val = Math.abs(val)
+            } else if (col.type === 'number') {
+              if (val && typeof(val) === 'string' && !isNaN(val)) {
+                val = +val
               }
-              if (col.round) {
-                val = Math.round(val * col.round) / col.round
-                // val = val.toFixed(col.decimal)
+              if (typeof(val) === 'number') {
+                if (col.abs === 'true') {
+                  val = Math.abs(val)
+                }
+                if (col.round) {
+                  val = Math.round(val * col.round) / col.round
+                }
+                if (col.noValue === 'false' && val === 0) {
+                  val = ''
+                }
               }
-              if (col.noValue === 'false' && val === 0) {
+            } else if (col.type === 'text') {
+              val = val + ''
+              
+              if (col.textFormat) {
+                if (col.textFormat === 'YYYY-MM-DD' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1])/.test(val)) {
+                  val = `${val.substr(0, 4)}-${val.substr(5, 2)}-${val.substr(8, 2)}`
+                } else if (col.textFormat === 'YYYY-MM-DD HH:mm:ss' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1]).([0-1][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9]/.test(val)) {
+                  val = `${val.substr(0, 4)}-${val.substr(5, 2)}-${val.substr(8, 2)} ${val.substr(11, 2)}:${val.substr(14, 2)}:${val.substr(17, 2)}`
+                }
+              }
+
+              if (col.noValue === 'false' && val < '1949-10-02') {
                 val = ''
+              }
+            }
+
+            if (val !== '') {
+              if (col.prefix) {
+                val = col.prefix + val
+              }
+              if (col.postfix) {
+                val = val + col.postfix
               }
             }
 
@@ -644,49 +741,46 @@
 
         if (requires.length) {
           requires.forEach(col => {
-            if (cols[col]) {
-              ws[cols[col] + '1'].s = {font: { color: { rgb: 'F5222D' } }}
-            }
+            ws[col + '1'].s = {font: { color: { rgb: 'F5222D' } }}
           })
         }
 
-        if (merges.length) {
+        if (merge) {
           ws['!merges'] = []
           merges.forEach(item => {
             ws['!merges'].push(XLSX.utils.decode_range(item))
           })
 
-          cols.forEach(col => {
-            if (ws[col + '1'].s) {
-              ws[col + '1'].s = {font: { color: { rgb: 'F5222D' } }, alignment: { horizontal: 'center', vertical: 'center' }}
-            } else {
-              ws[col + '1'].s = {alignment: { horizontal: 'center', vertical: 'center' }}
-            }
-            ws[col + '2'].s = {alignment: { horizontal: 'center', vertical: 'center' }}
+          columns.forEach(col => {
+            ws[col.name + '1'].s = ws[col.name + '1'].s || {}
+            ws[col.name + '1'].s.alignment = { horizontal: 'center', vertical: 'center' }
+
+            ws[col.name + '2'].s = {alignment: { horizontal: 'center', vertical: 'center' }}
           })
         }
 
-        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['A3'].s = {font: { sz: 10 , bold: true }, alignment: { horizontal: 'center', vertical: 'center' }, border: {top: {style: 'thin', color: '000000'}, left: {style: 'thin', color: '000000'}, bottom: {style: 'thin', color: '000000'}, right: {style: 'thin', color: '000000'}}};
+        // ws['A3'].z = '#,##0.00';
+        // ws['A3'].z = '#,##0.00;[Red]-#,##0.00;';
+        // ws["A1"].s = {fill: { bgColor: { rgb: "FFFFAA"  }}, font: { color: { rgb: "1890FF" } }}
+
+        if (data.length && styles.length) {
+          for (let n = table.length - data.length + 1; n <= table.length; n++) {
+            styles.forEach(col => {
+              if (col.z) {
+                ws[col.name + n].z = col.z
               }
-            }
+              if (col.s) {
+                ws[col.name + n].s = col.s
+              }
+            })
           }
         }
-
-        // ws["A1"].s = {fill: { bgColor: { rgb: "FFFFAA"  }}, font: { color: { rgb: "1890FF" } }}
 
         const wb = XLSX.utils.book_new()
         XLSX.utils.book_append_sheet(wb, ws, btn.verify.sheet || 'Sheet1')
   
-        XLSX.writeFile(wb, `${btn.$menuName || ''}${moment().format('YYYYMMDDHHmmss')}.xlsx`)
+        XLSX.writeFile(wb, `${btn.verify.excelName || btn.$menuName || ''}${moment().format('YYYYMMDDHHmmss')}.xlsx`)
   
         this.execSuccess({ErrCode: ErrCode || 'S', message: msg || '瀵煎嚭鎴愬姛锛�'})
       }
@@ -784,9 +878,9 @@
       _setting.arr_field = []
 
       btn.verify.columns.forEach(col => {
-        if (col.Column && col.Column !== '$Index') {
-          _setting.arr_field.push(col.Column)
-        }
+        if (col.output === 'false' || !col.Column || col.Column === '$Index') return
+        
+        _setting.arr_field.push(col.Column)
       })
       _setting.arr_field = _setting.arr_field.join(',')
       _setting.execute = btn.verify.defaultSql !== 'false'
@@ -986,39 +1080,24 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || 'download'
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return (
       <Button
-        type={type}
+        type="link"
         id={'button' + btn.uuid}
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         loading={loading}
         disabled={disabled}
         style={btn.style || null}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/exportPdf/index.jsx b/src/tabviews/zshare/actionList/exportPdf/index.jsx
index 8a8ad2e..3678b0b 100644
--- a/src/tabviews/zshare/actionList/exportPdf/index.jsx
+++ b/src/tabviews/zshare/actionList/exportPdf/index.jsx
@@ -109,42 +109,28 @@
     const { btn } = this.props
     const { loading } = this.state
 
-    let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
     let style = {...btn.style}
 
     if (loading) {
       style.opacity = 0
     }
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    let label = ''
+
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <MkIcon type={btn.icon} />
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
     
     return (
       <Button
-        type={type}
+        type="link"
         title={btn.show === 'icon' ? btn.label : ''}
         style={style}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/funcMegvii/index.jsx b/src/tabviews/zshare/actionList/funcMegvii/index.jsx
index 78adb47..19fc33c 100644
--- a/src/tabviews/zshare/actionList/funcMegvii/index.jsx
+++ b/src/tabviews/zshare/actionList/funcMegvii/index.jsx
@@ -514,43 +514,26 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
+    } else if (btn.$toolbtn) {
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{loadingNumber && !loadingTotal ? `(${loadingNumber})` : ''}{btn.label}</span>
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
-    }
-    
-    if (loadingNumber && !loadingTotal && btn.$toolbtn && (!btn.show || btn.show === 'button')) {
-      label = (loadingNumber && !loadingTotal ? `(${loadingNumber})` : '') + btn.label
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return (
       <>
         <Button
-          type={type}
+          type="link"
           title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
           loading={loading}
           disabled={disabled}
           style={btn.style}
-          icon={icon}
-          className={className}
+          className={btn.$toolbtn ? (btn.hover || '') : ''}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{label}</Button>
         {this.getModels()}
diff --git a/src/tabviews/zshare/actionList/funczip/index.jsx b/src/tabviews/zshare/actionList/funczip/index.jsx
index e308d90..534806d 100644
--- a/src/tabviews/zshare/actionList/funczip/index.jsx
+++ b/src/tabviews/zshare/actionList/funczip/index.jsx
@@ -409,42 +409,25 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
     
     return (
-      <>
-        <Button
-          type={type}
-          title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
-          loading={loading}
-          disabled={disabled}
-          style={btn.style}
-          icon={icon}
-          className={className}
-          onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
-        >{label}</Button>
-      </>
+      <Button
+        type="link"
+        title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
+        loading={loading}
+        disabled={disabled}
+        style={btn.style}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
+        onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
+      >{label}</Button>
     )
   }
 }
diff --git a/src/tabviews/zshare/actionList/index.scss b/src/tabviews/zshare/actionList/index.scss
index 23d8916..700f589 100644
--- a/src/tabviews/zshare/actionList/index.scss
+++ b/src/tabviews/zshare/actionList/index.scss
@@ -17,6 +17,19 @@
     padding: 0 15px;
   }
 
+  .ant-btn.mk-btn-hover-bg:not([disabled]):hover {
+    opacity: 1!important;
+    color: #ffffff!important;
+    border-color: var(--mk-sys-color)!important;
+    background-color: var(--mk-sys-color)!important;
+  }
+  .ant-btn.mk-btn-hover-border:not([disabled]):hover {
+    opacity: 1!important;
+    color: var(--mk-sys-color)!important;
+    border-color: var(--mk-sys-color)!important;
+    background-color: #ffffff!important;
+  }
+
   .loading-skeleton {
     background: -webkit-gradient(linear,left top,right top,color-stop(25%,#f5f5f5),color-stop(37%,#ffffff),color-stop(63%,#f5f5f5));
     background: linear-gradient(90deg,#f5f5f5 25%,#ffffff 37%,#f5f5f5 63%);
diff --git a/src/tabviews/zshare/actionList/newpagebutton/index.jsx b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
index 01d678e..0199b4a 100644
--- a/src/tabviews/zshare/actionList/newpagebutton/index.jsx
+++ b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -16,6 +16,7 @@
     btn: PropTypes.object,            // 鎸夐挳
     selectedData: PropTypes.any,      // 瀛愯〃涓�夋嫨鏁版嵁
     disabled: PropTypes.any,          // 琛屾寜閽鐢�
+    name: PropTypes.any
   }
 
   state = {
@@ -159,18 +160,75 @@
 
     if (btn.pageTemplate === 'billprint') {
       _name = '鍗曟嵁鎵撳嵃'
-      if (btn.Ot === 'required') {
-        data.forEach(item => {
-          let _id = item.$$uuid || ''
-          let url = '#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: _id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') })))
-          window.open(url)
-        })
-      } else if (btn.Ot === 'requiredOnce') {
-        Id = data.map(item => item.$$uuid).filter(Boolean).join(',')
+      if (btn.preHandle === 'true' && btn.pre_func) {
+        MKEmitter.emit('queryModuleParam', btn.$menuId, (res) => {
+          let searches = {}
+          res.search && res.search.forEach(item => {
+            searches[item.key] = item.value
+          })
 
-        window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: Id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
+          if (btn.Ot === 'requiredOnce') {
+            Id = data.map(item => item.$$uuid).filter(Boolean).join(',')
+          }
+
+          if (btn.Ot === 'required') {
+            data.forEach(item => {
+              let _param = { id: item.$$uuid || '', tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM')}
+              try {
+                // eslint-disable-next-line
+                let func = new Function('btn', 'searches', 'data', 'param', 'systemType', btn.pre_func)
+                _param = func(btn, searches, [item], _param, window.GLOB.systemType)
+              } catch (e) {
+                console.warn(e)
+              }
+
+              if (!_param || _param.error) {
+                notification.warning({
+                  top: 92,
+                  message: _param ? _param.error : '鏈幏鍙栧埌鎵撳嵃鍙傛暟锛岃嚜瀹氫箟鑴氭湰閿欒锛�',
+                  duration: 5
+                })
+                return
+              }
+              
+              window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify(_param))))
+            })
+          } else {
+            let _param = { id: Id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM')}
+            try {
+              // eslint-disable-next-line
+              let func = new Function('btn', 'searches', 'data', 'param', 'systemType', btn.pre_func)
+              _param = func(btn, searches, data, _param, window.GLOB.systemType)
+            } catch (e) {
+              console.warn(e)
+            }
+
+            if (!_param || _param.error) {
+              notification.warning({
+                top: 92,
+                message: _param ? _param.error : '鏈幏鍙栧埌鎵撳嵃鍙傛暟锛岃嚜瀹氫箟鑴氭湰閿欒锛�',
+                duration: 5
+              })
+              return
+            }
+
+            window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify(_param))))
+          }
+        })
       } else {
-        window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: Id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
+        if (btn.Ot === 'required') {
+          data.forEach(item => {
+            let _id = item.$$uuid || ''
+            let url = '#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: _id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') })))
+            window.open(url)
+          })
+        } else if (btn.Ot === 'requiredOnce') {
+          Id = data.map(item => item.$$uuid).filter(Boolean).join(',')
+  
+          window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: Id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
+        } else {
+          window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: Id, tempId: btn.printTemp, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
+        }
       }
     } else if (btn.pageTemplate === 'billprintTemp') {
       let src = '#/menudesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'billPrint', MenuId: Id, MenuNo: MenuNo, MenuName: name || '鎵撳嵃', Remark: Remark })))
@@ -250,44 +308,29 @@
   }
 
   render() {
-    const { btn } = this.props
+    const { btn, name } = this.props
     const { disabled, hidden } = this.state
 
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{name || btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <MkIcon type={btn.icon} />
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{name || btn.label}</span>
     }
 
     return (
       <Button
-        type={type}
+        type="link"
         id={'button' + btn.uuid}
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         style={btn.style || null}
         disabled={disabled}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/normalbutton/index.jsx b/src/tabviews/zshare/actionList/normalbutton/index.jsx
index f58f2fe..30564b9 100644
--- a/src/tabviews/zshare/actionList/normalbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -28,6 +28,7 @@
     columns: PropTypes.any,           // 瀛楁鍒�
     setting: PropTypes.any,           // 椤甸潰閫氱敤璁剧疆
     disabled: PropTypes.any,          // 琛屾寜閽鐢�
+    name: PropTypes.any
   }
 
   state = {
@@ -755,6 +756,9 @@
         param.username = sessionStorage.getItem('User_Name') || ''
         param.fullname = sessionStorage.getItem('Full_Name') || ''
       }
+      if (btn.dataM === 'true') {
+        param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
+      }
       
       let primaryId = ''
 
@@ -796,6 +800,9 @@
         if (btn.recordUser === 'true') {
           param.username = sessionStorage.getItem('User_Name') || ''
           param.fullname = sessionStorage.getItem('Full_Name') || ''
+        }
+        if (btn.dataM === 'true') {
+          param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
         }
 
         let primaryId = setting.primaryKey ? cell[setting.primaryKey] || '' : ''
@@ -2344,9 +2351,9 @@
       tabId = btn.refreshTab[btn.refreshTab.length - 1]
     }
 
-    if (btn.formCache === 'clear') { // 娓呴櫎琛ㄥ崟缂撳瓨
-      window.GLOB.CacheMap = new Map()
-    }
+    // if (btn.formCache === 'clear') { // 娓呴櫎琛ㄥ崟缂撳瓨
+    //   window.GLOB.CacheMap = new Map()
+    // }
 
     if (tabId && btn.$MenuID === tabId) { // 鍒锋柊褰撳墠鑿滃崟鏃讹紝鍋滄鍏朵粬鎿嶄綔
       MKEmitter.emit('reloadMenuView', tabId, 'table')
@@ -2474,9 +2481,38 @@
 
     if (!id) return
 
-    setTimeout(() => {
-      window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: id, tempId: btn.verify.printTempId, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
-    }, 500)
+    if (btn.verify.preHandle === 'true' && btn.verify.pre_func && /#position-print/.test(btn.verify.pre_func)) {
+      MKEmitter.emit('queryModuleParam', btn.$menuId, (res) => {
+        let searches = {}
+        res.search && res.search.forEach(item => {
+          searches[item.key] = item.value
+        })
+        let _param = { id: id || '', tempId: btn.verify.printTempId, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM')}
+
+        try {
+          // eslint-disable-next-line
+          let func = new Function('btn', 'searches', 'param', 'systemType', btn.verify.pre_func)
+          _param = func(btn, searches, _param, window.GLOB.systemType)
+        } catch (e) {
+          console.warn(e)
+        }
+
+        if (!_param || _param.error) {
+          notification.warning({
+            top: 92,
+            message: _param ? _param.error : '鏈幏鍙栧埌鎵撳嵃鍙傛暟锛岃嚜瀹氫箟鑴氭湰閿欒锛�',
+            duration: 5
+          })
+          return
+        }
+        
+        window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify(_param))))
+      })
+    } else {
+      setTimeout(() => {
+        window.open('#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: id, tempId: btn.verify.printTempId, pageId: btn.$MenuID || '', dataM: sessionStorage.getItem('dataM') }))))
+      }, 200)
+    }
   }
 
   sendWxMessage = (verify, id) => {
@@ -3169,7 +3205,7 @@
   }
 
   modelconfirm = () => {
-    const { btn, BID } = this.props
+    const { BID } = this.props
     const { btnconfig, selines } = this.state
     let _this = this
 
@@ -3314,7 +3350,7 @@
       this.execSubmit(selines, () => {}, result)
     } else {
       confirm({
-        title: btn.tipTitle || '纭畾瑕佹墽琛屽悧?',
+        title: btnconfig.setting.tipTitle || '纭畾瑕佹墽琛屽悧?',
         onOk() {
           return new Promise(resolve => {
             _this.execSubmit(selines, resolve, result)
@@ -3494,7 +3530,7 @@
   }
 
   render() {
-    const { btn } = this.props
+    const { btn, name } = this.props
     const { loadingNumber, loadingTotal, loading, disabled, hidden, check, count } = this.state
 
     if (hidden) return null
@@ -3513,42 +3549,25 @@
     }
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{name || btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + (btn.class || 'unset')
+      label = !loading ? <MkIcon type={btn.icon} /> : null
+    } else if (btn.$toolbtn) {
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{loadingNumber && !loadingTotal ? `(${loadingNumber})` : ''}{btn.label}</span>
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + (btn.class || 'unset')
-    }
-
-    if (loadingNumber && btn.progress !== 'progressbar' && btn.$toolbtn && (!btn.show || btn.show === 'button')) {
-      label = (loadingNumber ? `(${loadingNumber})` : '') + btn.label
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{name || btn.label}</span>
     }
 
     let BTN = <Button
-      type={type}
-      icon={icon}
+      type="link"
       id={'button' + btn.uuid}
       title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
       loading={loading}
       disabled={disabled}
       style={btn.style}
-      className={className}
+      className={btn.$toolbtn ? (btn.hover || '') : ''}
       onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
     >{label}</Button>
 
diff --git a/src/tabviews/zshare/actionList/popupbutton/index.jsx b/src/tabviews/zshare/actionList/popupbutton/index.jsx
index 7c34a66..7c57f0a 100644
--- a/src/tabviews/zshare/actionList/popupbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -20,6 +20,7 @@
     btn: PropTypes.object,            // 鎸夐挳
     setting: PropTypes.any,           // 椤甸潰閫氱敤璁剧疆
     disabled: PropTypes.any,          // 琛屾寜閽鐢�
+    name: PropTypes.any
   }
 
   state = {
@@ -173,9 +174,9 @@
     let _data = null
     let primaryId = ''
 
-    if (btn.Ot === 'requiredSgl' && setting.primaryKey) {
+    if (btn.Ot === 'requiredSgl') {
       _data = data[0]
-      primaryId = _data.$$uuid || _data[setting.primaryKey] || ''
+      primaryId = _data.$$uuid || ''
     }
 
     this.setState({
@@ -303,46 +304,31 @@
   }
 
   render() {
-    const { btn } = this.props
+    const { btn, name } = this.props
     const { loading, disabled, hidden } = this.state
 
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{name || btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{name || btn.label}</span>
     }
 
     return (
       <>
         <Button
-          type={type}
+          type="link"
           id={'button' + btn.uuid}
           title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
-          loading={loading}
+          loading={loading && !name}
           disabled={disabled}
           style={btn.style}
-          icon={icon}
-          className={className}
+          className={btn.$toolbtn ? (btn.hover || '') : ''}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{label}</Button>
         <span onClick={(e) => {e.stopPropagation()}} onDoubleClick={(e) => {e.stopPropagation()}}>{this.getPop()}</span>
diff --git a/src/tabviews/zshare/actionList/printbutton/index.jsx b/src/tabviews/zshare/actionList/printbutton/index.jsx
index 6627f32..86a4840 100644
--- a/src/tabviews/zshare/actionList/printbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -915,6 +915,9 @@
               _param.username = sessionStorage.getItem('User_Name') || ''
               _param.fullname = sessionStorage.getItem('Full_Name') || ''
             }
+            if (btn.dataM === 'true') {
+              _param.dataM = sessionStorage.getItem('dataM') === 'true' ? 'Y' : ''
+            }
   
             return _param
           })
@@ -1007,7 +1010,11 @@
     }
 
     let isDataM = sessionStorage.getItem('dataM') === 'true'
+    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript + _tailScript)
     let regoptions = [
+      { reg: /@orderBy@/ig, value: btn.verify.setting.order },
+      { reg: /@pageSize@/ig, value: '9999' },
+      { reg: /@pageIndex@/ig, value: '1'},
       { reg: /@ID@/ig, value: `'${ID}'`},
       { reg: /@BID@/ig, value: `'${BID || ''}'`},
       { reg: /@LoginUID@/ig, value: `'${sessionStorage.getItem('LoginUID') || ''}'`},
@@ -1125,7 +1132,11 @@
     let LText = ''
 
     if (_dataresource) {
-      LText = `/*system_query*/select ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${btn.verify.setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows `
+      if (custompage) {
+        LText = `/*system_query*/select ${arrFields} from ${_dataresource} `
+      } else {
+        LText = `/*system_query*/select ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${btn.verify.setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows `
+      }
     }
 
     if (_customScript) {
@@ -2357,39 +2368,24 @@
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
 
     return <>
       <Button
-        type={type}
+        type="link"
         id={'button' + btn.uuid}
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         loading={loading}
         disabled={disabled}
         style={btn.style || null}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
       <span onClick={(e) => {e.stopPropagation()}}>{this.getModels()}</span>
diff --git a/src/tabviews/zshare/actionList/shareLink/index.jsx b/src/tabviews/zshare/actionList/shareLink/index.jsx
index e4bd407..d5ba3e8 100644
--- a/src/tabviews/zshare/actionList/shareLink/index.jsx
+++ b/src/tabviews/zshare/actionList/shareLink/index.jsx
@@ -152,38 +152,22 @@
     const { loading } = this.state
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
-    let style = {...btn.style}
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = !loading ? <MkIcon type={btn.icon} /> : null
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{!loading && btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{btn.label}</span>
     }
     
     return (
       <Button
-        type={type}
+        type="link"
         title={btn.show === 'icon' ? btn.label : ''}
-        style={style}
         loading={loading}
-        icon={icon}
-        className={className}
+        style={btn.style || null}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/tabbutton/index.jsx b/src/tabviews/zshare/actionList/tabbutton/index.jsx
index af1a136..461c1aa 100644
--- a/src/tabviews/zshare/actionList/tabbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -1,11 +1,12 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, notification } from 'antd'
+import { Button, notification, Dropdown } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
 import MkIcon from '@/components/mk-icon'
-// import './index.scss'
+
+import './index.scss'
 
 class TabButton extends Component {
   static propTpyes = {
@@ -15,6 +16,7 @@
     btn: PropTypes.object,            // 鎸夐挳
     selectedData: PropTypes.any,      // 瀛愯〃涓�夋嫨鏁版嵁
     disabled: PropTypes.any,          // 琛屾寜閽鐢�
+    name: PropTypes.any
   }
 
   state = {
@@ -102,7 +104,7 @@
     const { btn, selectedData, BID } = this.props
     const { disabled } = this.state
 
-    if (disabled) return
+    if (disabled || btn.multiMenus) return
     if (triggerId && btn.uuid !== triggerId) return
 
     if (type === 'linkbtn' && !btn.$toolbtn && !is(fromJS(selectedData || []), fromJS(record))) {
@@ -137,8 +139,22 @@
       let ids = data.map(d => (d.$$uuid || ''))
       ids = ids.filter(Boolean)
       primaryId = ids.join(',')
-    } else if (btn.Ot === 'notRequired' && BID) {
-      primaryId = BID
+    } else if (btn.Ot === 'notRequired') {
+      if (btn.sysId === 'js') {
+        primaryId = (() => {
+          let uuid = []
+          let timestamp = new Date().getTime()
+          let _options = '0123456789abcdefghigklmnopqrstuv'
+          for (let i = 0; i < 19; i++) {
+            uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
+          }
+          uuid = timestamp + uuid.join('')
+          return uuid
+        })()
+        primaryId = primaryId + (btn.sign || '')
+      } else {
+        primaryId = BID || ''
+      }
     }
 
     let newtab = {}
@@ -196,45 +212,132 @@
     }
   }
 
+  triggerMenu = (tab) => {
+    const { btn, selectedData, BID } = this.props
+
+    let data = selectedData || []
+
+    if (btn.Ot !== 'notRequired' && data.length === 0) {
+      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾暟鎹�
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨琛岋紒',
+        duration: 5
+      })
+      return false
+    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
+      // 闇�瑕侀�夋嫨鍗曡鏃讹紝鏍¢獙鏁版嵁
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨鍗曡鏁版嵁锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let primaryId = ''
+
+    if (btn.Ot === 'requiredSgl') {
+      primaryId = data[0].$$uuid || ''
+    } else if (btn.Ot === 'requiredOnce') {
+      let ids = data.map(d => (d.$$uuid || ''))
+      ids = ids.filter(Boolean)
+      primaryId = ids.join(',')
+    } else if (btn.Ot === 'notRequired') {
+      if (btn.sysId === 'js') {
+        primaryId = (() => {
+          let uuid = []
+          let timestamp = new Date().getTime()
+          let _options = '0123456789abcdefghigklmnopqrstuv'
+          for (let i = 0; i < 19; i++) {
+            uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
+          }
+          uuid = timestamp + uuid.join('')
+          return uuid
+        })()
+        primaryId = primaryId + (tab.sign || '')
+      } else {
+        primaryId = BID || ''
+      }
+    }
+
+    let menuId = tab.menuId.slice(-1)[0]
+    let menu = null
+
+    if (window.GLOB.mkThdMenus.has(menuId)) {
+      menu = {...window.GLOB.mkThdMenus.get(menuId), param: { $BID: primaryId }}
+    } else if (tab.MenuID) {
+      menu = {
+        MenuID: tab.MenuID,
+        MenuName: tab.MenuName,
+        type: tab.tabType,
+        param: { $BID: primaryId }
+      }
+    }
+
+    if (!menu) {
+      notification.warning({
+        top: 92,
+        message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�',
+        duration: 5
+      })
+      return
+    }
+
+
+    if (btn.openTab === 'view') {
+      window.open('#/view/' + menu.MenuID + '/' + primaryId)
+    } else {
+      MKEmitter.emit('modifyTabs', menu, true)
+  
+      MKEmitter.emit('openNewTab')
+    }
+
+    if (window.GLOB.systemType === 'production') {
+      MKEmitter.emit('queryTrigger', {menuId: btn.uuid, name: '鏍囩椤�'})
+    }
+  }
+
   render() {
-    const { btn } = this.props
+    const { btn, name } = this.props
     const { disabled, hidden } = this.state
 
     if (hidden) return null
 
     let label = ''
-    let icon = ''
-    let type = 'link'
-    let className = ''
 
-    if (btn.show === 'button') {
-      label = btn.label
-      icon = btn.icon || ''
-    } else if (btn.show === 'link') {
-      label = <span>{btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon}/> : ''}</span>
-      icon = ''
+    if (btn.show === 'link') {
+      label = <span>{name || btn.label}{btn.icon ? <MkIcon style={{marginLeft: '8px'}} type={btn.icon} /> : ''}</span>
     } else if (btn.show === 'icon') {
-      icon = btn.icon || ''
-    } else if (!btn.$toolbtn) {
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <MkIcon type={btn.icon} />
     } else {
-      type = ''
-      icon = btn.icon || ''
-      label = btn.label
-      className = 'mk-btn mk-' + btn.class
+      label = <span>{btn.icon ? <MkIcon style={{marginRight: '8px'}} type={btn.icon} /> : ''}{name || btn.label}</span>
+    }
+
+    if (btn.multiMenus && !disabled) {
+      return (<Dropdown
+        overlay={<div className="mk-tab-dropdown-wrap">{
+          btn.multiMenus.map(tab => <div key={tab.uuid} onClick={() => this.triggerMenu(tab)}>{tab.name}</div>)
+        }</div>}
+        trigger={['hover']}
+      >
+        <Button
+          type="link"
+          title={btn.show === 'icon' ? btn.label : ''}
+          style={btn.style || null}
+          className={btn.$toolbtn ? (btn.hover || '') : ''}
+        >{label}</Button>
+      </Dropdown>)
     }
 
     return (
       <Button
-        type={type}
+        type="link"
         id={'button' + btn.uuid}
         title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
         style={btn.style || null}
         disabled={disabled}
-        icon={icon}
-        className={className}
+        className={btn.$toolbtn ? (btn.hover || '') : ''}
         onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
       >{label}</Button>
     )
diff --git a/src/tabviews/zshare/actionList/tabbutton/index.scss b/src/tabviews/zshare/actionList/tabbutton/index.scss
index 8b13789..6401b82 100644
--- a/src/tabviews/zshare/actionList/tabbutton/index.scss
+++ b/src/tabviews/zshare/actionList/tabbutton/index.scss
@@ -1 +1,19 @@
+.mk-tab-dropdown-wrap {
+  box-shadow: 0 0 2px #bcbcbc;
+  background: #ffffff;
+  min-width: 85px;
+  border-radius: 2px;
 
+  div {
+    height: 32px;
+    line-height: 32px;
+    padding: 0 15px;
+    color: rgba(0, 0, 0, 0.65);
+    background: #ffffff;
+    cursor: pointer;
+  }
+  div:hover {
+    background-color: var(--mk-sys-color);
+    color: #ffffff;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/automatic/index.jsx b/src/tabviews/zshare/automatic/index.jsx
index 8d3f243..d165c28 100644
--- a/src/tabviews/zshare/automatic/index.jsx
+++ b/src/tabviews/zshare/automatic/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, message } from 'antd'
+import { Button, message, Tooltip } from 'antd'
 
 import MKEmitter from '@/utils/events.js'
 // import './index.scss'
@@ -224,7 +224,9 @@
 
     return (
       <div className="tool-wrap">
-        <Button icon={running ? 'pause' : 'forward'} shape="circle" onClick={this.trigger}/>
+        <Tooltip placement="left" title="鏃犱汉鍊煎畧">
+          <Button icon={running ? 'pause' : 'forward'} shape="circle" onClick={this.trigger}/>
+        </Tooltip>
       </div>
     )
   }
diff --git a/src/tabviews/zshare/flowFloat/index.jsx b/src/tabviews/zshare/flowFloat/index.jsx
index 5aab582..631b307 100644
--- a/src/tabviews/zshare/flowFloat/index.jsx
+++ b/src/tabviews/zshare/flowFloat/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, Modal, notification, Spin, Empty } from 'antd'
+import { Button, Modal, notification, Spin, Empty, Tooltip } from 'antd'
 import { BranchesOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -191,7 +191,9 @@
 
     return (
       <div className="tool-wrap">
-        <Button shape="circle" onClick={this.trigger}><BranchesOutlined /></Button>
+        <Tooltip placement="left" title="宸ヤ綔娴�">
+          <Button shape="circle" onClick={this.trigger}><BranchesOutlined /></Button>
+        </Tooltip>
         <Modal
           wrapClassName="flow-setting-modal"
           title="宸ヤ綔娴�"
diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx
index c987f75..521962d 100644
--- a/src/tabviews/zshare/mutilform/index.jsx
+++ b/src/tabviews/zshare/mutilform/index.jsx
@@ -148,6 +148,7 @@
       item.readin = item.readin !== 'false' && item.readin !== 'top'
       item.readonly = check || item.readonly === 'true'
       item.writein = item.writein !== 'false'
+      item.defHidden = item.hidden === 'true'
       item.hidden = item.hidden === 'true'
       item.fieldlength = item.fieldlength || 50
 
@@ -508,7 +509,7 @@
 
         let _hidden = false
 
-        if (supItem.hidden) {
+        if (supItem.hidden && !supItem.defHidden) {
           _hidden = true
         } else {
           let box = [...item.values]
@@ -1291,7 +1292,7 @@
         } else if (item.type === 'radio') {
           content = (<MKRadio config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)}/>)
         } else if (item.type === 'date' || item.type === 'datemonth') {
-          content = (<MKDatePicker config={item} onChange={(val) => this.recordChange({[item.field]: val})} />)
+          content = (<MKDatePicker config={item} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit}/>)
         } else if (item.type === 'fileupload') {
           className = item.readonly ? 'readonly' : ''
           className += item.fileType === 'picture-card' ? ' file-upload' : ''
diff --git a/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
index 0fe72ab..48ababe 100644
--- a/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
@@ -3,6 +3,8 @@
 import { DatePicker } from 'antd'
 import moment from 'moment'
 
+import MKEmitter from '@/utils/events.js'
+
 const { MonthPicker } = DatePicker
 
 /**
@@ -68,6 +70,17 @@
     }
 
     this.props.onChange(_val)
+
+    if (!config.enter || config.enter === 'false') return
+
+    setTimeout(() => {
+      if (config.enter === 'tab') {
+        MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+      } else if (config.enter === 'sub') {
+        config.tabUuid && MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+        this.props.onSubmit(config.tabUuid)
+      }
+    }, 50)
   }
 
   disabledDate = (current) => {
diff --git a/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx b/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
index 9e80af9..aa4d070 100644
--- a/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
@@ -78,8 +78,14 @@
   render() {
     const { config } = this.props
     const { value, precision } = this.state
-
-    if (precision === null) {
+    
+    if (config.format === 'thdSeparator') {
+      if (precision === null) {
+        return (<InputNumber id={config.uuid} formatter={value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/,*/g, '')} value={value} disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleSubmit}/>)
+      } else {
+        return (<InputNumber id={config.uuid} formatter={value => `${value}`.replace(/\B(?=(\d{3})+(?!\d))/g, ',')} parser={value => value.replace(/,*/g, '')} value={value} precision={precision} disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleSubmit} />)
+      }
+    } else if (precision === null) {
       return (<InputNumber id={config.uuid} value={value} disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleSubmit}/>)
     } else {
       return (<InputNumber id={config.uuid} value={value} precision={precision} disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleSubmit} />)
diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx
index 44d6ab9..f9187b3 100644
--- a/src/tabviews/zshare/normalTable/index.jsx
+++ b/src/tabviews/zshare/normalTable/index.jsx
@@ -344,11 +344,14 @@
     e.stopPropagation()
 
     let __param = {
-      $searchkey: item.field,
-      $searchval: record[item.field] || '',
       $BID: record.$$uuid
     }
 
+    if (item.field) {
+      __param.$searchkey = item.field.toLowerCase()
+      __param.$searchval = record[item.field] || ''
+    }
+
     if (item.linkfields && item.linkfields.length > 0) {
       item.linkfields.forEach(field => {
         __param[field] = record[field] || ''
diff --git a/src/tabviews/zshare/normalTable/index.scss b/src/tabviews/zshare/normalTable/index.scss
index 75c4770..c65a3ae 100644
--- a/src/tabviews/zshare/normalTable/index.scss
+++ b/src/tabviews/zshare/normalTable/index.scss
@@ -10,11 +10,8 @@
     position: absolute;
     bottom: 40px;
   }
-  >.ant-table-wrapper {
-    position: relative;
-    z-index: 1;
-  }
   .ant-table-wrapper {
+    position: relative;
     color: rgba(0, 0, 0, 0.65);
     font-size: 14px;
     .ant-table {
diff --git a/src/tabviews/zshare/settingcomponent/index.jsx b/src/tabviews/zshare/settingcomponent/index.jsx
index f2488e9..77e2230 100644
--- a/src/tabviews/zshare/settingcomponent/index.jsx
+++ b/src/tabviews/zshare/settingcomponent/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, Modal, notification, Spin, Empty } from 'antd'
+import { Button, Modal, notification, Spin, Empty, Tooltip } from 'antd'
 
 import Api from '@/api'
 import MKEmitter from '@/utils/events.js'
@@ -522,10 +522,12 @@
 
     return (
       <div className="tool-wrap">
-        <Button icon="setting" shape="circle" onClick={this.trigger}/>
+        <Tooltip placement="left" title="鑷畾涔夎缃�">
+          <Button icon="setting" shape="circle" onClick={this.trigger}/>
+        </Tooltip>
         <Modal
           wrapClassName="custom-setting-modal"
-          title={'鑷畾涔夎缃�'}
+          title="鑷畾涔夎缃�"
           maskClosable={false}
           width={950}
           visible={visible}
diff --git a/src/tabviews/zshare/tablenodes/index.jsx b/src/tabviews/zshare/tablenodes/index.jsx
index 49f6f32..4a258bc 100644
--- a/src/tabviews/zshare/tablenodes/index.jsx
+++ b/src/tabviews/zshare/tablenodes/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, Button, notification, Spin, Input, Typography, message } from 'antd'
+import { Modal, Button, notification, Spin, Input, Typography, message, Tooltip } from 'antd'
 
 import Api from '@/api'
 import G6 from "@antv/g6"
@@ -477,7 +477,9 @@
 
     return (
       <div className="tool-wrap">
-        <Button icon="fork" shape="circle" onClick={this.trigger}/>
+        <Tooltip placement="left" title="琛ㄥ叧绯诲浘">
+          <Button icon="fork" shape="circle" onClick={this.trigger}/>
+        </Tooltip>
         <Modal
           title=""
           wrapClassName="view-table-modal"
diff --git a/src/tabviews/zshare/topSearch/advanceform/index.scss b/src/tabviews/zshare/topSearch/advanceform/index.scss
index fa9af70..2312e65 100644
--- a/src/tabviews/zshare/topSearch/advanceform/index.scss
+++ b/src/tabviews/zshare/topSearch/advanceform/index.scss
@@ -7,6 +7,10 @@
     float: none;
     vertical-align: top;
   }
+  .ant-checkbox-wrapper {
+    color: rgba(0, 0, 0, 0.85);
+    white-space: nowrap;
+  }
   .ant-form-item {
     display: flex;
     margin-bottom: 0px;
@@ -32,6 +36,9 @@
   .ant-select-dropdown {
     z-index: 10 !important;
   }
+  .ant-radio-group {
+    white-space: nowrap;
+  }
   .ant-calendar-picker-container {
     z-index: 10 !important;
   }
diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx
index 4e6d329..8e82f35 100644
--- a/src/tabviews/zshare/topSearch/index.jsx
+++ b/src/tabviews/zshare/topSearch/index.jsx
@@ -42,7 +42,7 @@
   sign = ''
 
   UNSAFE_componentWillMount () {
-    const { config, BID } = this.props
+    const { config } = this.props
 
     let _searchlist = []
     let fieldMap = new Map()
@@ -54,6 +54,7 @@
     let record = {}
     let forbid = false // header涓笉璁剧疆楂樼骇鎼滅储
     let _setting = {showAdv: false, show: false, style: null}
+    let BID = this.props.BID
     
     if (config.wrap) {
       _setting.show = config.wrap.show !== 'false'
@@ -66,6 +67,15 @@
       _setting.wrapperCol = {style: {width: (100 - _setting.labelwidth) + '%'}}
       _setting.borderRadius = config.wrap.borderRadius
       _setting.resetContrl = config.wrap.resetContrl || 'init'
+
+      if (config.wrap.searchBtn === 'show') {
+        _setting.showBtn = true
+      }
+
+      if (config.wrap.supModule) {
+        let BData = window.GLOB.CacheData.get(config.wrap.supModule)
+        BID = BData ? (BData.$BID || '') : ''
+      }
     }
     
     if (config.type === 'search') {
@@ -278,19 +288,42 @@
       searchlist: _list
     }, () => {
       if (!window.GLOB.mkHS && window.GLOB.sysType === 'local' && window.GLOB.systemType !== 'production') {
-        this.improveSimpleSearch(deForms, false)
+        this.improveSimpleSearch(deForms, false, null, BID)
       } else if (mainItems.length > 0 || localItems.length > 0) {
-        this.improveSearch(mainItems, localItems)
+        this.improveSearch(mainItems, localItems, BID)
       }
     })
+  }
+
+  componentDidMount () {
+    const { config } = this.props
+
+    if (config.type === 'search' && config.wrap.supModule) {
+      MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    }
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
   }
 
   UNSAFE_componentWillReceiveProps(nextProps) {
     const { config, BID } = this.props
 
-    if (config.checkBid && nextProps.BID !== BID) {
+    if (config.checkBid && config.type !== 'search' && nextProps.BID !== BID) {
       this.resetOptions(nextProps.BID)
     }
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.props
+
+    if (config.wrap.supModule !== MenuID) return
+
+    this.resetOptions(id)
   }
 
   resetOptions = (BID) => {
@@ -346,7 +379,7 @@
     })
 
     if (deForms.length > 0) {
-      this.improveSimpleSearch(deForms, true, searchlist)
+      this.improveSimpleSearch(deForms, true, searchlist, BID)
     } else {
       this.setState({
         searchlist: searchlist
@@ -391,8 +424,7 @@
   }
 
   // 鏌ヨ涓嬫媺鑿滃崟
-  improveSearch = (mainItems, localItems) => {
-    const { BID } = this.props
+  improveSearch = (mainItems, localItems, BID) => {
     let deffers = []
 
     // 鏈湴璇锋眰
@@ -495,7 +527,7 @@
   }
 
   // 娴嬭瘯绯荤粺鍗曚釜璇锋眰涓嬫媺閫夐」
-  improveSimpleSearch = (deForms, trigger, searchlist) => {
+  improveSimpleSearch = (deForms, trigger, searchlist, BID) => {
     if (deForms.length === 0) return
 
     let deffers = deForms.map((item, index) => {
@@ -506,8 +538,8 @@
         arr_field: item.arr_field
       }
 
-      if (this.props.BID) {
-        param.BID = this.props.BID
+      if (BID) {
+        param.BID = BID
       }
 
       if (window.GLOB.execType === 'x') {
@@ -569,11 +601,11 @@
           }
 
           if (item.linkField) {
-            _item.ParentID = cell[item.linkField]
+            _item.ParentID = cell[item.linkField] + ''
           }
 
           if (item.type !== 'checkcard') {
-            _item.Value = cell[item.valueField]
+            _item.Value = cell[item.valueField] + ''
             _item.Text = cell[item.valueText] + ''
             
             if (map.has(_item.ParentID + _item.Value)) return
@@ -588,7 +620,7 @@
             
             map.set(_item.ParentID + _item.Value, 0)
           } else {
-            _item.$value = cell[item.cardValField]
+            _item.$value = cell[item.cardValField] + ''
             _item = {..._item, ...cell}
 
             if (item.urlField) {
@@ -761,6 +793,16 @@
           </Form.Item>
         </Col>
       )
+    } else if (setting.showBtn) {
+      fields.push(
+        <Col className="mk-search-col search-button" key="actions">
+          <Form.Item>
+            <Button type="primary" onClick={this.handleSubmit}>
+              鎼滅储
+            </Button>
+          </Form.Item>
+        </Col>
+      )
     }
     
     return fields
diff --git a/src/tabviews/zshare/topSearch/index.scss b/src/tabviews/zshare/topSearch/index.scss
index 9d96cca..bf4590a 100644
--- a/src/tabviews/zshare/topSearch/index.scss
+++ b/src/tabviews/zshare/topSearch/index.scss
@@ -5,9 +5,11 @@
     display: inline-block;
     float: none;
     vertical-align: top;
+    text-align: left;
   }
   .ant-checkbox-wrapper {
     color: rgba(0, 0, 0, 0.85);
+    white-space: nowrap;
   }
   .ant-form-item {
     display: flex;
@@ -34,6 +36,9 @@
   .ant-select-dropdown {
     z-index: 10 !important;
   }
+  .ant-radio-group {
+    white-space: nowrap;
+  }
   .ant-calendar-picker-container {
     z-index: 10 !important;
   }
@@ -50,7 +55,7 @@
   }
   .search-button {
     min-height: 55px;
-    .ant-btn-link, .ant-btn-link:hover, .ant-btn-link:active{
+    .ant-btn-link, .ant-btn-link:hover, .ant-btn-link:active {
       border-color: transparent;
       span {
         position: relative;
diff --git a/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
index fc67c7d..3ec9b43 100644
--- a/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
+++ b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
@@ -54,10 +54,21 @@
     const { config } = this.props
 
     if (config.checkShift && nextProps.config.initval && nextProps.config.initval !== config.initval) {
-      let val = nextProps.config.initval.split(',')
+      let value = nextProps.config.initval || null
+
+      if (this.state.mode === 'daterange') {
+        if (value) {
+          let val = value.split(',')
+          value = [moment(val[0], this.state.format), moment(val[1], this.state.format)]
+        } else {
+          value = [null, null]
+        }
+      } else if (value) {
+        value = moment(value, this.state.format)
+      }
 
       this.setState({
-        value: [moment(val[0], config.format), moment(val[1], config.format)]
+        value: value
       })
 
       this.props.onChange(nextProps.config.initval, true)
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index c8b2d92..3f2571f 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/src/templates/modalconfig/index.jsx
@@ -264,7 +264,7 @@
         })
       }
 
-      if (item.type === 'switch' || item.type === 'check') {
+      if (['switch', 'check', 'popSelect'].includes(item.type)) {
         _linksupFields.push({
           field: item.field,
           label: item.label
diff --git a/src/templates/modalconfig/settingform/index.jsx b/src/templates/modalconfig/settingform/index.jsx
index 4ac0090..7baf400 100644
--- a/src/templates/modalconfig/settingform/index.jsx
+++ b/src/templates/modalconfig/settingform/index.jsx
@@ -347,8 +347,13 @@
               )}
             </Form.Item>
           </Col> : null}
-          {display === 'drawer' && appType !== 'mob' ? <Col span={12}>
-            <Form.Item label="琛ㄥ崟绫诲瀷">
+          {appType !== 'mob' && (display === 'drawer' || display === 'modal') ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="閫夋嫨鏌ョ湅鏃惰〃鍗曞潎涓哄彧璇伙紝浠呯敤浜庢暟鎹睍绀恒��">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                琛ㄥ崟绫诲瀷
+              </Tooltip>
+            }>
               {getFieldDecorator('formType', {
                 initialValue: config.setting.formType || 'edit'
               })(
@@ -359,6 +364,20 @@
               )}
             </Form.Item>
           </Col> : null}
+          {display === 'prompt' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鎻愮ず妗嗙殑纭鎻愮ず淇℃伅銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                纭鎻愮ず
+              </Tooltip>
+            }>
+              {getFieldDecorator('tipTitle', {
+                initialValue: config.setting.tipTitle || ''
+              })(
+                <Input autoComplete="off" onPressEnter={this.handleSubmit} />
+              )}
+            </Form.Item>
+          </Col> : null}
           {!this.props.isSubTab && !appType && this.state.viewType !== 'popview' && display === 'modal' ? <Col span={12}>
             <Form.Item label="鎸傝浇瀵硅薄">
               {getFieldDecorator('container', {
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
index 3e9c1ae..e163b1c 100644
--- a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -13,7 +13,7 @@
 
 const { TextArea } = Input
 const actionTypeOptions = {
-  pop: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'tipTitle', 'hidden'],
+  pop: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'hidden'],
   prompt: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'tipTitle', 'hidden'],
   exec: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError', 'openmenu', 'output', 'hidden'],
   excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'sheet', 'execSuccess', 'execError', 'hidden'],
diff --git a/src/templates/sharecomponent/actioncomponent/formconfig.jsx b/src/templates/sharecomponent/actioncomponent/formconfig.jsx
index 0476049..6cdce8c 100644
--- a/src/templates/sharecomponent/actioncomponent/formconfig.jsx
+++ b/src/templates/sharecomponent/actioncomponent/formconfig.jsx
@@ -523,7 +523,7 @@
       key: 'tipTitle',
       label: '纭鎻愮ず',
       initVal: card.tipTitle || '',
-      tooltip: '娉細寮圭獥锛堣〃鍗曪級鍦ㄦ樉绀轰负鏄惁妗嗘椂鏈夋晥銆�',
+      tooltip: '鎻愮ず妗嗙殑纭鎻愮ず淇℃伅銆�',
       required: false
     },
     {
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
index 85b9d3f..570e6a0 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -283,7 +283,7 @@
           </Col> : null}
           {!type ? <Col span={10}>
             <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0, whiteSpace: 'nowrap'}}>
-              ErrorCode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
             </Form.Item>
           </Col> : null}
           {!type ? <Col span={24} className="sqlfield">
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
index 3bba3de..c58226f 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -716,39 +716,46 @@
         if (!err) {
           let _verify = {...verify, ...values}
 
-          if (_verify.excelHandle !== 'true') {
+          if (_verify.excelHandle !== 'true') { 
             delete _verify.excel_func
+          }
+          if (_verify.default === 'false' && _verify.scripts.length === 0) {
+            notification.warning({
+              top: 92,
+              message: '涓嶆墽琛岄粯璁ql鏃讹紝蹇呴』璁剧疆鑷畾涔夎剼鏈紒',
+              duration: 5
+            })
+            return
           }
 
           let cols = _verify.columns.map(col => col.Column.toLowerCase())
           cols = Array.from(new Set(cols))
+          let error = ''
 
           if (_verify.columns.length === 0) {
-            notification.warning({
-              top: 92,
-              message: '璇疯缃瓻xcel鍒楀瓧娈�!',
-              duration: 5
-            })
-            return
+            error = '璇疯缃瓻xcel鍒楀瓧娈�!'
           } else if (_verify.columns.length > cols.length) {
-            notification.warning({
-              top: 92,
-              message: 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!',
-              duration: 5
-            })
-            return
+            error = 'Excel鍒楀瓧娈靛悕锛屼笉鍙噸澶�!'
+          } else if (cols.includes('bid')) {
+            error = 'bid瀛楁涓轰繚鐣欏瓧锛屼笉鍙娇鐢�!'
+          } else if (cols.includes('jskey')) {
+            error = 'jskey瀛楁涓轰繚鐣欏瓧锛屼笉鍙娇鐢�!'
           } else if (_verify.range === 1) {
             let tEmptys = _verify.columns.filter(op => !op.Text)
             if (tEmptys.length > 0) {
-              notification.warning({
-                top: 92,
-                message: '蹇界暐棣栬鏃讹紝浼氫娇鐢═ext鍊兼牎楠孍xcel棣栬鍐呭锛孴ext鍊间笌Excel琛ㄩ琛屽唴瀹圭浉鍚岋紝涓斿潎涓嶅彲涓虹┖锛�',
-                duration: 5
-              })
-              return
+              error = '蹇界暐棣栬鏃讹紝浼氫娇鐢═ext鍊兼牎楠孍xcel棣栬鍐呭锛孴ext鍊间笌Excel琛ㄩ琛屽唴瀹圭浉鍚岋紝涓斿潎涓嶅彲涓虹┖锛�'
             }
           }
 
+          if (error) {
+            notification.warning({
+              top: 92,
+              message: error,
+              duration: 5
+            })
+            return
+          }
+
           _verify.columns.sort((a, b) => {
             if (a.import === 'init' && b.import !== 'init') {
               return 1
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
index 120f02d..b73e55b 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
@@ -83,10 +83,6 @@
   .custom-table .ant-empty {
     margin: 20px 8px!important;
   }
-  .excel-custom-table {
-    position: relative;
-    top: -25px;
-  }
   .errorval {
     display: inline-block;
     width: 30px;
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
index 444e507..b7645c9 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -9,6 +9,7 @@
 import Utils from '@/utils/utils.js'
 import { checkSQL, getSearchFields } from '@/utils/utils-custom.js'
 import CodeMirror from '@/templates/zshare/codemirror'
+import MKEmitter from '@/utils/events.js'
 // import './index.scss'
 
 class CustomForm extends Component {
@@ -134,6 +135,9 @@
               loading: false,
               editItem: null
             })
+            if (values.uuid) {
+              MKEmitter.emit('editLineId', values.uuid)
+            }
             this.props.form.setFieldsValue({
               sql: ' '
             })
@@ -206,14 +210,14 @@
           </Col>
           <Col span={10}>
             <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0, whiteSpace: 'nowrap'}}>
-              ErrorCode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
             </Form.Item>
           </Col>
           <Col span={24} className="sqlfield">
             <Form.Item label="鍙敤瀛楁">
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鍏叡鍊硷紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename</span></Tooltip>,&nbsp;
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>
-              {usefulfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鎼滅储鏉′欢锛岃鎸夌収@xxx@鏍煎紡浣跨敤銆�'}>,&nbsp;{usefulfields}</Tooltip> : null}
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鎺掑簭銆佸垎椤典互鍙婃悳绱㈡潯浠跺彉閲忥紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�'}>, orderBy, pageSize, pageIndex{usefulfields ? ', ' + usefulfields : ''}</Tooltip>
               {linefields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'琛ㄥ崟鍙婅鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��'}>,&nbsp;{linefields}</Tooltip> : null}
             </Form.Item>
           </Col>
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
index 1e04573..02f31bc 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
@@ -248,6 +248,18 @@
             </Col> : null}
             {btnType !== 'print' && excelHandle !== 'true' ? <Col span={8}>
               <Form.Item label={
+                <Tooltip placement="topLeft" title="瀵煎嚭excel鐨勬枃浠跺悕锛岄粯璁や负鑿滃崟鍚�+缁勪欢鍚嶃��">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  鏂囦欢鍚�
+                </Tooltip>
+              }>
+                {getFieldDecorator('excelName', {
+                  initialValue: setting.excelName || ''
+                })(<Input autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {btnType !== 'print' && excelHandle !== 'true' ? <Col span={8}>
+              <Form.Item label={
                 <Tooltip placement="topLeft" title="瀵煎嚭excel涓伐浣滆〃鍚嶇О锛岄粯璁や负Sheet1銆�">
                   <QuestionCircleOutlined className="mk-form-tip" />
                   宸ヤ綔琛�
@@ -255,7 +267,7 @@
               }>
                 {getFieldDecorator('sheet', {
                   initialValue: setting.sheet || ''
-                })(<Input placeholder="" autoComplete="off" />)}
+                })(<Input autoComplete="off" />)}
               </Form.Item>
             </Col> : null}
             {btnType !== 'print' && excelHandle !== 'true' ? <Col span={8}>
@@ -286,7 +298,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            {btnType !== 'print' && excelHandle !== 'true' ? <Col span={8}>
+            {/* {btnType !== 'print' && excelHandle !== 'true' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="Excel鍐呭鍖烘槸鍚﹁嚜鍔ㄦ崲琛屻��">
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -301,7 +313,7 @@
                   <Radio value="true">鏄�</Radio>
                 </Radio.Group>)}
               </Form.Item>
-            </Col> : null}
+            </Col> : null} */}
           </Row>
         </Form>
       </div>
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
index 21d53fe..7b23dda 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -9,6 +9,7 @@
 import Utils from '@/utils/utils.js'
 import SettingUtils from './utils.jsx'
 import ColumnForm from './columnform'
+import OtherForm from './otherform'
 import DataSource from './datasource'
 import CustomScript from './customscript'
 import asyncComponent from '@/utils/asyncComponent'
@@ -30,6 +31,8 @@
     verify: {},
     debugId: '',
     activeKey: 'setting',
+    visible: false,
+    line: null,
     searchKey: '',
     excelColumns: [
       {
@@ -68,7 +71,7 @@
         editable: true,
         required: false,
         keyCol: true,
-        width: '8%',
+        width: '10%',
         render: (text) => {
           if (text === 'image') {
             return '鍥剧墖'
@@ -115,50 +118,50 @@
           {value: 'false', text: '鍚�'}
         ]
       },
-      {
-        title: '鍙栫粷瀵瑰��',
-        dataIndex: 'abs',
-        inputType: 'radio',
-        editable: true,
-        required: false,
-        keyVals: ['number'],
-        width: '10%',
-        render: (text, record) => {
-          if (record.type !== 'number') return ''
+      // {
+      //   title: '鍙栫粷瀵瑰��',
+      //   dataIndex: 'abs',
+      //   inputType: 'radio',
+      //   editable: true,
+      //   required: false,
+      //   keyVals: ['number'],
+      //   width: '10%',
+      //   render: (text, record) => {
+      //     if (record.type !== 'number') return ''
 
-          if (text === 'true') {
-            return '鏄�'
-          } else {
-            return '鍚�'
-          }
-        },
-        options: [
-          {value: 'true', text: '鏄�'},
-          {value: 'false', text: '鍚�'}
-        ]
-      },
-      {
-        title: '0鍊煎鍑�',
-        dataIndex: 'noValue',
-        inputType: 'radio',
-        editable: true,
-        required: false,
-        keyVals: ['number'],
-        width: '10%',
-        render: (text, record) => {
-          if (record.type !== 'number') return ''
+      //     if (text === 'true') {
+      //       return '鏄�'
+      //     } else {
+      //       return '鍚�'
+      //     }
+      //   },
+      //   options: [
+      //     {value: 'true', text: '鏄�'},
+      //     {value: 'false', text: '鍚�'}
+      //   ]
+      // },
+      // {
+      //   title: '0鍊煎鍑�',
+      //   dataIndex: 'noValue',
+      //   inputType: 'radio',
+      //   editable: true,
+      //   required: false,
+      //   keyVals: ['number'],
+      //   width: '10%',
+      //   render: (text, record) => {
+      //     if (record.type !== 'number') return ''
 
-          if (text !== 'false') {
-            return '鏄�'
-          } else {
-            return '鍚�'
-          }
-        },
-        options: [
-          {value: 'true', text: '鏄�'},
-          {value: 'false', text: '鍚�'}
-        ]
-      },
+      //     if (text !== 'false') {
+      //       return '鏄�'
+      //     } else {
+      //       return '鍚�'
+      //     }
+      //   },
+      //   options: [
+      //     {value: 'true', text: '鏄�'},
+      //     {value: 'false', text: '鍚�'}
+      //   ]
+      // },
       {
         title: '灏忔暟浣�',
         dataIndex: 'decimal',
@@ -170,7 +173,68 @@
         keyVals: ['number'],
         width: '12%',
         render: (text, record) => record.type === 'number' ? text : ''
-      }
+      },
+      {
+        title: '鍏朵粬',
+        dataIndex: 'other',
+        required: false,
+        width: '18%',
+        render: (_, record) => {
+          if (record.type === 'number') {
+            let val = ''
+
+            if (record.abs === 'true') {
+              val += '鍙栫粷瀵瑰�硷紱'
+            }
+            if (record.noValue === 'false') {
+              val += '0鍊间笉瀵煎嚭锛�'
+            }
+            if (record.format) {
+              if (record.format === 'thdSeparator') {
+                val += '鏍煎紡鍖栵細鍗冨垎浣嶏紱'
+              } else if (record.format === 'thdSepPm') {
+                val += '鏍煎紡鍖栵細鍗冨垎浣嶏紙璐熷�肩孩鑹诧級锛�'
+              } else if (record.format === 'percent') {
+                val += '鏍煎紡鍖栵細鐧惧垎姣旓紱'
+              }
+            }
+            if (record.prefix) {
+              val += `鍓嶇紑锛�${record.prefix}锛沗
+            }
+            if (record.postfix) {
+              val += `鍚庣紑锛�${record.postfix}锛沗
+            }
+
+            return <div>{val}<EditOutlined className="edit-other" onClick={() => {this.setState({visible: true, line: fromJS(record).toJS()})}} /></div>
+          } else if (record.type === 'text') {
+            let val = ''
+
+            if (record.wrapText === 'true') {
+              val += '鑷姩鎹㈣锛�'
+            }
+            if (record.noValue === 'false') {
+              val += '绌哄�间笉瀵煎嚭锛�'
+            }
+            if (record.textFormat) {
+              if (record.textFormat === 'YYYY-MM-DD') {
+                val += '鏍煎紡鍖栵細YYYY-MM-DD锛�'
+              } else if (record.textFormat === 'YYYY-MM-DD HH:mm:ss') {
+                val += '鏍煎紡鍖栵細YYYY-MM-DD HH:mm:ss锛�'
+              }
+            }
+            if (record.prefix) {
+              val += `鍓嶇紑锛�${record.prefix}锛沗
+            }
+            if (record.postfix) {
+              val += `鍚庣紑锛�${record.postfix}锛沗
+            }
+
+            return <div>{val}<EditOutlined className="edit-other" onClick={() => {this.setState({visible: true, line: fromJS(record).toJS()})}} /></div>
+          }
+
+          return ''
+        }
+      },
     ],
     scriptsColumns: [
       {
@@ -227,12 +291,12 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div style={{textAlign: 'center'}}>
-            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
-            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
+            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record)} style={{color: '#1890ff'}}><EditOutlined /></span>
+            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><SwapOutlined /></span>
             <Popconfirm
               overlayClassName="popover-confirm"
               title="纭畾鍒犻櫎鍚�?"
-              onConfirm={() => this.handleDelete(record, 'scripts')
+              onConfirm={() => this.handleDelete(record)
             }>
               <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
             </Popconfirm>
@@ -392,14 +456,9 @@
     })
   }
 
-  handleEdit = (record, type) => {
-    let node = null
-
-    if (type === 'scripts') {
-      this.scriptsForm.edit(record)
-      node = document.getElementById('mk-exout-script')
-    }
-
+  handleEdit = (record) => {
+    this.scriptsForm.edit(record)
+    let node = document.getElementById('mk-exout-script')
 
     if (node && node.scrollTop) {
       let inter = Math.ceil(node.scrollTop / 10)
@@ -415,19 +474,17 @@
     }
   }
 
-  handleStatus = (record, type) => {
+  handleStatus = (record) => {
     let verify = JSON.parse(JSON.stringify(this.state.verify))
     record.status = record.status === 'false' ? 'true' : 'false'
 
-    if (type === 'scripts') {
-      verify.scripts = verify.scripts.map(item => {
-        if (item.uuid === record.uuid) {
-          return record
-        } else {
-          return item
-        }
-      })
-    }
+    verify.scripts = verify.scripts.map(item => {
+      if (item.uuid === record.uuid) {
+        return record
+      } else {
+        return item
+      }
+    })
 
     this.setState({
       verify: verify
@@ -459,38 +516,12 @@
     })
   }
 
-  handleDelete = (record, type) => {
-    const { verify } = this.state
+  handleDelete = (record) => {
+    let verify = JSON.parse(JSON.stringify(this.state.verify))
 
-    verify.columns = verify.columns.filter(item => item.uuid !== record.uuid)
+    verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
 
     this.setState({ verify: verify })
-  }
-
-  handleUpDown = (record, type, direction) => {
-    let verify = JSON.parse(JSON.stringify(this.state.verify))
-    let index = 0
-
-    verify.columns = verify.columns.filter((item, i) => {
-      if (item.uuid === record.uuid) {
-        index = i
-      }
-
-      return item.uuid !== record.uuid
-    })
-    if ((index === 0 && direction === 'up') || (index === verify.columns.length && direction === 'down')) {
-      return
-    }
-
-    if (direction === 'up') {
-      verify.columns.splice(index - 1, 0, record)
-    } else {
-      verify.columns.splice(index + 1, 0, record)
-    }
-
-    this.setState({
-      verify: verify
-    })
   }
 
   showError = (errorType) => {
@@ -626,7 +657,7 @@
                 loading: false
               })
               reject()
-            }, verify.scripts)
+            }, verify.scripts, 'submit')
           })
         })
       } else if (activeKey === 'columns') {
@@ -645,7 +676,7 @@
               loading: false
             })
             reject()
-          }, verify.scripts)
+          }, verify.scripts, 'submit')
         }
       } else if (activeKey === 'scripts') {
         this.setState({loading: true})
@@ -659,7 +690,7 @@
             loading: false
           })
           reject()
-        }, verify.scripts)
+        }, verify.scripts, 'submit')
       } else {
         resolve(verify)
       }
@@ -812,27 +843,30 @@
           col.type = 'text'
         }
       }
+      if (col.type === 'text' && col.format) {
+        delete col.format
+      } else if (col.type === 'number' && col.textFormat) {
+        delete col.textFormat
+      }
 
       return col
     })
-    // if (columns[0] && !['image', 'text', 'number'].includes(columns[0].type)) {
-    //   columns = columns.map(col => {
-    //     let _cell = {
-    //       uuid: Utils.getuuid(),
-    //       Column: col.Column,
-    //       Text: col.Text,
-    //       Width: 20,
-    //       abs: 'false',
-    //       output: col.output || 'true',
-    //       required: col.required || 'false',
-    //       type: 'text',
-    //     }
-
-    //     return _cell
-    //   })
-    // }
 
     this.setState({verify: {...verify, columns}})
+  }
+
+  lineSubmit = () => {
+    const { line, verify } = this.state
+
+    let columns = verify.columns.map(col => {
+      if (col.uuid === line.uuid) {
+        return line
+      }
+
+      return col
+    })
+
+    this.setState({verify: {...verify, columns}, line: null, visible: false})
   }
 
   // 鏍囩鍒囨崲
@@ -956,7 +990,7 @@
     }
   }
 
-  sqlverify = (_resolve, _reject, scripts) => {
+  sqlverify = (_resolve, _reject, scripts, type) => {
     const { searches, verify, debugId } = this.state
 
     if (verify.dataType !== 'custom') {
@@ -978,10 +1012,24 @@
         this.setState({debugId: _debugId})
         _resolve()
       } else {
-        _reject()
-        Modal.error({
-          title: result.message
-        })
+        if (type === 'submit') {
+          Modal.confirm({
+            title: result.message,
+            okText: '鐭ラ亾浜�',
+            cancelText: '寮哄埗淇濆瓨',
+            onOk: () => {
+              _reject()
+            },
+            onCancel() {
+              _resolve()
+            }
+          })
+        } else {
+          _reject()
+          Modal.error({
+            title: result.message
+          })
+        }
       }
     })
   }
@@ -1007,7 +1055,7 @@
 
   render() {
     const { card } = this.props
-    const { verify, excelColumns, scriptsColumns, activeKey, loading, searches, searchKey } = this.state
+    const { verify, excelColumns, scriptsColumns, activeKey, loading, searches, searchKey, visible, line } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -1040,7 +1088,7 @@
             <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}>
               娓呯┖Excel鍒�
             </Button>
-            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>濡傞渶瀵煎嚭搴忓彿锛岃浣跨敤瀛楁 $Index锛涙暟鍊肩被鍨嬪鍑烘椂鍙彇缁濆鍊间互鍙婅缃皬鏁颁綅锛涘鍑轰负鍚︽椂锛屼笉浣跨敤琛屼俊鎭紱绾㈣壊鏍囬瀵煎嚭鏃跺垪澶存枃瀛椾负绾㈣壊銆�</div>
+            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>濡傞渶瀵煎嚭搴忓彿锛岃浣跨敤瀛楁 $Index锛涘鍑轰负鍚︽椂锛屼笉浣跨敤琛屼俊鎭紙鏂囨湰涓虹┖锛屾暟鍊间负0锛夛紱绾㈣壊鏍囬瀵煎嚭鏃跺垪澶存枃瀛椾负绾㈣壊銆�</div>
             <EditTable actions={['edit', 'move', 'copy', 'del']} type="excelcolumn" searchKey={searchKey} wrappedComponentRef={(inst) => this.columnRef = inst} data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
           </TabPane>
           {card.intertype === 'system' ? <TabPane tab={
@@ -1159,6 +1207,18 @@
             </Form>
           </TabPane>
         </Tabs>
+        <Modal
+          title=""
+          visible={visible}
+          width={1000}
+          maskClosable={false}
+          closable={false}
+          onOk={this.lineSubmit}
+          onCancel={() => {this.setState({visible: false, line: null})}}
+          destroyOnClose
+        >
+          <OtherForm line={line} submit={this.lineSubmit} onChange={(values) => this.setState({line: values})}/>
+        </Modal>
       </div>
     )
   }
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
index f96c1d1..dd96816 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
@@ -96,6 +96,15 @@
     padding: 0 5px;
     cursor: pointer;
   }
+  .edit-other {
+    opacity: 0;
+    color: #1890ff;
+    padding: 0 5px;
+    transition: opacity 0.2s;
+  }
+  tr:not([draggable="false"]) td:hover .edit-other {
+    opacity: 1;
+  }
 }
 .verify-excelout-box-tab {
   >.ant-spin {
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.jsx
new file mode 100644
index 0000000..9d79e04
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.jsx
@@ -0,0 +1,132 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Radio, Tooltip, Select, Input } from 'antd'
+import { QuestionCircleOutlined } from '@ant-design/icons'
+// import './index.scss'
+
+class ExcelOutOtherColumn extends Component {
+  static propTpyes = {
+    onChange: PropTypes.func
+  }
+
+  onChange = (key, val) => {
+    const { line } = this.props
+
+    this.props.onChange({...line, [key]: val})
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { line } = this.props
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} style={{minHeight: '100px', paddingTop: '10px'}}>
+        <Row gutter={24}>
+          {line.type === 'number' ? <Col span={8}>
+            <Form.Item label="鍙栫粷瀵瑰��">
+              {getFieldDecorator('abs', {
+                initialValue: line.abs || 'false'
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.onChange('abs', e.target.value)}}>
+                  <Radio value="true">鏄�</Radio>
+                  <Radio value="false">鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {line.type === 'text' ? <Col span={8}>
+            <Form.Item label="鑷姩鎹㈣">
+              {getFieldDecorator('wrapText', {
+                initialValue: line.wrapText || 'false'
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.onChange('wrapText', e.target.value)}}>
+                  <Radio value="true">鏄�</Radio>
+                  <Radio value="false">鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          <Col span={8}>
+            <Form.Item label={line.type === 'number' ? '0鍊�' : 
+              <Tooltip placement="topLeft" title="鏃堕棿灏忎簬 1949-10-02 鏃躲��">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                绌哄��
+              </Tooltip>
+            }>
+              {getFieldDecorator('noValue', {
+                initialValue: line.noValue || 'true'
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => {this.onChange('noValue', e.target.value)}}>
+                  <Radio value="true">瀵煎嚭</Radio>
+                  <Radio value="false">涓嶅鍑�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {line.type === 'number' ? <Col span={8}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="浣跨敤鏍煎紡鍖栨椂锛岄渶璁剧疆灏忔暟浣嶃��">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鏍煎紡鍖�
+              </Tooltip>
+            }>
+              {getFieldDecorator('format', {
+                initialValue: line.format || ''
+              })(
+                <Select onChange={(val) => this.onChange('format', val)}>
+                  <Select.Option value=""> 鏃� </Select.Option>
+                  <Select.Option value="thdSeparator"> 鍗冨垎浣� </Select.Option>
+                  <Select.Option value="thdSepPm"> 鍗冨垎浣嶏紙璐熷�肩孩鑹诧級 </Select.Option>
+                  <Select.Option value="percent"> 鐧惧垎姣� </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {line.type === 'text' ? <Col span={8}>
+            <Form.Item label="鏍煎紡鍖�">
+              {getFieldDecorator('textFormat', {
+                initialValue: line.textFormat || ''
+              })(
+                <Select onChange={(val) => this.onChange('textFormat', val)}>
+                  <Select.Option value=""> 鏃� </Select.Option>
+                  <Select.Option value="YYYY-MM-DD"> YYYY-MM-DD </Select.Option>
+                  <Select.Option value="YYYY-MM-DD HH:mm:ss"> YYYY-MM-DD HH:mm:ss </Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+          <Col span={8}>
+            <Form.Item label="鍓嶇紑">
+              {getFieldDecorator('prefix', {
+                initialValue: line.prefix || ''
+              })(
+                <Input autoComplete="off" onChange={(e) => this.onChange('prefix', e.target.value)} onPressEnter={this.props.submit}/>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={8}>
+            <Form.Item label="鍚庣紑">
+              {getFieldDecorator('postfix', {
+                initialValue: line.postfix || ''
+              })(
+                <Input autoComplete="off" onChange={(e) => this.onChange('postfix', e.target.value)} onPressEnter={this.props.submit}/>
+              )}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ExcelOutOtherColumn)
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.scss b/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/otherform/index.scss
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
index 7df803d..f4e335c 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -15,9 +15,9 @@
 
     let arr_field = []
     verify.columns.forEach(item => {
-      if (item.Column !== '$Index') {
-        arr_field.push(item.Column)
-      }
+      if (item.output === 'false' || item.Column === '$Index') return
+      
+      arr_field.push(item.Column)
     })
     arr_field = arr_field.join(',')
 
diff --git a/src/templates/sharecomponent/actioncomponent/verifymegvii/index.scss b/src/templates/sharecomponent/actioncomponent/verifymegvii/index.scss
index c26f463..457bdae 100644
--- a/src/templates/sharecomponent/actioncomponent/verifymegvii/index.scss
+++ b/src/templates/sharecomponent/actioncomponent/verifymegvii/index.scss
@@ -9,11 +9,6 @@
     word-wrap: break-word;
     word-break: break-word;
   }
-
-  .excel-custom-table {
-    position: relative;
-    top: -25px;
-  }
   .errorval {
     display: inline-block;
     width: 30px;
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
index ccad7dd..bbad3ad 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -97,12 +97,12 @@
         dataIndex: 'operation',
         render: (text, record) =>
           (<div style={{textAlign: 'center'}}>
-            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
-            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
+            <span className="operation-btn" title="缂栬緫" onClick={() => this.handleEdit(record)} style={{color: '#1890ff'}}><EditOutlined /></span>
+            <span className="operation-btn" title="鐘舵�佸垏鎹�" onClick={() => this.handleStatus(record)} style={{color: '#8E44AD'}}><SwapOutlined /></span>
             <Popconfirm
               overlayClassName="popover-confirm"
               title="纭畾鍒犻櫎鍚�?"
-              onConfirm={() => this.handleDelete(record, 'scripts')
+              onConfirm={() => this.handleDelete(record)
             }>
               <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
             </Popconfirm>
@@ -333,14 +333,9 @@
     })
   }
 
-  handleEdit = (record, type) => {
-    let node = null
-
-    if (type === 'scripts') {
-      this.scriptsForm.edit(record)
-      node = document.getElementById('mk-exout-script')
-    }
-
+  handleEdit = (record) => {
+    this.scriptsForm.edit(record)
+    let node = document.getElementById('mk-exout-script')
 
     if (node && node.scrollTop) {
       let inter = Math.ceil(node.scrollTop / 10)
@@ -356,6 +351,33 @@
     }
   }
 
+  handleStatus = (record) => {
+    let verify = fromJS(this.state.verify).toJS()
+    record.status = record.status === 'false' ? 'true' : 'false'
+
+    verify.scripts = verify.scripts.map(item => {
+      if (item.uuid === record.uuid) {
+        return record
+      } else {
+        return item
+      }
+    })
+
+    this.setState({
+      verify: verify
+    })
+  }
+
+  handleDelete = (record) => {
+    let verify = fromJS(this.state.verify).toJS()
+
+    verify.scripts = verify.scripts.filter(item => item.uuid !== record.uuid)
+
+    this.setState({ verify: verify })
+
+    this.scriptsForm.check(record)
+  }
+
   showError = (errorType) => {
     if (errorType === 'S') {
       notification.success({
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
index 60a1241..c33d899 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
@@ -34,8 +34,19 @@
       _dataresource = '(' + _dataresource + ') tb'
     }
 
+    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
+
     // 姝e垯鏇挎崲
     let regoptions = [{
+      reg: new RegExp('@orderBy@', 'ig'),
+      value: setting.order || ''
+    }, {
+      reg: new RegExp('@pageSize@', 'ig'),
+      value: 10
+    }, {
+      reg: new RegExp('@pageIndex@', 'ig'),
+      value: 1
+    }, {
       reg: /@datam@/ig,
       value: `''`
     }, {
@@ -61,10 +72,10 @@
 
     // 鏁版嵁婧愬鐞�, 瀛樺湪鏄剧ず鍒楁椂 
     if (_dataresource) {
-      if (setting.order) {
-        _dataresource = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows`
-      } else {
+      if (custompage || !setting.order) {
         _dataresource = `/*system_query*/select ${arr_field} from ${_dataresource}`
+      } else {
+        _dataresource = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows`
       }
     }
 
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
index db83147..0f771e9 100644
--- a/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
@@ -120,11 +120,11 @@
     if (options.length === 0) {
       options = [{Value: '1', Text: '閫夐」1'}, {Value: '2', Text: '閫夐」2'}]
     }
-    formItem = (<Radio.Group value={card.initval} style={{lineHeight: '36px'}}>
+    formItem = (<Radio.Group value={card.initval} style={{lineHeight: '36px', whiteSpace: 'nowrap'}}>
       {options.map((item, i) => (<Radio key={i} value={item.Value}> {item.Text} </Radio>))}
     </Radio.Group>)
   } else if (card.type === 'check') {
-    formItem = <Checkbox style={{lineHeight: '36px'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
+    formItem = <Checkbox style={{lineHeight: '36px', whiteSpace: 'nowrap'}} checked={card.initval === card.openVal}>{card.checkTip || ''}</Checkbox>
   } else if (card.type === 'range') {
     type = 'range-wrap'
     let vals = card.initval.split(',')
diff --git a/src/templates/sharecomponent/searchcomponent/index.jsx b/src/templates/sharecomponent/searchcomponent/index.jsx
index 9d4b8f3..ab95ce6 100644
--- a/src/templates/sharecomponent/searchcomponent/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/index.jsx
@@ -93,6 +93,7 @@
    * @description 鎼滅储鏉′欢缂栬緫锛岃幏鍙栨悳绱㈡潯浠惰〃鍗曚俊鎭�
    */
   handleSearch = (card) => {
+    const { config } = this.props
     const { searchlist } = this.state
     let linkableFields = []
 
@@ -108,8 +109,8 @@
     })
 
     let columns = null
-    if (this.props.config.type === 'table') {
-      columns = this.props.config.columns.map(item => {
+    if (config.columns && config.columns.length) {
+      columns = config.columns.map(item => {
         return {key: item.uuid, text: item.field, value: item.field, label: item.label}
       })
     }
diff --git a/src/templates/zshare/customscript/index.jsx b/src/templates/zshare/customscript/index.jsx
index 50e6ad5..0286596 100644
--- a/src/templates/zshare/customscript/index.jsx
+++ b/src/templates/zshare/customscript/index.jsx
@@ -328,7 +328,7 @@
             </Col> : null}
             <Col span={16}>
               <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0}}>
-                ErrorCode, retmsg
+                errorcode, retmsg
               </Form.Item>
             </Col>
             <Col span={24} className="sqlfield">
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index c2a388a..d39db79 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -1869,6 +1869,21 @@
     },
     {
       type: 'radio',
+      key: 'format',
+      label: '鏍煎紡鍖�',
+      tooltip: '浣跨敤鍗冨垎浣嶆椂锛屾暟鍊煎皢浠ュ崈鍒嗕綅鏍煎紡鏄剧ず锛屾彁浜ゆ椂涓哄師鏁板�笺��',
+      initVal: card.format || '',
+      forbid: appType === 'mob',
+      options: [{
+        value: '',
+        text: '鏃�'
+      }, {
+        value: 'thdSeparator',
+        text: '鍗冨垎浣�'
+      }]
+    },
+    {
+      type: 'radio',
       key: 'colorType',
       label: '棰滆壊绫诲瀷',
       initVal: card.colorType || 'hex',
@@ -2571,7 +2586,7 @@
       key: 'enter',
       label: '鍥炶溅浜嬩欢',
       initVal: (card.type === 'text' || card.type === 'number') ? (card.enter || 'sub') : (card.enter || 'false'),
-      tooltip: '1銆佺偣鍑籈nter閿垨鏂囨湰绫昏〃鍗曡緭鍏ュ洖杞︾锛�2銆佷笅鎷夐�夋嫨鎴栧紑鍏崇殑閫夐」鍒囨崲銆�',
+      tooltip: '1銆佺偣鍑籈nter閿垨鏂囨湰绫昏〃鍗曡緭鍏ュ洖杞︾锛�2銆佷笅鎷夐�夋嫨銆佹椂闂淬�佸紑鍏崇殑閫夐」鍒囨崲銆�',
       options: [{
         value: 'sub',
         text: '鎻愪氦'
diff --git a/src/templates/zshare/modalform/index.jsx b/src/templates/zshare/modalform/index.jsx
index 6f21e10..0984c6e 100644
--- a/src/templates/zshare/modalform/index.jsx
+++ b/src/templates/zshare/modalform/index.jsx
@@ -21,7 +21,7 @@
 
 const modalTypeOptions = {
   text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'encryption', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline', 'placeholder', 'place', 'marginTop', 'marginBottom', 'lenControl', 'inputType', 'constant', 'mkfocus'],
-  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline', 'place', 'marginTop', 'marginBottom', 'mkfocus'],
+  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline', 'place', 'marginTop', 'marginBottom', 'mkfocus', 'format'],
   select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'pickerMode'],
   checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
   radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
@@ -31,8 +31,8 @@
   fileupload: ['readonly', 'required', 'hidden', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'linkSubField', 'tooltip', 'extra', 'compress', 'miniSet', 'splitline', 'marginTop', 'marginBottom', 'maxSize'],
   switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'linkSubField', 'tooltip', 'extra', 'enter', 'splitline', 'marginTop', 'marginBottom'],
   check: ['initval', 'openVal', 'closeVal', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'splitline', 'marginTop', 'marginBottom', 'checkTip'],
-  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'place', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
-  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'place', 'marginTop', 'marginBottom'],
+  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'declareType', 'mode', 'splitline', 'place', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
+  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'splitline', 'place', 'marginTop', 'marginBottom'],
   // datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'marginTop', 'marginBottom', 'minDate', 'maxDate'],
   textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra', 'place', 'count', 'placeholder', 'marginTop', 'marginBottom'],
   cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'marginTop', 'marginBottom', 'separator'],
@@ -243,6 +243,9 @@
         shows.push('unchecked')
       }
     } else if (['date', 'datemonth'].includes(type)) {
+      if (this.record.enter === 'tab' || this.record.enter === 'sub') {
+        shows.push('tabField')
+      }
       reOptions.initval = dateOptions[type]
       reTypes.initval = 'select'
       if (type === 'date') {
diff --git a/src/templates/zshare/pasteform/index.jsx b/src/templates/zshare/pasteform/index.jsx
index 3067ef0..73d666e 100644
--- a/src/templates/zshare/pasteform/index.jsx
+++ b/src/templates/zshare/pasteform/index.jsx
@@ -116,7 +116,7 @@
       <Form {...formItemLayout} className="config-paste-form">
         <Row gutter={24}>
           <Col span={24}>
-            <Form.Item label="閰嶇疆淇℃伅" className="textarea">
+            <Form.Item label="" className="textarea">
               {getFieldDecorator('config', {
                 initialValue: '',
                 rules: [
diff --git a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
index c0c0a6c..22d6853 100644
--- a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
+++ b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -222,7 +222,7 @@
           </Col> : null}
           {!type ? <Col span={10}>
             <Form.Item label="鎶ラ敊瀛楁" style={{margin: 0, whiteSpace: 'nowrap'}}>
-              ErrorCode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
             </Form.Item>
           </Col> : null}
           {!type ? <Col span={24} className="sqlfield">
diff --git a/src/templates/zshare/verifycard/customscript/index.jsx b/src/templates/zshare/verifycard/customscript/index.jsx
index 0a068a3..6150cb5 100644
--- a/src/templates/zshare/verifycard/customscript/index.jsx
+++ b/src/templates/zshare/verifycard/customscript/index.jsx
@@ -46,7 +46,7 @@
   }
 
   handleConfirm = () => {
-    const { type, workFlow, flowType, useDefaultSql, defaultsql } = this.props
+    const { type, workFlow, flowType, flowSql, useDefaultSql, defaultsql } = this.props
     const { editItem, skip } = this.state
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     this.props.form.validateFieldsAndScroll((err, values) => {
@@ -136,6 +136,49 @@
           `
         }
 
+        if (window.GLOB.process && workFlow === 'true' && flowSql === 'true') {
+          if (flowType === 'start') {
+            sql += `
+              /* 宸ヤ綔娴侀粯璁ql */
+              insert into s_my_works_flow (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,work_group,works_flow_detail_id,work_grade,bid,createuserid,CreateUser,CreateStaff,upid)
+              select @ID@,@works_flow_code@,@works_flow_name@,@works_flow_param@,@status@,@statusname@,@work_group@,@works_flow_detail_id@,@work_grade@,@bid@,@UserID@,@UserName,@FullName,@time_id@
+              insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
+              select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+              insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+              select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
+            `
+          } else {
+            sql += `
+              /* 宸ヤ綔娴侀粯璁ql */
+              update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+              where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+              insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
+              select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+              
+              update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+              where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+
+              if @check_userids@ != ''
+              begin
+                    insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
+                    select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+                    insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                    select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@check_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+              end
+              if @notice_userids@ != ''
+              begin
+                    update n
+                    set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+                    from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
+                    inner join (select ID from dbo.SplitComma(@notice_userids@)) s
+                    on n.userid = s.id
+                    insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                    select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@notice_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@notice_userids@)
+              end
+            `
+          }
+        }
+
         sql += _backCustomScript + tail
 
         if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
@@ -166,6 +209,9 @@
           if (flowType !== 'start') {
             sql = sql.replace(/@check_userids@/ig, `'checkuserids'`)
             sql = sql.replace(/@notice_userids@/ig, `'noticeuserids'`)
+          } else {
+            sql = sql.replace(/@check_userids@/ig, `''`)
+            sql = sql.replace(/@notice_userids@/ig, `''`)
           }
         }
         
@@ -239,13 +285,16 @@
         insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
         select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@`
       } else {
-        value = `update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+        value = `update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
         where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
         insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
         select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+        
+        update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+        where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+  
         if @check_userids@ != ''
         begin
-              delete s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
               insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
               select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
               insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
@@ -253,7 +302,8 @@
         end
         if @notice_userids@ != ''
         begin
-              delete n
+              update n
+              set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
               from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
               inner join (select ID from dbo.SplitComma(@notice_userids@)) s
               on n.userid = s.id
@@ -303,17 +353,17 @@
           </Col> : null}
           {!_type ? <Col span={10}>
             <Form.Item label={'鎶ラ敊瀛楁'} style={{margin: 0, whiteSpace: 'nowrap'}}>
-              ErrorCode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
+              errorcode锛堝鍔犲悗缂�NT琛ㄧず鏁版嵁涓嶅洖婊氾紝濡侲NT銆丯NT銆丗NT銆丯MNT銆丆NT銆�-2NT锛�, retmsg
             </Form.Item>
           </Col> : null}
           {!_type ? <Col span={24} className="sqlfield">
             <Form.Item label={'鍙敤瀛楁'}>
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="鍏叡鍊硷紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�"><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
+              {window.GLOB.process && workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="宸ヤ綔娴佸彉閲忥紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�"><span style={{color: '#26C281'}}>works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, check_type, notice_type, check_userids, notice_userids, </span></Tooltip> : null}
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��"><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted</span></Tooltip>,&nbsp;
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞跺湪鍗曞彿鐢熸垚鎴栧垱寤哄嚟璇佹椂浣跨敤銆�"><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
               {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="琛ㄥ崟鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
               {colfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="瀛楁闆嗗彉閲忥紝绯荤粺浼氬畾涔夊彉閲忓苟璧嬪�笺��">, {colfields}</Tooltip> : ''}
-              {window.GLOB.process && workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="宸ヤ綔娴佸彉閲忥紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆傛敞锛歝heck_userids銆乶otice_userids 鍦ㄥ鎵规垨椹冲洖鏃舵湁鏁堛��">,<span style={{color: 'purple'}}> works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, check_type, notice_type, check_userids, notice_userids</span></Tooltip> : null}
             </Form.Item>
           </Col> : null}
           {!_type ? <Col span={8} style={{whiteSpace: 'nowrap'}}>
@@ -367,7 +417,7 @@
           </Col>
           <Col span={24} className="sql">
             <Form.Item label={
-              <Tooltip placement="topLeft" overlayStyle={{width: '320px', maxWidth: '320px'}} title={<><div>{'璋冭瘯鏇挎崲绗� /*$breakpoint_begin_xxxx@ 銆丂breakpoint_end_xxxx$*/锛屽湪鎺у埗鍙颁腑杈撳叆 window.debug = \'xxxx\' 浼氬惎鐢ㄥ搴旂殑璋冭瘯璇彞锛屽揩鎹烽敭 ctrl+c 鎴栧湪鎺у埗鍙颁腑杈撳叆 window.debug = false 鍏抽棴璋冭瘯銆傛敞锛氳皟璇曟椂瀛楃 $breakpoint_proc@ 灏嗚鏇挎崲銆�'}</div><div style={{height: '5px'}}></div><div>{'鏁版嵁妫�鏌ユ浛鎹㈢ $check@ -> \'\'銆� @check$ -> \'\'锛孍rrorCode绛変簬C鏃朵細璇㈤棶鏄惁缁х画鎵ц锛岀‘瀹氭椂 $check@ -> /*銆� @check$ -> */銆傛敞锛�1銆侀渶浣跨敤绯荤粺鎺ュ彛 2銆佽璁剧疆涓衡�滈�夋嫨澶氳鈥濇椂鏃犳晥銆�'}</div></>}>
+              <Tooltip placement="topLeft" overlayStyle={{width: '520px', maxWidth: '520px'}} title={<><div>{`璋冭瘯鏇挎崲绗� /*$breakpoint_begin_xxxx@ 銆丂breakpoint_end_xxxx$*/锛屽湪鎺у埗鍙颁腑杈撳叆 window.debug = 'xxxx' 浼氬惎鐢ㄥ搴旂殑璋冭瘯璇彞锛屽揩鎹烽敭 ctrl+c 鎴栧湪鎺у埗鍙颁腑杈撳叆 window.debug = false 鍏抽棴璋冭瘯銆傛敞锛氳皟璇曟椂瀛楃 $breakpoint_proc@ 灏嗚鏇挎崲銆俙}</div><div style={{height: '5px'}}></div><div>{`鏁版嵁妫�鏌ユ浛鎹㈢ $check@ -> ''銆� @check$ -> ''锛孍rrorCode绛変簬C鏃朵細璇㈤棶鏄惁缁х画鎵ц锛岀‘瀹氭椂 $check@ -> /*銆� @check$ -> */銆傛敞锛�1銆侀渶浣跨敤绯荤粺鎺ュ彛 2銆佽璁剧疆涓衡�滈�夋嫨澶氳鈥濇椂鏃犳晥銆俙}</div><div style={{height: '5px'}}></div><div>{`鏁版嵁鏉冮檺鏇挎崲绗� $@ -> /* 鎴� ''銆� @$ -> */ 鎴� ''`}</div></>}>
                 <QuestionCircleOutlined className="mk-form-tip" />
                 sql
               </Tooltip>
diff --git a/src/templates/zshare/verifycard/index.jsx b/src/templates/zshare/verifycard/index.jsx
index 4617c6c..c1951b2 100644
--- a/src/templates/zshare/verifycard/index.jsx
+++ b/src/templates/zshare/verifycard/index.jsx
@@ -1777,6 +1777,9 @@
                 type="fullscreen"
                 btn={this.props.card}
                 initsql={this.state.initsql}
+                workFlow={verify.workFlow}
+                flowType={verify.flowType}
+                flowSql={verify.flowSql}
                 customScripts={verify.scripts}
                 useDefaultSql={verify.default !== 'false'}
                 defaultsql={this.state.defaultsql}
@@ -1792,6 +1795,7 @@
               initsql={this.state.initsql}
               workFlow={verify.workFlow}
               flowType={verify.flowType}
+              flowSql={verify.flowSql}
               customScripts={verify.scripts}
               useDefaultSql={verify.default !== 'false'}
               defaultsql={this.state.defaultsql}
diff --git a/src/utils/utils-custom.js b/src/utils/utils-custom.js
index 9390ede..841817d 100644
--- a/src/utils/utils-custom.js
+++ b/src/utils/utils-custom.js
@@ -193,6 +193,42 @@
   }
 
   /**
+   * @description 鑾峰彇鎸囧畾缁勪欢
+   * @return {String}  缁勪欢id
+   */
+  static getComponent (Id) {
+    let interfaces = window.GLOB.customMenu.interfaces
+    let components = window.GLOB.customMenu.components
+    let cell = null
+
+    let mapComponents = (components = []) => {
+      components.forEach(item => {
+        if (item.uuid === Id) {
+          cell = item
+        }else if (item.type === 'tabs') {
+          item.subtabs.forEach(f_tab => {
+            mapComponents(f_tab.components)
+          })
+        } else if (item.type === 'group') {
+          mapComponents(item.components)
+        }
+      })
+    }
+
+    mapComponents(components)
+
+    if (!cell && interfaces) {
+      interfaces.forEach(m => {
+        if (m.uuid === Id && m.status === 'true') {
+          cell = m
+        }
+      })
+    }
+    
+    return cell
+  }
+
+  /**
    * @description 鑾峰彇涓婄骇妯″潡
    * @return {String}  selfId  褰撳墠缁勪欢id
    */
@@ -540,7 +576,16 @@
             return cell
           })
         }
-      } else if (item.type === 'table' && item.cols) {
+      } else if (item.type === 'table') {
+        if (item.supNodes && item.supNodes.length > 0) {
+          item.supNodes = item.supNodes.map(cell => {
+            cell.nodes = cell.nodes.map(n => md5(commonId + n))
+            cell.componentId = cell.nodes[cell.nodes.length - 1]
+
+            return cell
+          })
+        }
+
         let loopCol = (cols) => {
           return cols.map(col => {
             if (col.type === 'action') {
@@ -578,7 +623,7 @@
           })
         }
 
-        item.cols = loopCol(item.cols)
+        item.cols = loopCol(item.cols || [])
 
         if (item.colsCtrls) {
           item.colsCtrls = item.colsCtrls.map(col => {
@@ -846,7 +891,7 @@
           return cell
         })
       }
-    } else if (item.type === 'table' && item.cols) {
+    } else if (item.type === 'table') {
       let loopCol = (cols) => {
         return cols.map(col => {
           if (col.type === 'action') {
@@ -887,7 +932,7 @@
         })
       }
 
-      item.cols = loopCol(item.cols)
+      item.cols = loopCol(item.cols || [])
 
       if (item.colsCtrls) {
         item.colsCtrls = item.colsCtrls.map(col => {
@@ -1009,7 +1054,7 @@
       } else if (item.type === 'daterange') {
         value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
       } else if (item.type === 'range') {
-        value = item.initval || `${item.minValue || '-999999'},${item.maxValue || '999999'}`
+        value = item.initval || `${item.minValue || '-999999999'},${item.maxValue || '999999999'}`
       } else if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) {
         type = 'multi'
       }
@@ -1058,7 +1103,7 @@
       searchText.push('(' + item.key + ' >= \'' + val[0] + '\' AND ' + item.key + ' < \'' + val[1] + '\')')
     } else if (item.type === 'range') {
       let val = item.value.split(',')
-      searchText.push('(' + item.key + ' >= ' + (val[0] || -999999) + ' AND ' + item.key + ' < ' + (val[1] || 999999) + ')')
+      searchText.push('(' + item.key + ' >= ' + (val[0] || -999999999) + ' AND ' + item.key + ' <= ' + (val[1] || 999999999) + ')')
     } else if (item.type === 'datemonth') {
       if (item.match === '=') {
         searchText.push('(' + item.key + ' = \'' + item.value + '\')')
@@ -1122,10 +1167,10 @@
       let val = item.value.split(',')
       options.push({
         reg: new RegExp('@' + item.key + '@', 'ig'),
-        value: `${val[0] || -999999}`
+        value: `${val[0] || -999999999}`
       }, {
         reg: new RegExp('@' + item.key + '1@', 'ig'),
-        value: `${val[1] || 999999}`
+        value: `${val[1] || 999999999}`
       })
     } else if (item.type === 'datemonth') {
       if (item.match === '=') {
@@ -1675,7 +1720,7 @@
       } else if (!card.setting.supModule) {
         errors.push({ level: 0, detail: '鏈缃笂绾х粍浠讹紒'})
       }
-    } else if (card.type === 'card' && card.subtype === 'datacard') { // 鏁版嵁鍗★紝鍙兘鏈夊涓婄骇
+    } else if ((card.type === 'card' && card.subtype === 'datacard') || card.subtype === 'normaltable') { // 鏁版嵁鍗°�乼able锛屽彲鑳芥湁澶氫笂绾�
       if (card.wrap.supType !== 'multi' && !card.setting.supModule) {
         errors.push({ level: 0, detail: '鏈缃笂绾х粍浠讹紒'})
       }
diff --git a/src/utils/utils-datamanage.js b/src/utils/utils-datamanage.js
index 91dfd4a..1291a36 100644
--- a/src/utils/utils-datamanage.js
+++ b/src/utils/utils-datamanage.js
@@ -1,16 +1,13 @@
 import md5 from 'md5'
 import moment from 'moment'
+import { notification, Modal } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
 import Utils from './utils.js'
 
 export default class DataUtils {
   /**
-   * @description 鏁版嵁婧愬悕绉帮紝鐢ㄤ簬缁熶竴鏌ヨ
-   * @param {Object}   setting      鏁版嵁婧愯缃�
-   * @param {Array}    search       鎼滅储鏉′欢
-   * @param {String}   orderBy      鎺掑簭鏂瑰紡
-   * @param {Number}   pageIndex    椤电爜
-   * @param {Number}   pageSize     姣忛〉鏁伴噺
-   * @param {String}   BID          涓婄骇ID
+   * @description 鏁版嵁婧愮粺涓�鏌ヨ
    */
   static getQueryDataParams (setting, search = [], orderBy = '', pageIndex = 1, pageSize = 10, BID, id, year) {
     let param = null
@@ -442,6 +439,46 @@
 
     return param
   }
+
+  /**
+   * @description 鏁版嵁鑾峰彇鎴愬姛
+   */
+  static querySuccess (result) {
+    if (!result.message) return
+
+    if (result.ErrCode === 'Y') {
+      Modal.success({
+        title: result.message
+      })
+    } else if (result.ErrCode === 'S') {
+      notification.success({
+        top: 92,
+        message: result.message,
+        duration: 2
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁鑾峰彇澶辫触
+   */
+  static queryFail (result) {
+    if (!result.message && result.ErrCode !== 'version_up') return
+    
+    if (result.ErrCode === 'N') {
+      Modal.error({
+        title: result.message,
+      })
+    } else if (result.ErrCode === 'version_up') {
+      MKEmitter.emit('reloadTabs')
+    } else if (result.ErrCode !== '-2') {
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
 }
 
 /**
diff --git a/src/utils/utils.js b/src/utils/utils.js
index a904374..cf6abd4 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -204,6 +204,13 @@
       values = window.GLOB.SearchBox.get(config.$searchId + 'cache')
     }
 
+    let supModule = ''
+    if (config.setting && config.setting.supModule) {
+      supModule = config.setting.supModule
+    } else if (config.wrap && config.wrap.supModule) {
+      supModule = config.wrap.supModule
+    }
+
     config.search = config.search.map(item => {
       item.hidden = item.Hide === 'true'
       item.required = !item.hidden && item.required === 'true'
@@ -234,12 +241,14 @@
           } else {
             item.$initval = item.initval
             item.$supId = config.$pageId
-            if (config.setting && config.setting.supModule) {
-              item.$supId = config.setting.supModule
+            if (supModule) {
+              item.$supId = supModule
 
               config.checkBid = true
-              config.setting.checkBid = true
               item.checkShift = true
+              if (config.setting) {
+                config.setting.checkBid = true
+              }
             }
 
             item.initval = ''
@@ -296,12 +305,14 @@
           } else {
             item.$initval = item.initval
             item.$supId = config.$pageId
-            if (config.setting && config.setting.supModule) {
-              item.$supId = config.setting.supModule
+            if (supModule) {
+              item.$supId = supModule
 
               config.checkBid = true
-              config.setting.checkBid = true
               item.checkShift = true
+              if (config.setting) {
+                config.setting.checkBid = true
+              }
             }
 
             item.initval = ''
@@ -393,10 +404,12 @@
           item.initType = ''
         }
       } else if ((item.type === 'select' || item.type === 'link') && item.resourceType === '1') {
-        if (/@BID@/ig.test(item.dataSource) && config.setting && config.setting.supModule) {
+        if (/@BID@/ig.test(item.dataSource) && supModule) {
           config.checkBid = true
-          config.setting.checkBid = true
           item.checkBid = true
+          if (config.setting) {
+            config.setting.checkBid = true
+          }
         }
         if (item.initval === '$first') {
           item.initval = ''
@@ -541,8 +554,8 @@
       } else if (item.type === 'range') {
         let val = item.value.split(',')
 
-        newsearches[item.key] = val[0] || -999999
-        newsearches[item.key + '1'] = val[1] || 999999
+        newsearches[item.key] = val[0] || -999999999
+        newsearches[item.key + '1'] = val[1] || 999999999
       } else if (item.type === 'dateweek') {
         let _startval = ''
         let _endval = ''
@@ -690,7 +703,7 @@
       } else if (item.type === 'range') {
         let val = item.value.split(',')
 
-        searchText.push('(' + item.key + ' >= ' + (val[0] || -999999) + ' AND ' + item.key + ' < ' + (val[1] || 999999) + ')')
+        searchText.push('(' + item.key + ' >= ' + (val[0] || -999999999) + ' AND ' + item.key + ' <= ' + (val[1] || 999999999) + ')')
       } else {
         searchText.push('(' + item.key + ' ' + item.match + ' \'' + item.value + '\')')
       }
@@ -766,9 +779,9 @@
 
         let copy = JSON.parse(JSON.stringify(item))
         copy.key = copy.key + '1'
-        copy.value = val[1] || 999999
+        copy.value = val[1] || 999999999
         
-        item.value = val[0] || -999999
+        item.value = val[0] || -999999999
 
         options.push(item)
         options.push(copy)
@@ -1132,6 +1145,13 @@
 
     let _uniquesql = ''
     if (btn.uniques && btn.uniques.length > 0) {
+      let textFields = []
+      btn.columns.forEach((col) => {
+        if (/^Nvarchar/ig.test(col.type)) {
+          textFields.push(col.Column)
+        }
+      })
+
       btn.uniques.forEach(unique => {
         if (unique.status === 'false' || !unique.verifyType) return
 
@@ -1140,6 +1160,14 @@
         let _afields = _fields.map(_field => `a.${_field}`)
         _fields_ = _fields_.join(' and ')
 
+        let _where = []
+        _fields.forEach(f => {
+          if (textFields.includes(f)) {
+            _where.push(`${f}!=''`)
+          }
+        })
+        _where = _where.length ? `where ${_where.join(' and ')} ` : ''
+
         if (unique.verifyType === 'logic' || unique.verifyType === 'logic_temp') {
           _fields_ += ' and b.deleted=0'
         }
@@ -1147,7 +1175,7 @@
         _uniquesql += `
       /* 閲嶅鎬ч獙璇� */
       Set @tbid=''
-      Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from #${sheet} ) a group by ${unique.field} having sum(n)>1
+      Select top 1 @tbid=${_fields.join('+\' \'+')} from (select 1 as n,${unique.field} from #${sheet} ${_where}) a group by ${unique.field} having sum(n)>1
       
       If @tbid!=''
       Begin
@@ -1156,7 +1184,7 @@
       end
       
       ${unique.verifyType.indexOf('temp') === -1 ? `Set @tbid=''
-      Select top 1 @tbid=${_afields.join('+\' \'+')} from  #${sheet} a Inner join ${database}${sheet} b on ${_fields_}
+      Select top 1 @tbid=${_afields.join('+\' \'+')} from ${_where ? `(select * from #${sheet} ${_where})` : `#${sheet}`} a Inner join ${database}${sheet} b on ${_fields_}
       
       If @tbid!=''
       Begin
@@ -2122,6 +2150,7 @@
     let statusName = ''
     let detailId = ''
     let error = ''
+    let userid = sessionStorage.getItem('UserID') || ''
 
     if (verify.flowType === 'start') {
       target = flow.cells.filter(cell => cell.mknode === 'start')[0]
@@ -2250,7 +2279,15 @@
       error = '琛屼俊鎭腑鏃犲伐浣滄祦鍙傛暟'
     }
 
-    if (verify.flowSql === 'true' && target) {
+    if (error) {
+      status = 0
+      statusName = '寮傚父'
+
+      _sql += `
+      /* 宸ヤ綔娴佸紓甯竤ql */
+      select @ErrorCode='E',@retmsg='${error}' goto aaa
+      `
+    } else if (verify.flowSql === 'true' && target) {
       if (verify.flowType === 'start') {
         _sql += `
       /* 宸ヤ綔娴侀粯璁ql */
@@ -2261,16 +2298,124 @@
       insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
       select @ID@,@works_flow_code@,@works_flow_detail_id@,@userid@,@start_type@,@userid@,@UserName,@FullName,@time_id@
       `
+      } else if (line && line.approvalMethod === 'countersign' && (!node.checkIds || !node.checkIds.includes(userid))) {
+        status = 0
+        statusName = '寮傚父'
+
+        _sql += `
+        /* 宸ヤ綔娴佸紓甯竤ql */
+        select @ErrorCode='E',@retmsg='褰撳墠鐢ㄦ埛涓嶅湪瀹℃壒浜哄垪琛ㄤ腑' goto aaa
+        `
+      } else if (line && line.approvalMethod === 'countersign' && node.checkIds.length > 1) {
+        let label = ''
+        let field = ''
+        let mark = line.mark || '宸插鏍�'
+        let _declare = []
+        let _select = []
+        let _select2 = []
+        let _where = []
+        let fields = ['statuscharone', 'statuschartwo', 'statuscharthree', 'statuscharfour', 'statuscharfive']
+        node.checkUsers.forEach((user, index) => {
+          if (user.worker_id === userid) {
+            field = fields[index]
+            label = `'${user.parentNames[2] || ''}${user.workername || ''}${mark}'`
+          } else {
+            _declare.push(`@works_flow_${fields[index]} nvarchar(50)`)
+            _select.push(`@works_flow_${fields[index]}=''`)
+            _select2.push(`@works_flow_${fields[index]}=${fields[index]}`)
+            _where.push(`@works_flow_${fields[index]}!=''`)
+          }
+        })
+        _declare = _declare.join(',')
+        _select = _select.join(',')
+        _select2 = _select2.join(',')
+        _where = _where.join(' and ')
+
+        _sql += `
+      /* 宸ヤ綔娴侀粯璁ql */
+      declare ${_declare},@works_flow_key_id nvarchar(50),@works_flow_key_status nvarchar(20),@s_my_works_flow_log_param  nvarchar(max),@s_my_works_flow_log_status int,@s_my_works_flow_log_statusname nvarchar(50),@s_my_works_flow_log_detail_id  nvarchar(50)
+      select ${_select},@works_flow_key_id='',@works_flow_key_status ='',@s_my_works_flow_log_param='',@s_my_works_flow_log_status=0,@s_my_works_flow_log_statusname='',@s_my_works_flow_log_detail_id=''
+
+      select ${_select2},@works_flow_key_id=id,@s_my_works_flow_log_param=works_flow_param,@s_my_works_flow_log_status=status,@s_my_works_flow_log_statusname=statusname,@s_my_works_flow_log_detail_id=works_flow_detail_id
+      from s_my_works_flow where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+
+      if ${_where}
+      begin
+          set @works_flow_key_status='Y'
+      end
+
+      if @works_flow_key_status='Y'
+      begin
+            update s_my_works_flow set ${field}=${label},status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+            where id=@works_flow_key_id
+
+            insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid,${field})
+            select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@,${label}
+            
+            update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+            where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+
+            if @check_userids@ != ''
+            begin
+                  insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+                  insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@check_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
+            end
+            if @notice_userids@ != ''
+            begin
+                  update n
+                  set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+                  from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
+                  inner join (select ID from dbo.SplitComma(@notice_userids@)) s
+                  on n.userid = s.id
+                  insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
+                  select @ID@,@works_flow_code@,@works_flow_detail_id@,ID,@notice_type@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@notice_userids@)
+            end
+      end
+      else
+      begin
+            update s_my_works_flow set ${field}=${label},modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+            where id =@works_flow_key_id
+
+            insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid,${field})
+            select @ID@,@works_flow_code@,@works_flow_name@ ,@s_my_works_flow_log_param,@s_my_works_flow_log_status,@s_my_works_flow_log_statusname,@s_my_works_flow_log_detail_id,@work_group@,@work_grade@,@time_id@,${label}
+          
+            update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+            where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0 and userid =@userid@
+      end
+      `
       } else {
         _sql += `
       /* 宸ヤ綔娴侀粯璁ql */
-      update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
+      set @retmsg =''
+      select @retmsg='X' from s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0 and userid =@userid@
+
+      if @retmsg =''
+      begin
+          select @retmsg='X' from s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and userid=@userid@
+
+          if @retmsg !='' 
+          begin
+              select @ErrorCode='E', @retmsg='褰撳墠鍗曟嵁宸插鏍革紝璇峰埛鏂板悗閲嶈瘯'
+            goto aaa 
+          end
+
+          select @retmsg='椤甸潰鏁版嵁宸叉洿鏂帮紝鎴栨病鏈夊綋鍓嶅崟鎹殑瀹℃壒鏉冮檺'
+            goto aaa 
+      end
+      set @retmsg=''
+
+      update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname
       where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
       insert into s_my_works_flow_log (works_flow_id,works_flow_code,works_flow_name,works_flow_param,status,statusname,works_flow_detail_id,work_group,work_grade,upid)
       select @ID@,@works_flow_code@,@works_flow_name@ ,@works_flow_param@,@status@,@statusname@,@works_flow_detail_id@,@work_group@,@work_grade@,@time_id@
+      
+      update s_my_works_flow_role set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
+      where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
+
       if @check_userids@ != ''
       begin
-            delete s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
             insert into s_my_works_flow_role (works_flow_id,works_flow_code,userid,works_flow_detail_id,createuserid,CreateUser,CreateStaff,upid)
             select @ID@,@works_flow_code@,ID,@works_flow_detail_id@,@userid@,@UserName,@FullName,@time_id@ from dbo.SplitComma(@check_userids@)
             insert into s_my_works_flow_notice (works_flow_id,works_flow_code,works_flow_detail_id,userid,notice_type,createuserid,CreateUser,CreateStaff,upid)
@@ -2278,7 +2423,8 @@
       end
       if @notice_userids@ != ''
       begin
-            delete n
+            update n
+            set deleted=10,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname 
             from (select * from s_my_works_flow_notice where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0) n
             inner join (select ID from dbo.SplitComma(@notice_userids@)) s
             on n.userid = s.id
@@ -2297,12 +2443,27 @@
       `
     }
 
+    let checkIds = []
+    let checkUsers = []
+    let work_grade = sessionStorage.getItem('work_grade') || 0
     if (verify.flowType !== 'start') {
       if (line) {
-        let checkIds = []
         let noticeIds = []
         line.mkdata.members && line.mkdata.members.forEach(item => {
-          checkIds.push(item.worker_id)
+          if (line.mkdata.approver === 'departmentManager') {
+            if (item.job_type === 'manage' && departmentcode === item.parentIds[1]) {
+              checkIds.push(item.worker_id)
+              checkUsers.push(item)
+            }
+          } else if (line.mkdata.approver === 'directManager') {
+            if (departmentcode === item.parentIds[1] && item.work_grade > work_grade) {
+              checkIds.push(item.worker_id)
+              checkUsers.push(item)
+            }
+          } else {
+            checkIds.push(item.worker_id)
+            checkUsers.push(item)
+          }
         })
         line.mkdata.copys && line.mkdata.copys.forEach(item => {
           noticeIds.push(item.worker_id)
@@ -2313,6 +2474,9 @@
         _sql = _sql.replace(/@check_userids@/ig, `''`)
         _sql = _sql.replace(/@notice_userids@/ig, `''`)
       }
+    } else {
+      _sql = _sql.replace(/@check_userids@/ig, `''`)
+      _sql = _sql.replace(/@notice_userids@/ig, `''`)
     }
 
     _sql = _sql.replace(/@start_type@/ig, `'寮�濮�'`)
@@ -2321,9 +2485,10 @@
 
     _sql = _sql.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
     _sql = _sql.replace(/@works_flow_name@/ig, `'${flow.flow_name}'`)
+
     if (target) {
       let label = target.attrs && target.attrs.text && target.attrs.text.text ? target.attrs.text.text : ''
-      let msg = {...target.mkdata, label: label, id: target.id}
+      let msg = {...target.mkdata, label: label, id: target.id, checkIds, checkUsers}
       _sql = _sql.replace(/@works_flow_param@/ig, `'${window.btoa(window.encodeURIComponent(JSON.stringify(msg)))}'`)
     } else {
       _sql = _sql.replace(/@works_flow_param@/ig, `''`)
@@ -2332,7 +2497,7 @@
     _sql = _sql.replace(/@status@/ig, `'${status}'`)
     _sql = _sql.replace(/@statusname@/ig, `'${statusName}'`)
     _sql = _sql.replace(/@work_group@/ig, `'${sessionStorage.getItem('work_group') || ''}'`)
-    _sql = _sql.replace(/@work_grade@/ig, `'${sessionStorage.getItem('work_grade') || 0}'`)
+    _sql = _sql.replace(/@work_grade@/ig, `'${work_grade}'`)
   }
 
   if (_backCustomScript) {
diff --git a/src/views/appcheck/header/index.jsx b/src/views/appcheck/header/index.jsx
index 96bba6d..a5de4ee 100644
--- a/src/views/appcheck/header/index.jsx
+++ b/src/views/appcheck/header/index.jsx
@@ -7,13 +7,16 @@
 class AppManageHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   render () {
+    const { logo } = this.state
+
     return (
       <header className="app-manage-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="title">
           搴旂敤绠$悊
         </div>
diff --git a/src/views/appmanage/header/index.jsx b/src/views/appmanage/header/index.jsx
index 96bba6d..a5de4ee 100644
--- a/src/views/appmanage/header/index.jsx
+++ b/src/views/appmanage/header/index.jsx
@@ -7,13 +7,16 @@
 class AppManageHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   render () {
+    const { logo } = this.state
+
     return (
       <header className="app-manage-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="title">
           搴旂敤绠$悊
         </div>
diff --git a/src/views/billprint/index.jsx b/src/views/billprint/index.jsx
index 85f4b7e..416c51d 100644
--- a/src/views/billprint/index.jsx
+++ b/src/views/billprint/index.jsx
@@ -1,6 +1,6 @@
 import React, { Component } from 'react'
 import { is, fromJS } from 'immutable'
-import { Col, Row, Spin, notification, Button } from 'antd'
+import { Col, Row, Spin, notification, Button, Modal } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -47,6 +47,8 @@
     auto: true,
     ismob: /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(navigator.userAgent)
   }
+
+  reloading = false
 
   UNSAFE_componentWillMount() {
     const { params } = this.props.match
@@ -367,7 +369,9 @@
             let getColumns = (cols) => {
               return cols.filter(item => {
                 if (item.Hide === 'true') return false
-                  
+
+                item.IsSort = 'false'
+
                 if (item.type === 'number') {
                   if (typeof(item.decimal) === 'number') {
                     item.round = Math.pow(10, item.decimal)
@@ -629,6 +633,9 @@
 
     if (cell.marks && cell.marks.length === 0) {
       cell.marks = null
+    }
+    if (cell.anchors && cell.anchors.length === 0) {
+      cell.anchors = null
     }
     
     if (['text', 'number', 'formula'].includes(cell.eleType)) {
@@ -912,11 +919,15 @@
             if (item.func === 'sPC_Get_structured_data' && /灏嗘埅鏂瓧绗︿覆鎴栦簩杩涘埗鏁版嵁/ig.test(res.message)) {
               res.message = res.message + '璇锋鏌ュ瓧娈甸泦'
             }
-            notification.warning({
-              top: 92,
-              message: res.message,
-              duration: 5
-            })
+            if (res.ErrCode === 'version_up') {
+              this.reloadTabs()
+            } else {
+              notification.warning({
+                top: 92,
+                message: res.message,
+                duration: 5
+              })
+            }
             resolve(false)
           } else {
             res.componentId = componentId
@@ -1076,6 +1087,20 @@
     })
   }
 
+  reloadTabs = () => {
+    if (this.reloading) return
+
+    this.reloading = true
+
+    Api.getAppVersion(true).then(() => {
+      window.location.reload()
+    }, (message) => {
+      Modal.error({
+        title: message || '绯荤粺閰嶇疆鏇存柊澶辫触锛�',
+      })
+    })
+  }
+
   canvasToImage(canvas) {
     let image = new Image()
     image.src = canvas.toDataURL('image/jpg')
diff --git a/src/views/design/header/index.jsx b/src/views/design/header/index.jsx
index 009135a..1184437 100644
--- a/src/views/design/header/index.jsx
+++ b/src/views/design/header/index.jsx
@@ -23,6 +23,7 @@
     menulist: null, // 涓�绾ц彍鍗�
     userName: sessionStorage.getItem('CloudUserName'),
     avatar: Utils.getrealurl(sessionStorage.getItem('CloudAvatar')),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo,
     visible: false,
     loading: false
   }
@@ -409,11 +410,11 @@
 
   render () {
     const { mainMenu, editLevel } = this.props
-    const { menulist, visible, loading } = this.state
+    const { menulist, visible, loading, logo } = this.state
 
     return (
       <header className={'sys-header-container ant-menu-dark ' + (['level2', 'level3'].includes(editLevel) ? 'mask' : '')} id="main-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="header-collapse">
           <MenuFoldOutlined/>
         </div>
diff --git a/src/views/interface/header/index.jsx b/src/views/interface/header/index.jsx
index 903325e..a3944b8 100644
--- a/src/views/interface/header/index.jsx
+++ b/src/views/interface/header/index.jsx
@@ -9,6 +9,7 @@
   state = {
     userName: sessionStorage.getItem('CloudUserName'),
     avatar: Utils.getrealurl(sessionStorage.getItem('CloudAvatar')),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   UNSAFE_componentWillMount() {}
@@ -18,10 +19,11 @@
   }
 
   render () {
+    const { logo } = this.state
 
     return (
       <header className="interface-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="title">鎺ュ彛璋冭瘯</div>
         <div className="header-setting">
           <span className="close" onClick={this.close}>鍏抽棴</span>
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index 2d3f44e..70144d7 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -42,13 +42,6 @@
     syncing: false,
   }
 
-  changelang (item) {
-    // 鍒囨崲璇█
-    this.setState({
-      dict: item === 'zh-CN' ? zhCN : enUS
-    })
-  }
-
   handleSubmit = () => {
     this.loginformRef.handleConfirm().then(res => {
       this.setState({
@@ -354,6 +347,7 @@
     authCode = authCode ? authCode.split(',') : []
     let index = authCode.findIndex(key => key === _s)
     let license = false
+    let appkey = window.GLOB.localkey || window.GLOB.appkey
 
     if (window.GLOB.licenseKey) {
       if (window.GLOB.licenseKey.length !== 20) {
@@ -362,7 +356,7 @@
           okText: '鐭ラ亾浜�'
         })
       } else {
-        let key = md5(window.GLOB.appId + 'minke_software' + window.GLOB.appkey).toUpperCase().substr(-6)
+        let key = md5(window.GLOB.appId + 'minke_software' + appkey).toUpperCase().substr(-6)
   
         let key1 = window.GLOB.licenseKey.substring(0, 6)
         let key2 = window.GLOB.licenseKey.substring(6, 14)
@@ -370,7 +364,7 @@
         let key4 = md5(key1 + key2).toUpperCase().substr(-6)
   
         if (key === key1 && key3 === key4) {
-          let last = window.GLOB.appkey[window.GLOB.appkey.length - 1]
+          let last = appkey[appkey.length - 1]
           let offset = 0
           let keys = {}
       
@@ -443,7 +437,7 @@
         func: _func,
         AppID: window.GLOB.appId,
         TimeStamp: timeStamp,
-        appkey: window.GLOB.appkey,
+        appkey: appkey,
         SessionUid: localStorage.getItem('SessionUid') || '',
         userid: _id,
         LoginUID: _id,
@@ -573,7 +567,8 @@
         let _param = {
           func: 's_Get_style',
           TypeCharOne: 'PC',
-          LText: `select '${window.GLOB.appkey}'`,
+          LText: `select '${appkey}'`,
+          appkey: appkey
         }
 
         _param.userid = result.UserID
@@ -631,7 +626,7 @@
             }
 
             if ([10, 20, 30, 40, 50, 60, 70, 80, 90, 100].includes(res.member_level)) {
-              systemMsg.Member_Level = md5('mksoft' + window.GLOB.appkey + res.member_level)
+              systemMsg.Member_Level = md5('mksoft' + appkey + res.member_level)
               if (!window.GLOB.memberLevel) {
                 Object.defineProperty(window.GLOB, 'memberLevel', {
                   writable: false,
@@ -945,7 +940,6 @@
             lang={this.state.selectedlang}
             langList={this.state.langList}
             isDisabled={this.state.isDisabled}
-            changelang={(value) => this.changelang(value)}
             handleSubmit={() => this.handleSubmit()}
             authLogin={this.authLogin}
             wrappedComponentRef={(inst) => this.loginformRef = inst}
diff --git a/src/views/login/loginform.jsx b/src/views/login/loginform.jsx
index 4fdab93..057d84b 100644
--- a/src/views/login/loginform.jsx
+++ b/src/views/login/loginform.jsx
@@ -18,7 +18,6 @@
 class LoginTabForm extends Component {
   static propTpyes = {
     isDisabled: PropTypes.bool,
-    changelang: PropTypes.func,
     handleSubmit: PropTypes.func,
     authLogin: PropTypes.func,
     dict: PropTypes.object,
@@ -174,8 +173,12 @@
     })
   }
 
-  changelang = (item) => {
-    this.props.changelang(item)
+  changelang = (val) => {
+    const _href = window.location.href.split('#')[0]
+    localStorage.setItem(_href + 'lang', val)
+    sessionStorage.setItem('lang', val)
+
+    window.location.reload()
   }
 
   handleSubmit = e => {
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 7d3ece5..3f94889 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -654,7 +654,7 @@
         
         if (item.action && item.action.length > 0) {
           item.action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
             buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
             _sort++
           })
@@ -669,13 +669,13 @@
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
               if (cell.eleType !== 'button') return
-              if (cell.hidden === 'true') return
+              if (cell.hidden === 'true' || cell.permission === 'false') return
               buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
               _sort++
             })
             card.backElements && card.backElements.forEach(cell => {
               if (cell.eleType !== 'button') return
-              if (cell.hidden === 'true') return
+              if (cell.hidden === 'true' || cell.permission === 'false') return
               buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
               _sort++
             })
@@ -683,7 +683,7 @@
         } else if (item.type === 'balcony') {
           item.elements && item.elements.forEach(cell => {
             if (cell.eleType !== 'button') return
-            if (cell.hidden === 'true') return
+            if (cell.hidden === 'true' || cell.permission === 'false') return
             buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
             _sort++
           })
@@ -694,7 +694,7 @@
                 loopCol(col.subcols)
               } else if (col.type === 'custom') {
                 col.elements.forEach(cell => {
-                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
+                  if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
                   buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
                   _sort++
                 })
@@ -799,6 +799,11 @@
 
       let tbs = []
       let btns = this.getMenuMessage(config, tbs)
+
+      if (config.permission === 'false') {
+        btns = []
+      }
+
       let arr = []
       tbs = tbs.filter(tb => {
         let _tb = tb.toLowerCase()
@@ -828,6 +833,7 @@
       }
 
       let interfaces = getFuncsAndInters(config)
+      let urlFields = config.urlFields ? config.urlFields.join(',') : ''
 
       let param = {
         func: 'sPC_TrdMenu_AddUpt',
@@ -839,7 +845,7 @@
         EasyCode: config.easyCode || '',
         Template: 'CustomPage',
         MenuName: config.MenuName || '',
-        PageParam: JSON.stringify({Template: 'CustomPage', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces}),
+        PageParam: JSON.stringify({Template: 'CustomPage', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces, urlFields}),
         open_edition: config.open_edition,
         LText: '',
         LTexttb: '',
diff --git a/src/views/mkiframe/index.jsx b/src/views/mkiframe/index.jsx
index 2547d9d..b6e9761 100644
--- a/src/views/mkiframe/index.jsx
+++ b/src/views/mkiframe/index.jsx
@@ -19,6 +19,8 @@
     type: 'CustomPage'
   }
 
+  reloading = false
+
   UNSAFE_componentWillMount() {
     const { params, path } = this.props.match
     const { menuId, loginUid, bid } = params
@@ -112,6 +114,10 @@
     MKEmitter.addListener('modifyTabs', this.modifyTabs)
     MKEmitter.addListener('closeTabView', this.closeTabView)
 
+    if (window.GLOB.forcedUpdate) {
+      MKEmitter.addListener('reloadTabs', this.reloadTabs)
+    }
+
     if (window.GLOB.sysType !== 'cloud') {
       Object.defineProperty(window, 'debugger', {
         configurable: true,
@@ -152,7 +158,24 @@
       return
     }
     MKEmitter.removeListener('modifyTabs', this.modifyTabs)
+    MKEmitter.removeListener('reloadTabs', this.reloadTabs)
     MKEmitter.removeListener('closeTabView', this.closeTabView)
+  }
+
+  reloadTabs = () => {
+    if (this.reloading) return
+
+    this.reloading = true
+
+    Api.getAppVersion(true).then(() => {
+      window.location.reload()
+    }, (message) => {
+      notification.error({
+        top: 92,
+        message: message || '绯荤粺閰嶇疆鏇存柊澶辫触锛�',
+        duration: 10
+      })
+    })
   }
 
   modifyTabs = (tab) => {
@@ -183,7 +206,10 @@
     let historys = sessionStorage.getItem('page_historys')
     historys = historys ? JSON.parse(historys) : []
 
-    if (historys.length === 0) return
+    if (historys.length === 0) {
+      window.close()
+      return
+    }
 
     let tab = historys.shift()
 
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index 575cb43..d6e5f24 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -1039,7 +1039,7 @@
           return
         } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
           item.action && item.action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
 
             m.children.push({
               key: btn.uuid,
@@ -1048,7 +1048,7 @@
           })
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
-              if (cell.eleType !== 'button' || cell.hidden === 'true') return
+              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
               m.children.push({
                 key: cell.uuid,
@@ -1059,7 +1059,7 @@
             if (item.subtype !== 'dualdatacard') return
             
             card.backElements && card.backElements.forEach(cell => {
-              if (cell.eleType !== 'button' || cell.hidden === 'true') return
+              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
               m.children.push({
                 key: cell.uuid,
@@ -1069,7 +1069,7 @@
           })
         } else if (item.type === 'balcony') {
           item.elements && item.elements.forEach(cell => {
-            if (cell.eleType !== 'button' || cell.hidden === 'true') return
+            if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
             m.children.push({
               key: cell.uuid,
@@ -1098,7 +1098,7 @@
           }
         } else if (item.type === 'table') {
           item.action && item.action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
 
             m.children.push({
               key: btn.uuid,
@@ -1111,7 +1111,7 @@
                 loopCol(col.subcols)
               } else if (col.type === 'custom') {
                 col.elements.forEach(cell => {
-                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
+                  if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
                   m.children.push({
                     key: cell.uuid,
                     title: cell.label,
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index 4efe859..8206e33 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -877,7 +877,7 @@
           return
         } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
           item.action && item.action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
 
             m.children.push({
               key: btn.uuid,
@@ -886,7 +886,7 @@
           })
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
-              if (cell.eleType !== 'button' || cell.hidden === 'true') return
+              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
               m.children.push({
                 key: cell.uuid,
@@ -895,7 +895,7 @@
             })
 
             card.backElements && card.backElements.forEach(cell => {
-              if (cell.eleType !== 'button' || cell.hidden === 'true') return
+              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
               m.children.push({
                 key: cell.uuid,
@@ -905,7 +905,7 @@
           })
         } else if (item.type === 'balcony') {
           item.elements && item.elements.forEach(cell => {
-            if (cell.eleType !== 'button' || cell.hidden === 'true') return
+            if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
 
             m.children.push({
               key: cell.uuid,
@@ -923,7 +923,7 @@
           }
         } else if (item.type === 'table') {
           item.action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
 
             m.children.push({
               key: btn.uuid,
@@ -936,7 +936,7 @@
                 loopCol(col.subcols)
               } else if (col.type === 'custom') {
                 col.elements.forEach(cell => {
-                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
+                  if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
                   m.children.push({
                     key: cell.uuid,
                     title: cell.label,
diff --git a/src/views/rolemanage/header/index.jsx b/src/views/rolemanage/header/index.jsx
index d49edb8..6fd53ce 100644
--- a/src/views/rolemanage/header/index.jsx
+++ b/src/views/rolemanage/header/index.jsx
@@ -7,14 +7,17 @@
 class AppManageHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   render () {
     const { app } = this.props
+    const { logo } = this.state
+
     return (
       <header className="app-manage-header-container">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="title">
           {`${app.remark} ${app.typename}`}
         </div>
diff --git a/src/views/systemfunc/header/index.jsx b/src/views/systemfunc/header/index.jsx
index c146a84..03f2dfc 100644
--- a/src/views/systemfunc/header/index.jsx
+++ b/src/views/systemfunc/header/index.jsx
@@ -8,14 +8,11 @@
   state = {
     userName: sessionStorage.getItem('CloudUserName'),
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
+    logo: sessionStorage.getItem('CloudLogo') || MainLogo
   }
 
   exitManage = () => {
     window.close()
-  }
-
-  UNSAFE_componentWillMount () {
-
   }
 
   /**
@@ -28,9 +25,11 @@
   }
 
   render () {
+    const { logo } = this.state
+
     return (
       <header className="sys-header-container ant-menu-dark">
-        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="header-logo"><img src={logo} alt=""/></div>
         <div className="title">HS</div>
         <div className="header-setting">
           <img src={this.state.avatar} alt=""/>
diff --git a/src/views/systemfunc/sidemenu/index.jsx b/src/views/systemfunc/sidemenu/index.jsx
index 53dc77f..a11e157 100644
--- a/src/views/systemfunc/sidemenu/index.jsx
+++ b/src/views/systemfunc/sidemenu/index.jsx
@@ -66,7 +66,7 @@
         if (menu) {
           menu = fromJS(menu).toJS()
           menu.param = {}
-          menu.param.$searchkey = 'PrintTempNO'
+          menu.param.$searchkey = 'printtempno'
           menu.param.$searchval = temp
           setTimeout(() => {
             MKEmitter.emit('modifyTabs', menu)
@@ -77,7 +77,7 @@
         if (menu) {
           menu = fromJS(menu).toJS()
           menu.param = {}
-          menu.param.$searchkey = 'PrintTempNO'
+          menu.param.$searchkey = 'printtempno'
           menu.param.$searchval = tabTemp
           setTimeout(() => {
             MKEmitter.emit('modifyTabs', menu)
diff --git a/src/views/tabledesign/index.jsx b/src/views/tabledesign/index.jsx
index 7d16779..ce28473 100644
--- a/src/views/tabledesign/index.jsx
+++ b/src/views/tabledesign/index.jsx
@@ -459,7 +459,7 @@
           let _s = 1
 
           tab.components[0].action.forEach(btn => {
-            if (btn.hidden === 'true') return
+            if (btn.hidden === 'true' || btn.permission === 'false') return
 
             buttons.push(`select '${btn.uuid}' as menuid, '${btn.label}' as menuname, '${_s * 10}' as Sort, '${tab.components[0].uuid}' as parentid, 60 as Type`)
             _s++
@@ -471,7 +471,7 @@
                 loopCol(col.subcols)
               } else if (col.type === 'custom') {
                 col.elements.forEach(cell => {
-                  if (cell.eleType !== 'button' || cell.hidden === 'true') return
+                  if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
                   buttons.push(`select '${cell.uuid}' as menuid, '${cell.label}' as menuname, '${_s * 10}' as Sort, '${tab.components[0].uuid}' as parentid, 60 as Type`)
                   _s++
                 })
@@ -486,7 +486,7 @@
           tbs.push(...item.$tables)
         }
         item.action.forEach(btn => {
-          if (btn.hidden === 'true') return
+          if (btn.hidden === 'true' || btn.permission === 'false') return
 
           buttons.push(`select '${btn.uuid}' as menuid, '${btn.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
           _sort++
@@ -498,7 +498,7 @@
               loopCol(col.subcols)
             } else if (col.type === 'custom') {
               col.elements.forEach(cell => {
-                if (cell.eleType !== 'button' || cell.hidden === 'true') return
+                if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.permission === 'false') return
                 buttons.push(`select '${cell.uuid}' as menuid,  '${cell.label}' as menuname, '${_sort * 10}' as Sort, '${config.uuid}' as parentid, 40 as Type`)
                 _sort++
               })
@@ -581,6 +581,7 @@
       }
 
       let interfaces = getFuncsAndInters(config)
+      let urlFields = config.urlFields ? config.urlFields.join(',') : ''
 
       let param = {
         func: 'sPC_TrdMenu_AddUpt',
@@ -592,7 +593,7 @@
         EasyCode: config.easyCode || '',
         Template: 'BaseTable',
         MenuName: config.MenuName || '',
-        PageParam: JSON.stringify({Template: 'BaseTable', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces}),
+        PageParam: JSON.stringify({Template: 'BaseTable', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces, urlFields}),
         open_edition: config.open_edition,
         LText: '',
         LTexttb: '',
@@ -892,6 +893,13 @@
               <div className={'menu-view' + (menuloading ? ' saving' : '')}>
                 <Card bordered={false} extra={
                   <div className="mk-opeartion-list">
+                    {/* <Dropdown overlay={
+                      <div className="mk-button-dropdown-wrap">
+                        <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
+                      </div>
+                    } trigger={['click']} placement="bottomCenter">
+                      <Button className="mk-button-more">鏇村<DownOutlined/></Button>
+                    </Dropdown> */}
                     {config ? <Debug config={config}/> : null}
                     {config ? <Transfer config={config}/> : null}
                     {config ? <Unattended config={config} updateConfig={this.updateConfig}/> : null}

--
Gitblit v1.8.0