From 34e7681fd12b1c4e4994d3bea1a553870e10bc50 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期六, 11 三月 2023 17:58:54 +0800
Subject: [PATCH] 2023-03-11

---
 src/templates/zshare/modalform/index.jsx                                                  |   31 
 src/menu/components/timeline/normal-timeline/index.jsx                                    |   14 
 src/tabviews/custom/components/editor/braft-editor/index.jsx                              |   63 
 src/menu/components/chart/antv-bar/chartcompile/index.scss                                |   11 
 src/mob/mobshell/index.jsx                                                                |   20 
 src/components/resetPassword/index.jsx                                                    |  182 
 src/menu/components/card/balcony/options.jsx                                              |   20 
 src/templates/zshare/verifycard/customscript/index.jsx                                    |    8 
 src/views/menudesign/printmenuform/index.jsx                                              |   14 
 src/tabviews/custom/popview/index.jsx                                                     |   70 
 src/menu/components/chart/antv-scatter/index.jsx                                          |   12 
 src/tabviews/custom/components/module/voucher/resetAttach/documents/index.scss            |    0 
 src/tabviews/zshare/mutilform/mkInput/index.jsx                                           |    4 
 src/menu/components/table/edit-table/columns/editColumn/index.jsx                         |   24 
 src/tabviews/zshare/actionList/changeuserbutton/index.jsx                                 |   97 
 src/menu/datasource/verifycard/index.jsx                                                  |  153 
 src/assets/css/main.scss                                                                  |   21 
 src/tabviews/custom/components/module/voucher/resetAttach/index.scss                      |  235 
 src/menu/components/card/cardcellcomponent/index.jsx                                      |   36 
 src/menu/components/form/dragtitle/index.scss                                             |    4 
 src/menu/components/form/tab-form/index.jsx                                               |  130 
 src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx             |  120 
 src/menu/stylecontroller/syscolorsketch/index.scss                                        |   13 
 src/pc/menushell/card.jsx                                                                 |   22 
 src/menu/components/carousel/prop-card/index.jsx                                          |   12 
 src/tabviews/zshare/actionList/funcMegvii/index.jsx                                       |   75 
 src/menu/components/card/cardcomponent/index.jsx                                          |   19 
 src/menu/components/chart/antv-pie/index.jsx                                              |   12 
 src/views/systemproc/proc/index.scss                                                      |    4 
 src/menu/components/table/edit-table/columns/index.scss                                   |    1 
 src/views/menudesign/index.scss                                                           |    8 
 src/menu/components/card/prop-card/index.jsx                                              |   14 
 src/menu/components/tabs/tabcomponents/card.jsx                                           |    7 
 src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx                        |  122 
 src/templates/zshare/modalform/modaleditable/index.jsx                                    |   50 
 src/menu/components/tabs/paste/index.jsx                                                  |   23 
 src/menu/components/table/edit-table/columns/index.jsx                                    |  193 
 src/menu/datasource/verifycard/utils.jsx                                                  |   44 
 src/tabviews/custom/components/chart/antv-bar-line/index.jsx                              |   74 
 package-lock.json                                                                         |  121 
 src/assets/css/viewstyle.scss                                                             |   82 
 src/tabviews/custom/components/chart/antv-dashboard/index.jsx                             |    2 
 src/views/login/loginform.jsx                                                             |    2 
 src/menu/datasource/verifycard/index.scss                                                 |   17 
 src/templates/zshare/codemirror/index.scss                                                |    3 
 src/menu/components/share/actioncomponent/dragaction/card.jsx                             |    2 
 src/tabviews/zshare/topSearch/index.jsx                                                   |   10 
 src/menu/components/form/tab-form/index.scss                                              |    1 
 src/menu/components/card/doublecardcomponent/index.scss                                   |  118 
 src/templates/comtableconfig/index.jsx                                                    |  147 
 src/menu/components/form/simple-form/options.jsx                                          |   26 
 src/menu/components/form/simple-form/index.jsx                                            |   89 
 src/tabviews/custom/components/table/edit-table/index.jsx                                 |   17 
 src/mob/components/tabs/tabcomponents/index.jsx                                           |   20 
 src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx                        |    4 
 src/menu/stylecombcontroller/styleInput/index.scss                                        |    2 
 src/mob/mobshell/card.jsx                                                                 |   35 
 src/templates/zshare/codemirror/index.jsx                                                 |   10 
 src/assets/img/file-ppt-fill.png                                                          |    0 
 src/mob/components/search/single-search/index.jsx                                         |   11 
 src/tabviews/custom/components/card/prop-card/index.scss                                  |    5 
 src/menu/components/table/base-table/columns/editColumn/index.jsx                         |   10 
 src/tabviews/zshare/tablenodes/index.jsx                                                  |   44 
 src/pc/bgcontroller/index.jsx                                                             |   72 
 src/views/pcdesign/index.jsx                                                              |  108 
 src/menu/datasource/verifycard/settingform/index.jsx                                      |   52 
 src/mob/components/formdragelement/index.jsx                                              |    4 
 src/mob/components/tabs/tabcomponents/card.jsx                                            |    7 
 src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx                         |    8 
 src/views/systemfunc/sidemenu/index.jsx                                                   |   10 
 src/locales/zh-CN/login.js                                                                |    2 
 src/tabviews/custom/components/module/account/index.scss                                  |    9 
 src/tabviews/custom/components/form/step-form/index.jsx                                   |   22 
 src/templates/modalconfig/source.jsx                                                      |    5 
 src/views/systemfunc/sidemenu/config.jsx                                                  |   18 
 src/assets/img/file-excel-fill.png                                                        |    0 
 src/menu/components/form/dragtitle/card.jsx                                               |   12 
 src/pc/modulesource/option.jsx                                                            |    5 
 src/menu/components/editor/braft-editor/options.jsx                                       |   49 
 src/tabviews/custom/components/card/cardItem/index.scss                                   |   16 
 src/menu/components/group/paste/index.jsx                                                 |    4 
 src/tabviews/custom/components/tree/antd-tree/index.jsx                                   |  109 
 src/tabviews/zshare/actionList/popupbutton/index.jsx                                      |   99 
 src/tabviews/zshare/normalTable/index.jsx                                                 |    6 
 src/templates/comtableconfig/updatetable/index.jsx                                        |   14 
 src/templates/treepageconfig/index.jsx                                                    |  102 
 src/menu/datasource/index.jsx                                                             |    4 
 src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx                            |    2 
 src/menu/components/module/voucher/index.jsx                                              |   66 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx                     |    4 
 src/menu/components/form/step-form/index.scss                                             |    2 
 src/menu/components/tree/antd-tree/index.jsx                                              |   78 
 src/tabviews/custom/index.scss                                                            |    5 
 src/views/billprint/index.jsx                                                             |   11 
 src/locales/en-US/main.js                                                                 |    6 
 src/tabviews/subtabtable/index.jsx                                                        |    9 
 src/tabviews/zshare/actionList/normalbutton/index.jsx                                     |  319 
 src/views/tabledesign/index.scss                                                          |    6 
 src/views/menudesign/index.jsx                                                            |   23 
 src/menu/modulesource/option.jsx                                                          |    5 
 src/tabviews/custom/components/card/data-card/index.jsx                                   |  122 
 src/tabviews/custom/components/module/voucher/index.jsx                                   | 1093 +++
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx                         |   11 
 src/templates/calendarconfig/index.jsx                                                    |   65 
 src/menu/components/card/double-data-card/index.jsx                                       |  645 ++
 src/menu/components/card/doublecardcomponent/index.jsx                                    |  318 +
 src/menu/stylecontroller/styleInput/index.jsx                                             |   14 
 src/views/tabledesign/popview/index.scss                                                  |    2 
 src/menu/pastecontroller/index.jsx                                                        |   17 
 src/menu/components/card/data-card/index.jsx                                              |   27 
 src/menu/components/chart/antv-dashboard/index.jsx                                        |   12 
 src/views/appmanage/index.jsx                                                             |    7 
 src/menu/components/search/main-search/options.jsx                                        |   11 
 src/tabviews/custom/components/module/voucher/printVoucher/index.scss                     |  126 
 src/tabviews/zshare/actionList/index.scss                                                 |    1 
 src/tabviews/zshare/mutilform/mkInput/index.scss                                          |    2 
 src/views/design/index.jsx                                                                |    2 
 src/menu/components/card/doublecardcomponent/options.jsx                                  |  194 
 src/menu/components/chart/antv-G6/index.jsx                                               |   12 
 src/menu/components/tree/antd-tree/index.scss                                             |    3 
 src/components/header/index.jsx                                                           |  117 
 src/tabviews/custom/components/card/double-data-card/index.jsx                            |  973 +++
 src/templates/formtabconfig/index.jsx                                                     |  101 
 src/templates/zshare/verifycard/callbackcustomscript/index.jsx                            |    4 
 src/tabviews/custom/components/card/cardItem/index.jsx                                    |   23 
 src/components/qrcode/index.jsx                                                           |    4 
 src/mob/modalconfig/source.jsx                                                            |    5 
 src/menu/components/iframe/index.jsx                                                      |   12 
 src/mob/components/topbar/normal-navbar/options.jsx                                       |    9 
 src/templates/zshare/editcomponent/index.jsx                                              |  132 
 src/tabviews/custom/components/carousel/data-card/index.jsx                               |   23 
 src/templates/sharecomponent/fieldscomponent/index.jsx                                    |   35 
 src/menu/components/code/sandbox/index.jsx                                                |    2 
 src/tabviews/zshare/mutilform/mkSelect/index.jsx                                          |    2 
 src/tabviews/custom/components/tree/antd-tree/index.scss                                  |   34 
 src/mob/modalconfig/pastecomponent/index.jsx                                              |    6 
 src/components/paste/index.jsx                                                            |    4 
 src/tabviews/custom/components/chart/custom-chart/index.jsx                               |    2 
 src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss                     |  117 
 src/menu/components/card/balcony/index.jsx                                                |   31 
 src/tabviews/zshare/actionList/tabbutton/index.jsx                                        |   97 
 src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx                      |  103 
 src/menu/stylecontroller/index.jsx                                                        |   91 
 src/tabviews/custom/components/module/voucher/voucherTable/index.scss                     |  140 
 src/templates/zshare/verifycard/index.jsx                                                 |    2 
 src/menu/modulecell/index.jsx                                                             |    3 
 src/tabviews/zshare/actionList/printbutton/index.jsx                                      |  162 
 src/tabviews/custom/components/table/edit-table/normalTable/index.scss                    |    5 
 src/menu/components/card/cardcellcomponent/formconfig.jsx                                 |   26 
 src/tabviews/custom/components/module/voucher/index.scss                                  |   77 
 src/menu/components/editor/braft-editor/index.jsx                                         |   47 
 src/menu/components/module/voucher/index.scss                                             |   32 
 package.json                                                                              |    1 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx          |   49 
 src/views/menudesign/popview/index.scss                                                   |    2 
 src/views/systemproc/proc/index.jsx                                                       |    2 
 src/menu/components/chart/antv-bar/chartcompile/index.jsx                                 |   41 
 src/tabviews/custom/components/module/voucher/resetRemark/index.jsx                       |   62 
 src/menu/components/share/markcomponent/index.jsx                                         |    3 
 src/menu/components/card/cardcellcomponent/dragaction/action.jsx                          |    4 
 src/menu/components/card/cardcellcomponent/elementform/index.jsx                          |  100 
 src/assets/img/picture-fill.png                                                           |    0 
 src/menu/components/share/actioncomponent/dragaction/index.jsx                            |    3 
 src/menu/stylecombcontroller/styleInput/index.jsx                                         |    2 
 src/menu/components/table/edit-table/options.jsx                                          |   15 
 src/menu/stylecontroller/index.scss                                                       |   13 
 src/templates/modalconfig/index.jsx                                                       |   32 
 src/tabviews/custom/components/form/step-form/index.scss                                  |    2 
 src/tabviews/zshare/actionList/newpagebutton/index.jsx                                    |   97 
 src/views/design/sidemenu/index.jsx                                                       |    2 
 src/mob/modalconfig/index.jsx                                                             |  112 
 src/menu/stylecombcontroller/index.jsx                                                    |   52 
 src/tabviews/commontable/index.jsx                                                        |   12 
 src/locales/en-US/login.js                                                                |    2 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx                      |   22 
 src/assets/img/rar.png                                                                    |    0 
 src/menu/stylecontroller/styleInput/index.scss                                            |    2 
 src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx                    |   28 
 src/menu/normalCss/index.scss                                                             |   21 
 src/tabviews/custom/components/card/cardcellList/index.jsx                                |   27 
 src/tabviews/custom/components/card/prop-card/index.jsx                                   |   32 
 src/menu/stylecontroller/syscolorsketch/index.jsx                                         |   44 
 src/tabviews/zshare/actionList/funczip/index.jsx                                          |   75 
 src/menu/components/carousel/data-card/options.jsx                                        |    1 
 src/menu/components/card/data-card/options.jsx                                            |   18 
 src/tabviews/custom/components/table/normal-table/index.jsx                               |   28 
 src/tabviews/custom/components/chart/antv-pie/index.jsx                                   |    2 
 src/tabviews/custom/components/timeline/normal-timeline/index.jsx                         |   17 
 src/templates/subtableconfig/index.jsx                                                    |  257 
 src/tabviews/custom/components/table/edit-table/normalTable/index.jsx                     |  146 
 src/menu/components/group/groupcomponents/card.jsx                                        |    3 
 src/tabviews/zshare/mutilform/index.jsx                                                   |  105 
 src/templates/zshare/modalform/index.scss                                                 |    5 
 src/menu/components/share/actioncomponent/actionform/index.jsx                            |   23 
 src/tabviews/custom/index.jsx                                                             |   90 
 src/menu/components/card/cardcomponent/index.scss                                         |   31 
 src/menu/components/table/normal-table/columns/index.jsx                                  |    3 
 src/views/appmanage/submutilform/index.jsx                                                |   12 
 src/tabviews/custom/components/chart/antv-scatter/index.jsx                               |    2 
 src/menu/components/card/cardcellcomponent/dragaction/index.scss                          |   68 
 src/tabviews/custom/components/form/tab-form/index.scss                                   |    2 
 src/views/design/header/index.jsx                                                         |   38 
 src/tabviews/custom/components/module/account/index.jsx                                   |   79 
 src/tabviews/custom/components/chart/antv-G6/index.jsx                                    |    4 
 src/pc/menushell/index.jsx                                                                |   20 
 src/tabviews/custom/popview/index.scss                                                    |    5 
 src/tabviews/zshare/actionList/exceloutbutton/index.jsx                                   |  125 
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx                            |   19 
 src/menu/components/card/balcony/index.scss                                               |    7 
 src/menu/components/chart/antv-bar/index.jsx                                              |   12 
 src/views/tabledesign/index.jsx                                                           |   31 
 src/tabviews/zshare/actionList/index.jsx                                                  |    1 
 src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss                       |    0 
 src/tabviews/custom/components/form/simple-form/index.jsx                                 |    8 
 src/tabviews/subtable/index.jsx                                                           |   10 
 src/menu/components/table/edit-table/index.jsx                                            |   22 
 src/menu/components/carousel/data-card/index.jsx                                          |   12 
 src/tabviews/custom/components/card/table-card/index.jsx                                  |   19 
 src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss                          |  117 
 src/menu/components/module/voucher/options.jsx                                            |   66 
 src/menu/components/form/step-form/index.jsx                                              |  150 
 src/tabviews/zshare/mutilform/mkCheckCard/index.jsx                                       |   30 
 src/templates/modalconfig/settingform/index.jsx                                           |   36 
 src/views/mobdesign/popview/index.jsx                                                     |    4 
 src/menu/components/search/main-search/index.jsx                                          |   14 
 src/tabviews/custom/components/module/voucher/voucherTable/index.jsx                      | 1191 ++-
 src/tabviews/custom/components/module/voucher/resetRemark/index.scss                      |    0 
 src/views/login/index.scss                                                                |    2 
 src/menu/components/module/account/options.jsx                                            |   16 
 src/templates/zshare/modalform/modaleditable/index.scss                                   |    9 
 src/views/login/index.jsx                                                                 |   88 
 src/tabviews/zshare/mutilform/mkRadio/index.jsx                                           |    2 
 src/utils/utils-datamanage.js                                                             |   33 
 src/tabviews/custom/components/code/sand-box/index.jsx                                    |   20 
 src/menu/components/card/table-card/index.jsx                                             |   14 
 src/menu/components/share/pastebasetable/index.jsx                                        |    4 
 src/utils/utils-custom.js                                                                 |  259 
 src/mob/modulesource/option.jsx                                                           |    5 
 src/components/resetPassword/index.scss                                                   |   22 
 src/templates/sharecomponent/fieldscomponent/editcard/index.jsx                           |    4 
 src/tabviews/zshare/actionList/excelInbutton/index.jsx                                    |   97 
 public/options.json                                                                       |    4 
 src/pc/components/login/normal-login/options.jsx                                          |   18 
 src/menu/components/tabs/tabcomponents/index.jsx                                          |   20 
 src/tabviews/basetable/index.jsx                                                          |   22 
 src/menu/tablenodes/index.jsx                                                             |   25 
 src/views/pcdesign/index.scss                                                             |   11 
 src/menu/menushell/card.jsx                                                               |    7 
 src/tabviews/zshare/mutilform/mkVercode/index.jsx                                         |  220 
 src/tabviews/custom/components/module/voucher/printVoucher/index.jsx                      |  354 +
 src/templates/modalconfig/dragelement/card.jsx                                            |    6 
 src/views/mobdesign/index.jsx                                                             |   77 
 src/tabviews/zshare/mutilform/mkVercode/index.scss                                        |    0 
 src/views/design/index.scss                                                               |    5 
 src/api/cacheutils.js                                                                     |    4 
 src/assets/img/file-word-fill.png                                                         |    0 
 src/menu/components/card/double-data-card/options.jsx                                     |  240 
 src/menu/components/share/actioncomponent/formconfig.jsx                                  |   75 
 src/tabviews/basetable/index.scss                                                         |    5 
 src/tabviews/custom/components/group/normal-group/index.jsx                               |    9 
 src/tabviews/custom/components/carousel/prop-card/index.jsx                               |   22 
 src/menu/components/table/base-table/columns/index.jsx                                    |    2 
 src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx             |  160 
 src/menu/components/table/normal-table/index.jsx                                          |   14 
 src/views/design/sidemenu/thdmenuplus/index.jsx                                           |    9 
 src/menu/components/card/cardcomponent/options.jsx                                        |   21 
 src/menu/components/group/normal-group/index.jsx                                          |   39 
 src/menu/components/form/simple-form/index.scss                                           |   11 
 src/tabviews/custom/components/table/base-table/index.jsx                                 |   12 
 src/tabviews/custom/components/card/double-data-card/index.scss                           |  338 +
 src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx        |    2 
 src/components/resetPassword/resetpwd/index.jsx                                           |  317 +
 src/assets/img/file-fill.png                                                              |    0 
 src/menu/datasource/verifycard/customscript/index.jsx                                     |    2 
 src/menu/components/form/dragtitle/index.jsx                                              |    9 
 src/views/mobdesign/index.scss                                                            |   10 
 src/tabviews/custom/components/share/normalTable/index.jsx                                |    6 
 src/templates/modalconfig/dragelement/index.jsx                                           |    2 
 src/menu/components/form/step-form/options.jsx                                            |   42 
 src/assets/img/file-pdf-fill.png                                                          |    0 
 src/menu/normalCss/index.jsx                                                              |   70 
 src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx                           |  116 
 src/tabviews/custom/components/card/data-card/index.scss                                  |   92 
 src/utils/utils.js                                                                        |   44 
 src/tabviews/custom/components/card/table-card/index.scss                                 |    7 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx                     |   70 
 src/index.js                                                                              |   11 
 src/tabviews/custom/components/form/tab-form/index.jsx                                    |   16 
 src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.jsx  |  266 
 src/menu/components/search/main-search/dragsearch/index.jsx                               |    8 
 src/menu/components/share/pastecomponent/index.jsx                                        |   13 
 src/locales/zh-CN/main.js                                                                 |    6 
 src/tabviews/custom/components/share/tabtransfer/index.jsx                                |    7 
 src/templates/zshare/formconfig.jsx                                                       |  119 
 src/tabviews/custom/components/interfaces/interItem/index.jsx                             |   40 
 src/tabviews/custom/components/module/voucher/resetAttach/index.jsx                       |  297 +
 src/pc/createview/index.jsx                                                               |    8 
 src/mob/components/formdragelement/card.jsx                                               |    2 
 src/pc/components/login/normal-login/index.jsx                                            |   16 
 /dev/null                                                                                 |  259 
 src/menu/modalconfig/index.scss                                                           |    9 
 src/templates/sharecomponent/searchcomponent/settingform/index.jsx                        |   12 
 src/menu/modalconfig/index.jsx                                                            |  112 
 src/tabviews/custom/components/card/balcony/index.jsx                                     |   21 
 src/tabviews/custom/components/card/cardcellList/index.scss                               |    1 
 src/menu/components/table/base-table/index.jsx                                            |    9 
 src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.scss |   29 
 src/menu/menushell/index.jsx                                                              |   20 
 src/menu/components/card/double-data-card/index.scss                                      |  148 
 309 files changed, 14,007 insertions(+), 3,326 deletions(-)

diff --git a/package-lock.json b/package-lock.json
index a469c79..40ebbc0 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3158,6 +3158,12 @@
       "resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.2.tgz",
       "integrity": "sha512-ce5d3q03Ex0sy4R14722Rmt6MT07Ua+k4FwDfdcToYJcMKNtRVQvJ6JCAPdAmAnbRb6CsX6aYb9m96NGod9uTw=="
     },
+    "@types/raf": {
+      "version": "3.4.0",
+      "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.0.tgz",
+      "integrity": "sha512-taW5/WYqo36N7V39oYyHP9Ipfd5pNFvGTIQsNGj86xV88YQ7GnI30/yMfKDF7Zgin0m3e+ikX88FvImnK4RjGw==",
+      "optional": true
+    },
     "@types/react": {
       "version": "16.9.2",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.2.tgz",
@@ -5216,6 +5222,11 @@
         "node-int64": "^0.4.0"
       }
     },
+    "btoa": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
+      "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g=="
+    },
     "buffer": {
       "version": "4.9.1",
       "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
@@ -5404,9 +5415,48 @@
       }
     },
     "caniuse-lite": {
-      "version": "1.0.30001399",
-      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz",
-      "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA=="
+      "version": "1.0.30001464",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001464.tgz",
+      "integrity": "sha512-oww27MtUmusatpRpCGSOneQk2/l5czXANDSFvsc7VuOQ86s3ANhZetpwXNf1zY/zdfP63Xvjz325DAdAoES13g=="
+    },
+    "canvg": {
+      "version": "3.0.10",
+      "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
+      "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+      "optional": true,
+      "requires": {
+        "@babel/runtime": "^7.12.5",
+        "@types/raf": "^3.4.0",
+        "core-js": "^3.8.3",
+        "raf": "^3.4.1",
+        "regenerator-runtime": "^0.13.7",
+        "rgbcolor": "^1.0.1",
+        "stackblur-canvas": "^2.0.0",
+        "svg-pathdata": "^6.0.3"
+      },
+      "dependencies": {
+        "@babel/runtime": {
+          "version": "7.20.13",
+          "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+          "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+          "optional": true,
+          "requires": {
+            "regenerator-runtime": "^0.13.11"
+          }
+        },
+        "core-js": {
+          "version": "3.28.0",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.28.0.tgz",
+          "integrity": "sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==",
+          "optional": true
+        },
+        "regenerator-runtime": {
+          "version": "0.13.11",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+          "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+          "optional": true
+        }
+      }
     },
     "capture-exit": {
       "version": "2.0.0",
@@ -7025,6 +7075,12 @@
       "requires": {
         "domelementtype": "1"
       }
+    },
+    "dompurify": {
+      "version": "2.4.4",
+      "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.4.tgz",
+      "integrity": "sha512-1e2SpqHiRx4DPvmRuXU5J0di3iQACwJM+mFGE2HAkkK7Tbnfk9WcghcAmyWc9CRrjyRRUpmuhPUH6LphQQR3EQ==",
+      "optional": true
     },
     "domutils": {
       "version": "1.7.0",
@@ -9504,6 +9560,11 @@
       "version": "4.2.1",
       "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
       "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
+    },
+    "fflate": {
+      "version": "0.4.8",
+      "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
+      "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
     },
     "figgy-pudding": {
       "version": "3.5.1",
@@ -12699,6 +12760,42 @@
       "version": "0.0.0",
       "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
       "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
+    },
+    "jspdf": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
+      "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
+      "requires": {
+        "@babel/runtime": "^7.14.0",
+        "atob": "^2.1.2",
+        "btoa": "^1.2.1",
+        "canvg": "^3.0.6",
+        "core-js": "^3.6.0",
+        "dompurify": "^2.2.0",
+        "fflate": "^0.4.8",
+        "html2canvas": "^1.0.0-rc.5"
+      },
+      "dependencies": {
+        "@babel/runtime": {
+          "version": "7.20.13",
+          "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
+          "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+          "requires": {
+            "regenerator-runtime": "^0.13.11"
+          }
+        },
+        "core-js": {
+          "version": "3.28.0",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.28.0.tgz",
+          "integrity": "sha512-GiZn9D4Z/rSYvTeg1ljAIsEqFm0LaN9gVtwDCrKL80zHtS31p9BAjmTxVqTQDMpwlMolJZOFntUG2uwyj7DAqw==",
+          "optional": true
+        },
+        "regenerator-runtime": {
+          "version": "0.13.11",
+          "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+          "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
+        }
+      }
     },
     "jsprim": {
       "version": "1.4.1",
@@ -18887,6 +18984,12 @@
       "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
       "integrity": "sha1-QzdOLiyglosO8VI0YLfXMP8i7rM="
     },
+    "rgbcolor": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+      "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+      "optional": true
+    },
     "rimraf": {
       "version": "2.7.1",
       "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
@@ -19982,6 +20085,12 @@
       "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz",
       "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA=="
     },
+    "stackblur-canvas": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.5.0.tgz",
+      "integrity": "sha512-EeNzTVfj+1In7aSLPKDD03F/ly4RxEuF/EX0YcOG0cKoPXs+SLZxDawQbexQDBzwROs4VKLWTOaZQlZkGBFEIQ==",
+      "optional": true
+    },
     "stacktrace-parser": {
       "version": "0.1.10",
       "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.10.tgz",
@@ -20260,6 +20369,12 @@
       "resolved": "https://registry.npmjs.org/svg-parser/-/svg-parser-2.0.2.tgz",
       "integrity": "sha512-1gtApepKFweigFZj3sGO8KT8LvVZK8io146EzXrpVuWCDAbISz/yMucco3hWTkpZNoPabM+dnMOpy6Swue68Zg=="
     },
+    "svg-pathdata": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+      "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+      "optional": true
+    },
     "svgo": {
       "version": "1.3.0",
       "resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.0.tgz",
diff --git a/package.json b/package.json
index 5ae1493..2f95956 100644
--- a/package.json
+++ b/package.json
@@ -61,6 +61,7 @@
     "jest-watch-typeahead": "0.3.1",
     "js-table2excel": "^1.0.3",
     "jsbarcode": "^3.11.3",
+    "jspdf": "^2.5.1",
     "jssha": "^3.2.0",
     "jszip": "^3.10.0",
     "md5": "^2.2.1",
diff --git a/public/options.json b/public/options.json
index db18eef..58add2d 100644
--- a/public/options.json
+++ b/public/options.json
@@ -11,10 +11,10 @@
   "WXAppID": "wx4d8a34c8d4494872",
   "WXminiAppID": "",
   "nginx": "true",
-  "debugger": false,
+  "debugger": true,
   "licenseKey": "",
   "probation": "",
-  "transfer": "false",
+  "transfer": true,
   "keepPassword": "true",
   "platforms": ["H5", "wechat", "android", "ios", "wxMiniProgram"],
   "host": "http://dms-test.worx.cn",
diff --git a/src/api/cacheutils.js b/src/api/cacheutils.js
index 012223d..1c174d9 100644
--- a/src/api/cacheutils.js
+++ b/src/api/cacheutils.js
@@ -45,6 +45,10 @@
     } catch (e) {
       console.warn('WebSql 鍒濆鍖栧け璐ワ紒')
       window.GLOB.WebSql = null
+
+      if (window.indexedDB) {
+        this.openIndexDB(db)
+      }
     }
   }
 
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 630b514..6f5c18a 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -17,6 +17,17 @@
   }
 }
 
+.table-col-1, .table-col-2, .table-col-3, .table-col-4 {
+  .ant-table colgroup > col.ant-table-selection-col {
+    width: 40px!important;
+  }
+}
+.table-col-5, .table-col-6, .table-col-7 {
+  .ant-table colgroup > col.ant-table-selection-col {
+    width: 50px!important;
+  }
+}
+
 /* 璁剧疆iconfont鏍囩font-family */ 
 [class^="icon-"],[class*=" icon-"] {
   font-family: "iconfont";
@@ -315,6 +326,12 @@
     background: rgba(0, 0, 0, 0);
   }
 }
+.moveable-modal {
+  overflow-x: hidden!important;
+  .ant-modal-header {
+    cursor: move;
+  }
+}
 
 .ant-drawer {
   z-index: 1080!important;
@@ -488,4 +505,8 @@
   display: flex;
   flex: auto;
   min-height: 100%;
+}
+
+.component-wrap >.ant-col {
+  min-height: 0;
 }
\ No newline at end of file
diff --git a/src/assets/css/viewstyle.scss b/src/assets/css/viewstyle.scss
index e638889..198cd72 100644
--- a/src/assets/css/viewstyle.scss
+++ b/src/assets/css/viewstyle.scss
@@ -26,19 +26,6 @@
           }
         }
       }
-
-      .ant-tabs-nav .ant-tabs-tab-active {
-        color: $color6;
-      }
-      .ant-tabs-nav .ant-tabs-ink-bar {
-        background-color: $color6;
-      }
-      .ant-tabs-nav .ant-tabs-tab:active {
-        color: $color7;
-      }
-      .ant-tabs-nav .ant-tabs-tab:hover {
-        color: $color5;
-      }
     }
     >.mk-breadview-wrap {
       >.ant-breadcrumb {
@@ -205,6 +192,19 @@
     }
   }
 
+  .ant-tabs-nav .ant-tabs-tab-active {
+    color: $color6;
+  }
+  .ant-tabs-nav .ant-tabs-ink-bar {
+    background-color: $color6;
+  }
+  .ant-tabs-nav .ant-tabs-tab:active {
+    color: $color7;
+  }
+  .ant-tabs-nav .ant-tabs-tab:hover {
+    color: $color5;
+  }
+
   // 绯荤粺鏍峰紡淇敼
   .ant-select-dropdown-menu-item:hover:not(.ant-select-dropdown-menu-item-disabled) {
     background-color: $color1;
@@ -280,6 +280,11 @@
     .ant-pagination-next:hover .ant-pagination-item-link {
       color: $color6;
     }
+    .ant-pagination-options {
+      > div:not(:first-child) {
+        z-index: 1;
+      }
+    }
   }
   // 琛ㄦ牸鎺掑簭鍥炬爣
   .ant-table-thead > tr > th .ant-table-column-sorter .ant-table-column-sorter-inner .ant-table-column-sorter-up.on, .ant-table-thead > tr > th .ant-table-column-sorter .ant-table-column-sorter-inner .ant-table-column-sorter-down.on {
@@ -348,6 +353,12 @@
       background-color: $color6;
     }
   }
+  .ant-tree li .ant-tree-node-content-wrapper:hover {
+    background-color: $color1;
+  }
+  .ant-tree li .ant-tree-node-content-wrapper.ant-tree-node-selected {
+    background-color: $color2;
+  }
 }
 
 body.hidden-split-line #root { // 鍘婚櫎鐧诲綍椤靛垎鍓茬嚎
@@ -378,6 +389,9 @@
 body[class*='mk-blue-'] {
   --mk-sys-color: #1890ff;
   --mk-sys-color1: #e6f7ff;
+  --mk-sys-color2: #bae7ff;
+  --mk-sys-color3: #91d5ff;
+  --mk-sys-color4: #69c0ff;
   --mk-sys-color5: #40a9ff;
   @include viewstyle(#e6f7ff, #bae7ff, #91d5ff, #69c0ff, #40a9ff, #1890ff, #096dd9);
 }
@@ -385,6 +399,9 @@
 body[class*='mk-red-'] {
   --mk-sys-color: #f5222d;
   --mk-sys-color1: #fff1f0;
+  --mk-sys-color2: #ffccc7;
+  --mk-sys-color3: #ffa39e;
+  --mk-sys-color4: #ff7875;
   --mk-sys-color5: #ff4d4f;
   @include viewstyle(#fff1f0, #ffccc7, #ffa39e, #ff7875, #ff4d4f, #f5222d, #cf1322);
 }
@@ -392,6 +409,9 @@
 body[class*='mk-orange-red-'] {
   --mk-sys-color: #fa541c;
   --mk-sys-color1: #fff2e8;
+  --mk-sys-color2: #ffd8bf;
+  --mk-sys-color3: #ffbb96;
+  --mk-sys-color4: #ff9c6e;
   --mk-sys-color5: #ff7a45;
   @include viewstyle(#fff2e8, #ffd8bf, #ffbb96, #ff9c6e, #ff7a45, #fa541c, #d4380d);
 }
@@ -399,6 +419,9 @@
 body[class*='mk-orange-'] {
   --mk-sys-color: #fa8c16;
   --mk-sys-color1: #fff7e6;
+  --mk-sys-color2: #ffe7ba;
+  --mk-sys-color3: #ffd591;
+  --mk-sys-color4: #ffc069;
   --mk-sys-color5: #ffa940;
   @include viewstyle(#fff7e6, #ffe7ba, #ffd591, #ffc069, #ffa940, #fa8c16, #d46b08);
 }
@@ -406,6 +429,9 @@
 body[class*='mk-orange-yellow-'] {
   --mk-sys-color: #faad14;
   --mk-sys-color1: #fffbe6;
+  --mk-sys-color2: #fff1b8;
+  --mk-sys-color3: #ffe58f;
+  --mk-sys-color4: #ffd666;
   --mk-sys-color5: #ffc53d;
   @include viewstyle(#fffbe6, #fff1b8, #ffe58f, #ffd666, #ffc53d, #faad14, #d48806);
 }
@@ -413,6 +439,9 @@
 body[class*='mk-yellow-'] {
   --mk-sys-color: #fadb14;
   --mk-sys-color1: #feffe6;
+  --mk-sys-color2: #ffffb8;
+  --mk-sys-color3: #fffb8f;
+  --mk-sys-color4: #fff566;
   --mk-sys-color5: #ffec3d;
   @include viewstyle(#feffe6, #ffffb8, #fffb8f, #fff566, #ffec3d, #fadb14, #d4b106);
 }
@@ -420,6 +449,9 @@
 body[class*='mk-yellow-green-'] {
   --mk-sys-color: #a0d911;
   --mk-sys-color1: #fcffe6;
+  --mk-sys-color2: #f4ffb8;
+  --mk-sys-color3: #eaff8f;
+  --mk-sys-color4: #d3f261;
   --mk-sys-color5: #bae637;
   @include viewstyle(#fcffe6, #f4ffb8, #eaff8f, #d3f261, #bae637, #a0d911, #7cb305);
 }
@@ -427,6 +459,9 @@
 body[class*='mk-green-'] {
   --mk-sys-color: #52c41a;
   --mk-sys-color1: #f6ffed;
+  --mk-sys-color2: #d9f7be;
+  --mk-sys-color3: #b7eb8f;
+  --mk-sys-color4: #95de64;
   --mk-sys-color5: #73d13d;
   @include viewstyle(#f6ffed, #d9f7be, #b7eb8f, #95de64, #73d13d, #52c41a, #389e0d);
 }
@@ -434,6 +469,9 @@
 body[class*='mk-cyan-'] {
   --mk-sys-color: #13c2c2;
   --mk-sys-color1: #e6fffb;
+  --mk-sys-color2: #b5f5ec;
+  --mk-sys-color3: #87e8de;
+  --mk-sys-color4: #5cdbd3;
   --mk-sys-color5: #36cfc9;
   @include viewstyle(#e6fffb, #b5f5ec, #87e8de, #5cdbd3, #36cfc9, #13c2c2, #08979c);
 }
@@ -441,6 +479,9 @@
 body[class*='mk-blue-purple-'] {
   --mk-sys-color: #2f54eb;
   --mk-sys-color1: #f0f5ff;
+  --mk-sys-color2: #d6e4ff;
+  --mk-sys-color3: #adc6ff;
+  --mk-sys-color4: #85a5ff;
   --mk-sys-color5: #597ef7;
   @include viewstyle(#f0f5ff, #d6e4ff, #adc6ff, #85a5ff, #597ef7, #2f54eb, #1d39c4);
 }
@@ -448,6 +489,9 @@
 body[class*='mk-purple-'] {
   --mk-sys-color: #722ed1;
   --mk-sys-color1: #f9f0ff;
+  --mk-sys-color2: #efdbff;
+  --mk-sys-color3: #d3adf7;
+  --mk-sys-color4: #b37feb;
   --mk-sys-color5: #9254de;
   @include viewstyle(#f9f0ff, #efdbff, #d3adf7, #b37feb, #9254de, #722ed1, #531dab);
 }
@@ -455,6 +499,9 @@
 body[class*='mk-magenta-'] {
   --mk-sys-color: #eb2f96;
   --mk-sys-color1: #fff0f6;
+  --mk-sys-color2: #ffd6e7;
+  --mk-sys-color3: #ffadd2;
+  --mk-sys-color4: #ff85c0;
   --mk-sys-color5: #f759ab;
   @include viewstyle(#fff0f6, #ffd6e7, #ffadd2, #ff85c0, #f759ab, #eb2f96, #c41d7f);
 }
@@ -462,6 +509,9 @@
 body[class*='mk-grass-green-'] {
   --mk-sys-color: #aeb303;
   --mk-sys-color1: #f2efda;
+  --mk-sys-color2: #e6de97;
+  --mk-sys-color3: #d9d26c;
+  --mk-sys-color4: #ccc845;
   --mk-sys-color5: #bfbf22;
   @include viewstyle(#f2efda, #e6de97, #d9d26c, #ccc845, #bfbf22, #aeb303, #838c00);
 }
@@ -469,6 +519,9 @@
 body[class*='mk-deep-red-'] {
   --mk-sys-color: #c32539;
   --mk-sys-color1: #fff0f0;
+  --mk-sys-color2: #f5cbcb;
+  --mk-sys-color3: #e89b9e;
+  --mk-sys-color4: #db7077;
   --mk-sys-color5: #cf4856;
   @include viewstyle(#fff0f0, #f5cbcb, #e89b9e, #db7077, #cf4856, #c32539, #9c162c);
 }
@@ -476,6 +529,9 @@
 body[class*='mk-deep-blue-'] {
   --mk-sys-color: #1d3661;
   --mk-sys-color1: #eff1f4;
+  --mk-sys-color2: #e0e3e9;
+  --mk-sys-color3: #dbdfe6;
+  --mk-sys-color4: #c6cede;
   --mk-sys-color5: #394c6f;
   @include viewstyle(#eff1f4, #e0e3e9, #dbdfe6, #c6cede, #394c6f, #1d3661, #1d3661);
 }
\ No newline at end of file
diff --git a/src/assets/img/file-excel-fill.png b/src/assets/img/file-excel-fill.png
new file mode 100644
index 0000000..3f7f242
--- /dev/null
+++ b/src/assets/img/file-excel-fill.png
Binary files differ
diff --git a/src/assets/img/file-fill.png b/src/assets/img/file-fill.png
new file mode 100644
index 0000000..113b328
--- /dev/null
+++ b/src/assets/img/file-fill.png
Binary files differ
diff --git a/src/assets/img/file-pdf-fill.png b/src/assets/img/file-pdf-fill.png
new file mode 100644
index 0000000..054d2ca
--- /dev/null
+++ b/src/assets/img/file-pdf-fill.png
Binary files differ
diff --git a/src/assets/img/file-ppt-fill.png b/src/assets/img/file-ppt-fill.png
new file mode 100644
index 0000000..6b784ed
--- /dev/null
+++ b/src/assets/img/file-ppt-fill.png
Binary files differ
diff --git a/src/assets/img/file-word-fill.png b/src/assets/img/file-word-fill.png
new file mode 100644
index 0000000..37d9c52
--- /dev/null
+++ b/src/assets/img/file-word-fill.png
Binary files differ
diff --git a/src/assets/img/picture-fill.png b/src/assets/img/picture-fill.png
new file mode 100644
index 0000000..782d46b
--- /dev/null
+++ b/src/assets/img/picture-fill.png
Binary files differ
diff --git a/src/assets/img/rar.png b/src/assets/img/rar.png
new file mode 100644
index 0000000..830f5db
--- /dev/null
+++ b/src/assets/img/rar.png
Binary files differ
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index 7f2669a..cfbbe05 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -3,7 +3,6 @@
 import PropTypes from 'prop-types'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import moment from 'moment'
 import { Dropdown, Menu, Modal, notification, Switch, Input } from 'antd'
 import { SearchOutlined, DownOutlined, MenuFoldOutlined, MenuUnfoldOutlined } from '@ant-design/icons'
 
@@ -16,15 +15,13 @@
 import Api from '@/api'
 import MKEmitter from '@/utils/events.js'
 import options from '@/store/options.js'
-import zhCN from '@/locales/zh-CN/main.js'
-import enUS from '@/locales/en-US/main.js'
 import Utils from '@/utils/utils.js'
 import avatar from '@/assets/img/avatar.jpg'
 import './index.scss'
 
 const { confirm } = Modal
 const { Search } = Input
-const Resetpwd = asyncComponent(() => import('./resetpwd'))
+const Resetpwd = asyncComponent(() => import('@/components/resetPassword'))
 const LoginForm = asyncComponent(() => import('./loginform'))
 
 class Header extends Component {
@@ -33,9 +30,6 @@
   }
   state = {
     menulist: null, // 涓�绾ц彍鍗�
-    visible: false, // 淇敼瀵嗙爜妯℃�佹
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    confirmLoading: false,
     userName: '',
     fullName: '',
     logourl: window.GLOB.mainlogo,
@@ -57,60 +51,12 @@
 
   changePassword = () => {
     // 鐐瑰嚮淇敼瀵嗙爜锛屾樉绀哄脊绐�
-    this.setState({
-      visible: true
-    })
-  }
-
-  resetPwdSubmit = () => {
-    if (!this.formRef) return
-
-    this.formRef.handleConfirm().then(res => {
-      this.setState({
-        confirmLoading: true
-      })
-
-      let _param = {
-        func: 's_PwdUpt',
-        LText: `select '${res.originpwd}','${res.password}'`
-      }
-      
-      _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
-      _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
-      _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
-  
-      Api.getSystemConfig(_param).then(result => {
-        this.setState({
-          visible: !result.status,
-          confirmLoading: false
-        })
-
-        if (result.status) {
-          notification.success({
-            top: 92,
-            message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
-            duration: 2
-          })
-          setTimeout(() => {
-            sessionStorage.clear()
-            this.props.logout()
-            this.props.history.replace('/login')
-          }, 2000)
-        } else {
-          notification.warning({
-            top: 92,
-            message: result.message,
-            duration: 5
-          })
-        }
-      })
-    }, () => {})
-  }
-
-  handleCancel = () => {
-    // 鍙栨秷鏃跺叧闂慨鏀瑰瘑鐮佹ā鎬佹锛屾竻绌鸿〃鍗曟暟鎹�
-    this.setState({
-      visible: false
+    MKEmitter.emit('resetpassword', () => {
+      setTimeout(() => {
+        sessionStorage.clear()
+        this.props.logout()
+        this.props.history.replace('/login')
+      }, 2000)
     })
   }
 
@@ -118,8 +64,10 @@
     // 閫�鍑虹櫥褰�
     let _this = this
     confirm({
-      title: this.state.dict['main.logout.hint'],
+      title: '鎮ㄧ‘瀹氳閫�鍑哄悧?',
       content: '',
+      okText: '纭畾',
+      cancelText: '鍙栨秷',
       onOk() {
         sessionStorage.clear()
         _this.props.logout()
@@ -225,6 +173,8 @@
   getMenulist = (result) => {
     let thdMenuList = []
     let menulist = []
+    let names = new Map()
+    let doublenames = new Map()
     result.fst_menu && result.fst_menu.forEach(fst => {
       let fstItem = {
         MenuID: fst.MenuID,
@@ -268,6 +218,7 @@
                 ParentId: snd.MenuID,
                 MenuID: trd.MenuID,
                 MenuName: trd.MenuName,
+                menu_name: trd.MenuName,
                 ParentNames: [fst.MenuName, snd.MenuName],
                 MenuNo: trd.MenuNo,
                 EasyCode: trd.EasyCode,
@@ -296,6 +247,12 @@
 
               trdItem.OpenType = trdItem.OpenType.toLowerCase() // NewPage涓烘墦寮�澶栭儴椤甸潰鍦板潃
 
+              if (names.has(trdItem.menu_name)) {
+                doublenames.set(trdItem.menu_name, true)
+              } else {
+                names.set(trdItem.menu_name, true)
+              }
+
               thdMenuList.push(trdItem)
 
               return trdItem
@@ -309,6 +266,13 @@
       }
 
       menulist.push(fstItem)
+    })
+
+    thdMenuList = thdMenuList.map(item => {
+      if (doublenames.has(item.menu_name)) {
+        item.menu_name += '锛�' + item.ParentNames.join('-') + '锛�'
+      }
+      return item
     })
 
     return { menulist, thdMenuList }
@@ -594,23 +558,23 @@
     const menu = (
       <Menu className="header-dropdown">
         {debug && <Menu.Item key="switch">
-          {this.state.dict['main.edit']}
+          缂栬緫
           <Switch size="small" style={{marginLeft: '7px'}} checked={false} onChange={this.changeEditState} />
         </Menu.Item>}
-        <Menu.Item key="password" onClick={this.changePassword}>{this.state.dict['main.password']}</Menu.Item>
+        <Menu.Item key="password" onClick={this.changePassword}>淇敼瀵嗙爜</Menu.Item>
         {this.state.systems.length ? <Menu.SubMenu style={{minWidth: '110px'}} title="鍒囨崲绯荤粺">
           {this.state.systems.map((system, index) => (
             <Menu.Item style={{minWidth: '100px', lineHeight: '30px'}} key={'sub' + index} onClick={() => {this.changeSystem(system)}}> {system.AppName} </Menu.Item>
           ))}
         </Menu.SubMenu> : null}
-        <Menu.Item key="doc" onClick={this.gotoDoc}>{this.state.dict['main.doc']}</Menu.Item>
+        <Menu.Item key="doc" onClick={this.gotoDoc}>鏂囨。涓績</Menu.Item>
         <Menu.Item key="verup" onClick={this.verup}>
           椤甸潰鏇存柊
         </Menu.Item>
         {appVersion ? <Menu.Item key="version" onClick={this.about}>
           鍏充簬
         </Menu.Item> : null}
-        <Menu.Item key="logout" onClick={this.logout}>{this.state.dict['main.logout']}</Menu.Item>
+        <Menu.Item key="logout" onClick={this.logout}>閫�鍑�</Menu.Item>
       </Menu>
     )
 
@@ -740,12 +704,12 @@
                         option.MenuNo.toLowerCase().indexOf(searchkey.toLowerCase()) >= 0 ||
                         option.EasyCode.toLowerCase().indexOf(searchkey.toLowerCase()) >= 0
                       ) {
-                        return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.MenuName}</Menu.Item>
+                        return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.menu_name}</Menu.Item>
                       } else {
                         return null
                       }
                     }
-                    return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.MenuName}</Menu.Item>
+                    return <Menu.Item key={option.MenuID} onClick={() => this.changeVerMenu(option)}>{option.menu_name}</Menu.Item>
                   })}
                 </Menu>
               </div>
@@ -763,29 +727,20 @@
             </span>
           </div>
         </Dropdown>
-        {/* 淇敼瀵嗙爜 */}
-        <Modal
-          title={this.state.dict['main.password']}
-          visible={this.state.visible}
-          onOk={this.resetPwdSubmit}
-          confirmLoading={this.state.confirmLoading}
-          onCancel={this.handleCancel}
-          destroyOnClose
-        >
-          <Resetpwd dict={this.state.dict} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
-        </Modal>
         {/* 缂栬緫鐘舵�佺櫥褰� */}
         <Modal
-          title={this.state.dict['main.login.develop']}
+          title="鐧诲綍寮�鍙戞満"
           visible={this.state.loginVisible}
           onOk={this.loginSubmit}
           width={'430px'}
           confirmLoading={this.state.loginLoading}
           onCancel={() => {this.setState({ loginVisible: false, loginLoading: false })}}
           destroyOnClose
-        >
+          >
           <LoginForm handleSubmit={() => this.loginSubmit()} wrappedComponentRef={(inst) => this.loginRef = inst}/>
         </Modal>
+        {/* 淇敼瀵嗙爜 */}
+        <Resetpwd />
       </header>
     )
   }
diff --git a/src/components/header/resetpwd/index.jsx b/src/components/header/resetpwd/index.jsx
deleted file mode 100644
index f796811..0000000
--- a/src/components/header/resetpwd/index.jsx
+++ /dev/null
@@ -1,158 +0,0 @@
-import React, {Component} from 'react'
-import { Form, Input } from 'antd'
-
-class Resetpwd extends Component {
-  state = {
-    confirmDirty: false,
-    autoCompleteResult: [],
-    level: localStorage.getItem(window.location.href.split('#')[0] + 'pwdlevel') || ''
-  }
-
-  onEnterSubmit = (e) => {
-    // 琛ㄥ崟鍥炶溅鎻愪氦
-    if (e.key !== 'Enter') return
-    
-    if (!this.props.form.getFieldValue('originpwd')) {
-      this.focusInput('originpwd')
-    } else if (!this.props.form.getFieldValue('password')) {
-      this.focusInput('password')
-    } else if (!this.props.form.getFieldValue('confirm')) {
-      this.focusInput('confirm')
-    } else {
-      this.props.resetPwdSubmit()
-    }
-  }
-
-  focusInput = (selectId) => {
-    let _form = document.getElementById('reset-password-form')
-    let _inputs = _form.getElementsByTagName('input')
-    _inputs = [..._inputs]
-    _inputs.forEach(input => {
-      if (!input || input.id !== selectId) return
-
-      if (input.focus) {
-        input.focus()
-      }
-    })
-  }
-
-  handleConfirm = () => {
-    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
-    return new Promise((resolve, reject) => {
-      this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-          resolve(values)
-        } else {
-          reject(err)
-        }
-      })
-    })
-  }
-
-  handleConfirmBlur = e => {
-    const { value } = e.target
-    this.setState({ confirmDirty: this.state.confirmDirty || !!value })
-  }
-
-  compareToFirstPassword = (rule, value, callback) => {
-    const { form } = this.props
-    if (value && value !== form.getFieldValue('password')) {
-      callback('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷达紒')
-    } else {
-      callback()
-    }
-  }
-
-  validateToNextPassword = (rule, value, callback) => {
-    const { form } = this.props
-    const { level } = this.state
-
-    if (value && this.state.confirmDirty) {
-      form.validateFields(['confirm'], { force: true })
-    }
-
-    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
-      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛楀拰瀛楁瘝銆�')
-    } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
-      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛椼�佸瓧姣嶅拰鐗规畩瀛楃銆�')
-    } else {
-      callback()
-    }
-  }
-
-  render() {
-    const { getFieldDecorator } = this.props.form
-    const { level } = this.state
-
-    const formItemLayout = {
-      labelCol: {
-        xs: { span: 24 },
-        sm: { span: 8 }
-      },
-      wrapperCol: {
-        xs: { span: 24 },
-        sm: { span: 14 }
-      }
-    }
-
-    let rules = []
-    if (level) {
-      rules.push({
-        min: 8,
-        message: '瀵嗙爜闀垮害涓嶅彲灏忎簬8浣嶏紒'
-      })
-    }
-
-    return (
-      <Form {...formItemLayout} onKeyDown={this.onEnterSubmit} id="reset-password-form">
-        <Form.Item label="鍘熷瘑鐮�">
-          {getFieldDecorator('originpwd', {
-            rules: [
-              {
-                required: true,
-                message: '璇疯緭鍏ュ師瀵嗙爜锛�'
-              }
-            ]
-          })(<Input.Password autoFocus/>)}
-        </Form.Item>
-        <Form.Item label="鏂板瘑鐮�" hasFeedback>
-          {getFieldDecorator('password', {
-            rules: [
-              {
-                required: true,
-                message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
-              },
-              {
-                pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
-                message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
-              },
-              ...rules,
-              {
-                max: 50,
-                message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
-              },
-              {
-                validator: this.validateToNextPassword
-              }
-            ]
-          })(<Input.Password />)}
-        </Form.Item>
-        <Form.Item label="纭瀵嗙爜" hasFeedback>
-          {getFieldDecorator('confirm', {
-            rules: [
-              {
-                required: true,
-                message: '璇风‘璁ゅ瘑鐮侊紒'
-              },
-              {
-                validator: this.compareToFirstPassword
-              }
-            ]
-          })(<Input.Password onBlur={this.handleConfirmBlur} />)}
-        </Form.Item>
-      </Form>
-    )
-  }
-}
-
-export default Form.create()(Resetpwd)
\ No newline at end of file
diff --git a/src/components/paste/index.jsx b/src/components/paste/index.jsx
index 7fc8904..bf998d5 100644
--- a/src/components/paste/index.jsx
+++ b/src/components/paste/index.jsx
@@ -17,10 +17,6 @@
     visible: false
   }
 
-  handleMenuClick = () => {
-    this.setState({visible: true})
-  }
-
   pasteSubmit = () => {
     const { options } = this.props
     this.pasteFormRef.handleConfirm().then(res => {
diff --git a/src/components/qrcode/index.jsx b/src/components/qrcode/index.jsx
index 0fbc0cc..7fdc4fa 100644
--- a/src/components/qrcode/index.jsx
+++ b/src/components/qrcode/index.jsx
@@ -5,7 +5,7 @@
 
 import './index.scss'
 
-class BarCode extends Component {
+class MkQrCode extends Component {
   static propTpyes = {
     card: PropTypes.object,  // 鏉$爜璁剧疆
     value: PropTypes.any,    // 鏉$爜鍊�
@@ -55,4 +55,4 @@
   }
 }
 
-export default BarCode
\ No newline at end of file
+export default MkQrCode
\ No newline at end of file
diff --git a/src/components/resetPassword/index.jsx b/src/components/resetPassword/index.jsx
new file mode 100644
index 0000000..a72283a
--- /dev/null
+++ b/src/components/resetPassword/index.jsx
@@ -0,0 +1,182 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Modal, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import Resetpwd from './resetpwd'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class ResetPassword extends Component {
+  state = {
+    visible: false,
+    loading: false,
+    type: 'account',
+    okText: '纭畾',
+    smsId: '',
+    mob: '',
+    code: ''
+  }
+
+  callback = null
+
+  componentDidMount() {
+    MKEmitter.addListener('resetpassword', this.resetpassword)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+  
+  componentWillUnmount() {
+    MKEmitter.removeListener('resetpassword', this.resetpassword)
+  }
+
+  resetpassword = (callback) => {
+    this.callback = callback
+    this.setState({
+      visible: true,
+      loading: false,
+      type: 'account',
+      okText: '纭畾',
+      mob: '',
+      code: '',
+      smsId: sessionStorage.getItem('mk_sms_id') || ''
+    })
+  }
+
+  resetPwdSubmit = () => {
+    const { type } = this.state
+
+    if (type === 'account') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          loading: true
+        })
+  
+        let _param = {
+          func: 's_PwdUpt',
+          LText: `select '${res.originpwd}','${res.password}'`
+        }
+        
+        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
+        _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
+        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
+    
+        Api.getSystemConfig(_param).then(result => {
+          if (result.status) {
+            this.setState({
+              visible: false,
+              loading: false
+            })
+            notification.success({
+              top: 92,
+              message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
+              duration: 2
+            })
+            this.callback && this.callback()
+          } else {
+            this.setState({
+              loading: false
+            })
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+        })
+      }, () => {})
+    } else if (type === 'mob') {
+      this.formRef.handleConfirm().then(res => {
+        if (!/^1[3456789]\d{9}$/.test(res.phone)) {
+          notification.warning({
+            top: 92,
+            message: '鎵嬫満鍙锋牸寮忛敊璇紝璇烽噸濉紒',
+            duration: 5
+          })
+          return
+        }
+
+        this.setState({
+          mob: res.phone,
+          type: 'code'
+        })
+      }, () => {})
+    } else if (type === 'code') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          code: res.vercode,
+          type: 'phonepwd',
+          okText: '纭畾'
+        })
+      }, () => {})
+    } else if (type === 'phonepwd') {
+      this.formRef.handleConfirm().then(res => {
+        this.setState({
+          loading: true
+        })
+  
+        let _param = {
+          func: 's_PwdUpt',
+          LText: `select '','${res.password}'`,
+          mob: this.state.mob,
+          check_code: this.state.code
+        }
+        
+        _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
+        _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
+        _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
+    
+        Api.getSystemConfig(_param).then(result => {
+          if (result.status) {
+            this.setState({
+              visible: false,
+              loading: false
+            })
+            notification.success({
+              top: 92,
+              message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
+              duration: 2
+            })
+            this.callback && this.callback()
+          } else {
+            this.setState({
+              loading: false
+            })
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+        })
+      }, () => {})
+    }
+  }
+
+  render() {
+    const { visible, loading, okText, type, mob, smsId } = this.state
+
+    return (
+      <Modal
+        title="淇敼瀵嗙爜"
+        wrapClassName="reset-password-modal"
+        visible={visible}
+        maskClosable={false}
+        onOk={this.resetPwdSubmit}
+        onCancel={() => { this.setState({ visible: false })}}
+        okText={okText}
+        confirmLoading={loading}
+        destroyOnClose
+      >
+        <Resetpwd type={type} mob={mob} smsId={smsId} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
+        {type === 'account' && smsId ? <div className="forget-pwd"><span onClick={() => this.setState({type: 'mob', okText: '涓嬩竴姝�'})}>蹇樿瀵嗙爜锛�</span></div> : null}
+      </Modal>
+    )
+  }
+}
+
+export default ResetPassword
\ No newline at end of file
diff --git a/src/components/resetPassword/index.scss b/src/components/resetPassword/index.scss
new file mode 100644
index 0000000..f943fa2
--- /dev/null
+++ b/src/components/resetPassword/index.scss
@@ -0,0 +1,22 @@
+.reset-password-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 150px;
+
+    .forget-pwd {
+      text-align: right;
+      padding-right: 40px;
+      color: #1890ff;
+      span {
+        cursor: pointer;
+      }
+    }
+    .vercode-line {
+      .ant-form-item-control-wrapper {
+        margin-left: 8.3%;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/components/resetPassword/resetpwd/index.jsx b/src/components/resetPassword/resetpwd/index.jsx
new file mode 100644
index 0000000..ee7a60a
--- /dev/null
+++ b/src/components/resetPassword/resetpwd/index.jsx
@@ -0,0 +1,317 @@
+import React, {Component} from 'react'
+import { Form, Input, Button, message } from 'antd'
+import moment from 'moment'
+import md5 from 'md5'
+
+import Api from '@/api'
+
+class Resetpwd extends Component {
+  state = {
+    confirmDirty: false,
+    autoCompleteResult: [],
+    level: localStorage.getItem(window.location.href.split('#')[0] + 'pwdlevel') || ''
+  }
+
+  LoginTimer = null
+
+  onEnterSubmit = (e) => {
+    // 琛ㄥ崟鍥炶溅鎻愪氦
+    if (e.key !== 'Enter') return
+    
+    if (!this.props.form.getFieldValue('originpwd')) {
+      this.focusInput('originpwd')
+    } else if (!this.props.form.getFieldValue('password')) {
+      this.focusInput('password')
+    } else if (!this.props.form.getFieldValue('confirm')) {
+      this.focusInput('confirm')
+    } else {
+      this.props.resetPwdSubmit()
+    }
+  }
+
+  focusInput = (selectId) => {
+    let _form = document.getElementById('reset-password-form')
+    let _inputs = _form.getElementsByTagName('input')
+    _inputs = [..._inputs]
+    _inputs.forEach(input => {
+      if (!input || input.id !== selectId) return
+
+      if (input.focus) {
+        input.focus()
+      }
+    })
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleConfirmBlur = e => {
+    const { value } = e.target
+    this.setState({ confirmDirty: this.state.confirmDirty || !!value })
+  }
+
+  compareToFirstPassword = (rule, value, callback) => {
+    const { form } = this.props
+    if (value && value !== form.getFieldValue('password')) {
+      callback('涓ゆ杈撳叆瀵嗙爜涓嶄竴鑷达紒')
+    } else {
+      callback()
+    }
+  }
+
+  validateToNextPassword = (rule, value, callback) => {
+    const { form } = this.props
+    const { level } = this.state
+
+    if (value && this.state.confirmDirty) {
+      form.validateFields(['confirm'], { force: true })
+    }
+
+    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
+      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛楀拰瀛楁瘝銆�')
+    } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
+      callback('瀵嗙爜涓繀椤诲惈鏈夋暟瀛椼�佸瓧姣嶅拰鐗规畩瀛楃銆�')
+    } else {
+      callback()
+    }
+  }
+
+  getvercode = () => {
+    const { mob, smsId } = this.props
+
+    let _param = {
+      func: 'mes_sms_send_code_sso',
+      send_type: 'reset_pwd',
+      mob: mob,
+      ID: smsId
+    }
+    _param.LText = 'minke'
+    _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    _param.secretkey = md5(`${_param.LText}mingke${_param.timestamp}`)
+    
+    _param.userid = sessionStorage.getItem('visitorUserID') || ''
+    _param.LoginUID = sessionStorage.getItem('visitorLoginUID') || ''
+
+    Api.getSystemConfig(_param).then(res => {
+      if (!res.status || !res.n_id) {
+        message.warning(res.message || '楠岃瘉鐮佽幏鍙栧け璐ワ紒')
+        return
+      }
+
+      let param = {
+        func: 'MSN_sms_send_code',
+        send_type: 'reset_pwd',
+        mob: mob,
+        timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+        ID: smsId,
+        n_id: res.n_id
+      }
+  
+      param.LText = md5(`${mob}mingke${window.GLOB.appkey}${param.timestamp}`)
+      param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
+
+      param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
+      param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+      param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+  
+      this.setState({
+        verdisabled: true,
+        delay: 60
+      })
+
+      this.LoginTimer = setTimeout(this.resetVerCodeDelay, 1000)
+  
+      Api.genericInterface(param).then(res => {
+        if (res.status) {
+  
+        } else {
+          clearTimeout(this.LoginTimer)
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+          message.warning(res.message)
+        }
+      }, () => {
+        clearTimeout(this.LoginTimer)
+        this.setState({
+          verdisabled: false,
+          delay: null
+        })
+      })
+    })
+  }
+
+  resetVerCodeDelay = () => {
+    const { delay } = this.state
+    if (delay && delay > 1) {
+      this.setState({delay: delay - 1})
+      this.LoginTimer = setTimeout(this.resetVerCodeDelay, 1000)
+    } else {
+      this.setState({
+        verdisabled: false,
+        delay: null
+      })
+    }
+  }
+
+  render() {
+    const { type } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { level, delay, verdisabled } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    let rules = []
+    if (level) {
+      rules.push({
+        min: 8,
+        message: '瀵嗙爜闀垮害涓嶅彲灏忎簬8浣嶏紒'
+      })
+    }
+
+    return (
+      <>
+        {type === 'account' ? <Form {...formItemLayout} onKeyDown={this.onEnterSubmit} id="reset-password-form">
+          <Form.Item label="鍘熷瘑鐮�">
+            {getFieldDecorator('originpwd', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ュ師瀵嗙爜锛�'
+                }
+              ]
+            })(<Input.Password autoFocus/>)}
+          </Form.Item>
+          <Form.Item label="鏂板瘑鐮�" hasFeedback>
+            {getFieldDecorator('password', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
+                },
+                {
+                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
+                  message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
+                },
+                ...rules,
+                {
+                  max: 50,
+                  message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
+                },
+                {
+                  validator: this.validateToNextPassword
+                }
+              ]
+            })(<Input.Password />)}
+          </Form.Item>
+          <Form.Item label="纭瀵嗙爜" hasFeedback>
+            {getFieldDecorator('confirm', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇风‘璁ゅ瘑鐮侊紒'
+                },
+                {
+                  validator: this.compareToFirstPassword
+                }
+              ]
+            })(<Input.Password onBlur={this.handleConfirmBlur} />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'phonepwd' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item label="鏂板瘑鐮�" hasFeedback>
+            {getFieldDecorator('password', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ柊瀵嗙爜锛�'
+                },
+                {
+                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
+                  message: '瀵嗙爜鍙厑璁稿寘鍚暟瀛椼�佸瓧姣嶄互鍙�!@#$%&*()_銆�'
+                },
+                ...rules,
+                {
+                  max: 50,
+                  message: '鏈�澶у瘑鐮侀暱搴︿负50浣嶏紒'
+                },
+                {
+                  validator: this.validateToNextPassword
+                }
+              ]
+            })(<Input.Password />)}
+          </Form.Item>
+          <Form.Item label="纭瀵嗙爜" hasFeedback>
+            {getFieldDecorator('confirm', {
+              rules: [
+                {
+                  required: true,
+                  message: '璇风‘璁ゅ瘑鐮侊紒'
+                },
+                {
+                  validator: this.compareToFirstPassword
+                }
+              ]
+            })(<Input.Password onBlur={this.handleConfirmBlur} />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'mob' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item label="鎵嬫満鍙�">
+            {getFieldDecorator('phone', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ墜鏈哄彿锛�'
+                }
+              ]
+            })(<Input placeholder="璇疯緭鍏ユ墜鏈哄彿" autoComplete="off" />)}
+          </Form.Item>
+        </Form> : null}
+        {type === 'code' ? <Form wrapperCol={{ xs: { span: 24 }, sm: { span: 20 }}} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
+          <Form.Item className="vercode-line" label="">
+            {getFieldDecorator('vercode', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ラ獙璇佺爜锛�'
+                }
+              ]
+            })(<Input
+              addonAfter={
+                <Button type="link" size="small" disabled={verdisabled} onClick={this.getvercode}>
+                  {delay ? `${delay}s鍚庨噸鏂拌幏鍙朻 : '鑾峰彇楠岃瘉鐮�'}
+                </Button>
+              }
+              placeholder="璇疯緭鍏ラ獙璇佺爜"
+              autoComplete="off"
+            />)}
+          </Form.Item>
+        </Form> : null}
+      </>
+    )
+  }
+}
+
+export default Form.create()(Resetpwd)
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
index bf9a423..f7ee9b8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -133,7 +133,10 @@
 
       GLOB.mainSystemApi = 'https://cloud.positecgroup.com/webapi/dostars'
 
-      // GLOB.mainSystemApi = 'http://sso.mk9h.cn/cloud/webapi/dostars'
+      // GLOB.mainSystemApi = 'https://sso.mk9h.cn/cloud/webapi/dostars'
+      // if (!/^https/.test(window.location.protocol)) { // https杞崲
+      //   GLOB.mainSystemApi = 'http://sso.mk9h.cn/cloud/webapi/dostars'
+      // }
 
       if (GLOB.watermark) {
         GLOB.dataFormat = true
@@ -213,6 +216,11 @@
       } catch (e) {
         console.warn('Parse Failure')
       }
+    }
+
+    // 涓嶄娇鐢ㄧ櫨鍙剁獥鎵撳紑鑿滃崟鏃讹紝鍘绘帀鍚堝苟鏍囪
+    if (GLOB.navBar !== 'shutter') {
+      localStorage.removeItem('collapse')
     }
 
     document.body.className = className
@@ -310,6 +318,7 @@
     })
 
     window.GLOB.CacheMap = new Map()     // 缂撳瓨閰嶇疆淇℃伅
+    window.GLOB.CacheVoucher = new Map() // 缂撳瓨鍑瘉淇℃伅
     window.GLOB.UserCacheMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夎缃�
     window.GLOB.CacheData = new Map()    // 瀛樺偍閫変腑鏁版嵁
 
diff --git a/src/locales/en-US/login.js b/src/locales/en-US/login.js
index f2df2c1..9abd3b6 100644
--- a/src/locales/en-US/login.js
+++ b/src/locales/en-US/login.js
@@ -8,8 +8,6 @@
   'login.phone.empty': 'Please enter your cell phone number!',
   'login.vercode': 'Verification code',
   'login.vercode.empty': 'Please enter your verification code!',
-  'login.vercode.query': 'Get verify code',
-  'login.vercode.queryagain': 'Obtain again after @s',
   'login.password': 'Password',
   'login.password.empty': 'Please input your Password!',
   'login.remember': 'Remember me',
diff --git a/src/locales/en-US/main.js b/src/locales/en-US/main.js
index 2a9103e..1b18f24 100644
--- a/src/locales/en-US/main.js
+++ b/src/locales/en-US/main.js
@@ -1,17 +1,11 @@
 export default {
   'main.search': 'Search',
   'main.reset': 'Reset',
-  'main.edit': 'Edit',
   'main.confirm': 'OK',
   'main.submit': 'Submit',
   'main.return': 'Return',
   'main.close': 'Close',
   'main.cancel': 'Cancel',
-  'main.logout': 'Logout',
-  'main.doc': '鏂囨。涓績',
-  'main.logout.hint': 'Are you sure you want to log out?',
-  'main.password': 'Change the password',
-  'main.login.develop': 'Login developer',
   'main.revert.default': 'Restore default Settings',
   'main.copy.success': 'Copy success',
   'main.pagination.of': 'of',
diff --git a/src/locales/zh-CN/login.js b/src/locales/zh-CN/login.js
index 321aa63..ea06d7a 100644
--- a/src/locales/zh-CN/login.js
+++ b/src/locales/zh-CN/login.js
@@ -8,8 +8,6 @@
   'login.phone.empty': '璇疯緭鍏ユ墜鏈哄彿!',
   'login.vercode': '楠岃瘉鐮�',
   'login.vercode.empty': '璇疯緭鍏ラ獙璇佺爜!',
-  'login.vercode.query': '鑾峰彇楠岃瘉鐮�',
-  'login.vercode.queryagain': '@s鍚庨噸鏂拌幏鍙�',
   'login.password': '瀵嗙爜',
   'login.password.empty': '璇疯緭鍏ュ瘑鐮�!',
   'login.remember': '璁颁綇瀵嗙爜',
diff --git a/src/locales/zh-CN/main.js b/src/locales/zh-CN/main.js
index db616d0..cf33d24 100644
--- a/src/locales/zh-CN/main.js
+++ b/src/locales/zh-CN/main.js
@@ -1,17 +1,11 @@
 export default {
   'main.search': '鎼滅储',
   'main.reset': '閲嶇疆',
-  'main.edit': '缂栬緫',
   'main.confirm': '纭畾',
   'main.submit': '鎻愪氦',
   'main.return': '杩斿洖',
   'main.close': '鍏抽棴',
   'main.cancel': '鍙栨秷',
-  'main.logout': '閫�鍑�',
-  'main.doc': '鏂囨。涓績',
-  'main.logout.hint': '鎮ㄧ‘瀹氳閫�鍑哄悧?',
-  'main.password': '淇敼瀵嗙爜',
-  'main.login.develop': '鐧诲綍寮�鍙戞満',
   'main.revert.default': '鎭㈠榛樿璁剧疆',
   'main.copy.success': '澶嶅埗鎴愬姛',
   'main.pagination.of': '鍏�',
diff --git a/src/menu/components/card/balcony/index.jsx b/src/menu/components/card/balcony/index.jsx
index 4c89067..d495918 100644
--- a/src/menu/components/card/balcony/index.jsx
+++ b/src/menu/components/card/balcony/index.jsx
@@ -1,8 +1,8 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Checkbox } from 'antd'
-import { PlusOutlined, PlusSquareOutlined, EditOutlined, FontColorsOutlined, DeleteOutlined, SettingOutlined, ToolOutlined, ClockCircleOutlined } from '@ant-design/icons'
+import { Popover, Checkbox, message } from 'antd'
+import { PlusOutlined, PlusSquareOutlined, EditOutlined, FontColorsOutlined, DeleteOutlined, SettingOutlined, ToolOutlined, ClockCircleOutlined, ColumnHeightOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -191,7 +191,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -245,9 +245,19 @@
   }
 
   getWrapForms = () => {
-    const { wrap } = this.state.card
+    const { card } = this.state
 
-    return getWrapForm(wrap)
+    let buttons = []
+    card.elements && card.elements.forEach(item => {
+      if (item.eleType === 'button') {
+        buttons.push({
+          value: item.uuid,
+          label: item.label
+        })
+      }
+    })
+
+    return getWrapForm(card.wrap, buttons, card.columns)
   }
 
   updateWrap = (res) => {
@@ -275,6 +285,7 @@
 
     return (
       <div className="menu-balcony-edit-box" style={_style} id={card.uuid}>
+        {card.style.height ? <ColumnHeightOutlined className="fixed-height" title="瀹氶珮" /> : null}
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <PlusOutlined className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} />
@@ -297,7 +308,15 @@
         <CardCellComponent cards={card} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/balcony/index.scss b/src/menu/components/card/balcony/index.scss
index 6d5f095..3aaefbb 100644
--- a/src/menu/components/card/balcony/index.scss
+++ b/src/menu/components/card/balcony/index.scss
@@ -47,6 +47,13 @@
     right: -30px;
     font-size: 16px;
   }
+  .fixed-height {
+    position: absolute;
+    bottom: 3px;
+    right: 3px;
+    font-size: 10px;
+    color: orange;
+  }
 }
 .menu-balcony-edit-box::after {
   display: block;
diff --git a/src/menu/components/card/balcony/options.jsx b/src/menu/components/card/balcony/options.jsx
index 86b84f5..4cce86c 100644
--- a/src/menu/components/card/balcony/options.jsx
+++ b/src/menu/components/card/balcony/options.jsx
@@ -4,7 +4,7 @@
 /**
  * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
  */
-export default function (wrap) {
+export default function (wrap, buttons, columns) {
   let menu = window.GLOB.customMenu
 
   let modules = MenuUtils.getLinkModules(menu.components) || []
@@ -69,6 +69,7 @@
       controlFields: [
         {field: 'empty', values: ['dynamic']},
         {field: 'publicId', values: ['public']},
+        {field: 'bgField', values: ['dynamic', 'public']},
       ]
     },
     {
@@ -248,6 +249,15 @@
       ],
     },
     {
+      type: 'select',
+      field: 'bgField',
+      label: '鑳屾櫙鍥�',
+      initval: wrap.bgField || '',
+      tooltip: '鍔ㄦ�佽儗鏅紝鑳屾櫙鍥剧墖鐢卞瓧娈靛�兼帶鍒躲�傝娉ㄦ剰璋冩暣鑳屾櫙鏍峰紡銆�',
+      required: false,
+      options: columns
+    },
+    {
       type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
@@ -260,6 +270,14 @@
       forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
     },
     {
+      type: 'select',
+      field: 'linkbtn',
+      label: '鍏宠仈鎸夐挳',
+      initval: wrap.linkbtn || '',
+      required: false,
+      options: buttons
+    },
+    {
       type: 'multiselect',
       field: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
index 6418290..5b2b78c 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -1,7 +1,7 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
 import { Popover, Button, Switch, Checkbox } from 'antd'
-import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined, ProfileOutlined, WarningOutlined } from '@ant-design/icons'
+import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined, ProfileOutlined, WarningOutlined, PlusOutlined, MinusOutlined } from '@ant-design/icons'
 
 import { resetStyle } from '@/utils/utils-custom.js'
 import MkIcon from '@/components/mk-icon'
@@ -53,6 +53,8 @@
   if (card.OpenType === 'form') {
     if (card.formType === 'switch') {
       btnElement = (<Switch style={_style} className={card.size === 'large' ? 'ant-switch-large' : ''} size={card.size} checkedChildren={card.openText || ''} unCheckedChildren={card.closeText || ''}/>)
+    } else if (card.formType === 'counter') {
+      btnElement = (<div style={_style} className={'mk-counter ' + card.size}><span><MinusOutlined /></span><span>1</span><span><PlusOutlined /></span></div>)
     } else if (card.formType === 'radio') {
       btnElement = (<Checkbox style={_style}></Checkbox>)
     } else {
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 197c671..8069bcf 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -101,32 +101,29 @@
       //   </div>
       // )
     } else if (card.eleType === 'picture') {
-      let _imagestyle = {}
+      let _imagestyle = {
+        backgroundSize: card.style.backgroundSize || 'cover',
+        backgroundPosition: card.style.backgroundPosition || 'center',
+        backgroundRepeat: card.style.backgroundRepeat || 'no-repeat',
+        borderRadius: card.style.borderRadius || 0
+      }
       let url = card.url !== '@icon@' ? card.url : sessionStorage.getItem('CloudAvatar')
 
       if (url) {
         url = url.replace(/@mywebsite@\//ig, window.GLOB.baseurl)
-        _imagestyle = {backgroundImage: `url('${url}')`}
+        _imagestyle.backgroundImage = `url('${url}')`
       } else {
         let index = card.uuid.match(/\d{1}/g)
         index = index.slice(-1)[0] % 5
         let demos = [demo1, demo2, demo3, demo4, demo5]
 
-        _imagestyle = {backgroundImage: `url('${demos[index]}')`}
-      }
-
-      if (card.style && card.style.borderRadius) {
-        _imagestyle.borderRadius = card.style.borderRadius
+        _imagestyle.backgroundImage = `url('${demos[index]}')`
       }
 
       if (PicRadio[card.lenWidRadio]) {
         _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
       } else {
         _imagestyle.paddingTop = '100%'
-      }
-
-      if (card.backgroundSize) {
-        _imagestyle.backgroundSize = card.backgroundSize
       }
 
       return (
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.scss b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
index aade5ba..3d44552 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.scss
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -118,6 +118,7 @@
   .ant-mk-icon {
     vertical-align: top;
     line-height: inherit;
+    color: inherit;
   }
   .ant-switch-large {
     min-width: 60px;
@@ -141,6 +142,73 @@
     height: 26px;
   }
 
+  .mk-counter {
+    display: inline-block;
+    white-space: nowrap;
+    border: 1px solid #d9d9d9;
+    font-size: 14px;
+    border-radius: 2px;
+    background: #ffffff;
+    span {
+      display: inline-block;
+      height: 20px;
+      line-height: 22px;
+      vertical-align: top;
+      text-align: center;
+    }
+    span:first-child {
+      width: 22px;
+      text-align: center;
+      font-size: 12px;
+      border-right: 1px solid #d9d9d9;
+    }
+    span:nth-child(2) {
+      width: 42px;
+    }
+    span:last-child {
+      width: 22px;
+      text-align: center;
+      font-size: 12px;
+      border-left: 1px solid #d9d9d9;
+    }
+  }
+  .mk-counter.small {
+    font-size: 12px;
+    span {
+      height: 18px;
+      line-height: 19px;
+    }
+    span:first-child {
+      width: 20px;
+      font-size: 10px;
+    }
+    span:nth-child(2) {
+      width: 38px;
+    }
+    span:last-child {
+      width: 20px;
+      font-size: 10px;
+    }
+  }
+  .mk-counter.large {
+    font-size: 16px;
+    span {
+      height: 24px;
+      line-height: 25px;
+    }
+    span:first-child {
+      width: 26px;
+      font-size: 13px;
+    }
+    span:nth-child(2) {
+      width: 48px;
+    }
+    span:last-child {
+      width: 26px;
+      font-size: 13px;
+    }
+  }
+
   .card-cell > div {
     background-position: center center;
     background-repeat: no-repeat;
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index cb4f601..009826c 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -17,7 +17,7 @@
   sequence: ['eleType', 'width'],
   text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix', 'link', 'anchors', 'noValue', 'bgImage', 'fixStyle', 'copyable'],
   number: ['eleType', 'datatype', 'width', 'height', 'prefix', 'postfix', 'noValue', 'fixStyle'],
-  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'backgroundSize', 'maxWidth', 'link', 'noValue'],
+  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'maxWidth', 'link', 'noValue'],
   video: ['eleType', 'datatype', 'width', 'aspectRatio', 'autoPlay', 'loop', 'startTime', 'noValue', 'posterType'],
   icon: ['eleType', 'datatype', 'width', 'tooltip'],
   slider: ['eleType', 'datatype', 'width', 'color', 'maxValue', 'showInfo', 'showType', 'strokeWidth', 'strokeLinecap', 'trailColor'],
@@ -48,7 +48,7 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { card, config } = this.props
+    const { card, config, side } = this.props
     let _options = this.getOptions(card.eleType, card.datatype, card.link, (card.showType || 'line'), card.showInfo, card.fixStyle || '', card.posterType || '')
     
     this.setState({
@@ -64,20 +64,38 @@
 
         if (item.key === 'field' || item.key === 'linkurl' || item.key === 'bgImage' || item.key === 'posterField') {
           item.options = []
-          config.columns.forEach(col => {
-            let label = `${col.field}锛�${col.label}锛塦
-            if (/^(Int|Decimal)/ig.test(col.datatype) && (card.eleType === 'number' || card.eleType === 'slider')) {
-              item.options.push({
-                value: col.field,
-                text: label
-              })
-            } else if (/^(Nvarchar|date)/ig.test(col.datatype) && card.eleType !== 'number' && card.eleType !== 'slider') {
-              item.options.push({
-                value: col.field,
-                text: label
-              })
-            }
-          })
+          
+          if (side === 'sub') {
+            config.subColumns.forEach(col => {
+              let label = `${col.field}锛�${col.label}锛塦
+              if (/^(Int|Decimal)/ig.test(col.datatype) && (card.eleType === 'number' || card.eleType === 'slider')) {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              } else if (/^(Nvarchar|date)/ig.test(col.datatype) && card.eleType !== 'number' && card.eleType !== 'slider') {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              }
+            })
+          } else {
+            config.columns.forEach(col => {
+              let label = `${col.field}锛�${col.label}锛塦
+              if (/^(Int|Decimal)/ig.test(col.datatype) && (card.eleType === 'number' || card.eleType === 'slider')) {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              } else if (/^(Nvarchar|date)/ig.test(col.datatype) && card.eleType !== 'number' && card.eleType !== 'slider') {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              }
+            })
+          }
         } else if (item.key === 'value' && card.eleType === 'slider') {
           item.type = 'number'
           item.label = '鍊�'
@@ -140,7 +158,7 @@
       }
     } else if (eleType === 'icon') {
       if (datatype === 'dynamic') {
-        _options.push('field')
+        _options.push('field', 'noValue')
       } else {
         _options.push('icon')
       }
@@ -159,7 +177,7 @@
    * 3銆佸垏鎹㈡爣绛剧被鍨嬶紝閲嶇疆鍙�夋爣绛�
    */
   selectChange = (key, value, option) => {
-    const { card, config } = this.props
+    const { card, config, side } = this.props
     const { datatype, eleType, showType, showInfo, fixStyle, posterType } = this.state
 
     if (key === 'eleType') {
@@ -170,21 +188,39 @@
 
         if (item.key === 'field') {
           item.options = []
-          config.columns.forEach(col => {
-            let label = `${col.field}锛�${col.label}锛塦
 
-            if (/^(Int|Decimal)/ig.test(col.datatype) && (value === 'number' || value === 'slider')) {
-              item.options.push({
-                value: col.field,
-                text: label
-              })
-            } else if (/^(Nvarchar|date)/ig.test(col.datatype) && value !== 'number' && value !== 'slider') {
-              item.options.push({
-                value: col.field,
-                text: label
-              })
-            }
-          })
+          if (side === 'sub') {
+            config.subColumns.forEach(col => {
+              let label = `${col.field}锛�${col.label}锛塦
+              if (/^(Int|Decimal)/ig.test(col.datatype) && (value === 'number' || value === 'slider')) {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              } else if (/^(Nvarchar|date)/ig.test(col.datatype) && value !== 'number' && value !== 'slider') {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              }
+            })
+          } else {
+            config.columns.forEach(col => {
+              let label = `${col.field}锛�${col.label}锛塦
+  
+              if (/^(Int|Decimal)/ig.test(col.datatype) && (value === 'number' || value === 'slider')) {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              } else if (/^(Nvarchar|date)/ig.test(col.datatype) && value !== 'number' && value !== 'slider') {
+                item.options.push({
+                  value: col.field,
+                  text: label
+                })
+              }
+            })
+          }
         } else if (item.key === 'value') {
           if (value === 'slider') {
             item.type = 'number'
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index c63b76f..859dc58 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -28,7 +28,7 @@
     anchors = MenuUtils.getAnchors(window.GLOB.customMenu.components, cards.uuid) || []
   }
 
-  if (cards.type === 'table' || (cards.type === 'card' && cards.subtype === 'datacard')) {
+  if (cards.type === 'table' || (cards.type === 'card' && cards.subtype !== 'propcard')) {
     _options.push({value: 'sequence', text: '搴忓彿'})
   } else if (card.eleType === 'sequence') { // 鎷栨嫿娣诲姞绫诲瀷杞崲
     card.eleType = 'text'
@@ -440,18 +440,18 @@
         { value: '9:16', text: '9:16' },
       ]
     },
-    {
-      type: 'radio',
-      key: 'backgroundSize',
-      label: '鍥惧儚澶у皬',
-      initVal: card.backgroundSize || 'cover',
-      required: false,
-      options: [
-        { value: 'cover', text: '瑕嗙洊' },
-        { value: 'contain', text: '鍖呭惈' },
-        { value: 'auto', text: '鑷�傚簲' },
-      ]
-    },
+    // {
+    //   type: 'radio',
+    //   key: 'backgroundSize',
+    //   label: '鍥惧儚澶у皬',
+    //   initVal: card.backgroundSize || 'cover',
+    //   required: false,
+    //   options: [
+    //     { value: 'cover', text: '瑕嗙洊' },
+    //     { value: 'contain', text: '鍖呭惈' },
+    //     { value: 'auto', text: '鑷�傚簲' },
+    //   ]
+    // },
     {
       type: 'number',
       key: 'maxWidth',
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index a71506f..9459118 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -122,11 +122,12 @@
     this.setState({elements: this.state.elements.filter(item => item.uuid !== eleId)})
   }
 
-  cardAddElement = (id, element) => {
-    const { cardCell } = this.props
+  cardAddElement = (id, element, type) => {
+    const { cardCell, side } = this.props
 
     if (id !== cardCell.uuid) return
     if (window.GLOB.$lock) return
+    if (type && side !== type) return
 
     window.GLOB.$lock = true
     setTimeout(() => {
@@ -149,12 +150,13 @@
         options = ['margin', 'float']
       } else {
         options.push('width', 'minHeight', 'float')
+        _style.minHeight = _style.minHeight || '28px'
       }
       if (element.wrapStyle) {
         _style.float = element.wrapStyle.textAlign || 'left'
       }
     } else if (element.eleType === 'picture') {
-      options = ['border', 'margin']
+      options = ['background', 'border', 'margin']
     } else if (element.eleType === 'color') {
       options = ['border', 'margin', 'padding']
     } else if (element.eleType === 'text') {
@@ -172,7 +174,7 @@
       card: element
     })
 
-    MKEmitter.emit('changeStyle', options, _style, this.getStyle)
+    MKEmitter.emit('changeStyle', options, _style, this.getStyle, 'mk-' + element.eleType)
   }
 
   getStyle = (style) => {
@@ -241,6 +243,9 @@
         _card.wrapStyle = {textAlign: style.float}
         delete _card.style.float
       }
+    } else if (_card.eleType === 'picture') {
+      _card.style = style
+      delete _card.style.backgroundImage
     } else {
       _card.style = style
     }
@@ -401,6 +406,8 @@
             }
       
             res.innerHeight = res.barHeight + (res.displayValue === 'true' ? fontSize + 2 : 0)
+          } else if (res.eleType === 'picture') {
+            delete res.style.backgroundImage
           }
           
           return res
@@ -529,9 +536,13 @@
   }
 
   handleSubConfig = (item) => {
-    const { cards } = this.props
+    const { cards, side } = this.props
     const { appType } = this.state
     let btn = fromJS(item).toJS()
+
+    if (side === 'sub') {
+      btn.$sub = true
+    }
 
     if ((sessionStorage.getItem('style-control') && sessionStorage.getItem('style-control') === 'true')) return
 
@@ -687,7 +698,7 @@
   }
 
   getVerify = (card) => {
-    const { cards } = this.props
+    const { cards, side } = this.props
 
     if (!card) return null
 
@@ -695,13 +706,13 @@
       return <VerifyCard
         card={card}
         config={cards}
-        columns={cards.columns}
+        columns={side === 'sub' ? cards.subColumns : cards.columns}
         wrappedComponentRef={(inst) => this.verifyRef = inst}
       />
     } else if (card.OpenType === 'excelIn') {
       return <VerifyExcelIn
         card={card}
-        columns={cards.columns}
+        columns={side === 'sub' ? cards.subColumns : cards.columns}
         wrappedComponentRef={(inst) => this.verifyRef = inst}
       />
     } else if (card.OpenType === 'excelOut') {
@@ -713,14 +724,14 @@
     } else if (card.OpenType === 'funcbutton' && card.funcType === 'print') {
       return <VerifyPrint
         card={card}
-        columns={cards.columns}
+        columns={side === 'sub' ? cards.subColumns : cards.columns}
         wrappedComponentRef={(inst) => this.verifyRef = inst}
       />
     }
   }
 
   render() {
-    const { cards, cardCell } = this.props
+    const { cards, cardCell, side } = this.props
     const { elements, visible, actvisible, profVisible, card, record } = this.state
 
     return (
@@ -728,7 +739,7 @@
         <DragElement
           list={elements}
           parent={cardCell}
-          fields={cards.columns}
+          fields={side === 'sub' ? cards.subColumns : cards.columns}
           updateMarks={this.updateMarks}
           handleList={this.handleList}
           handleMenu={this.handleElement}
@@ -751,6 +762,7 @@
           >
             <ElementForm
               card={card}
+              side={side}
               formlist={this.state.formlist}
               inputSubmit={this.handleSubmit}
               config={cards}
@@ -765,7 +777,7 @@
             maskClosable={false}
             onCancel={this.editModalCancel}
             footer={[
-              record && record.intertype === 'inner' ? <CreateFunc key="create" ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
+              record && record.intertype === 'inner' && cards.subtype === 'dualdatacard' ? <CreateFunc key="create" ref="btnCreatFunc" trigger={this.creatFunc}/> : null,
               <Button key="cancel" onClick={this.editModalCancel}>鍙栨秷</Button>,
               <Button key="confirm" type="primary" onClick={this.handleActionSubmit}>纭畾</Button>
             ]}
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index 6bd283e..a7efb6a 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -13,7 +13,7 @@
 import './index.scss'
 
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
-const CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
+const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const PasteController = asyncIconComponent(() => import('@/components/paste'))
 
@@ -311,9 +311,24 @@
     }
     _style = resetStyle(_style)
 
+    let checkAll = ''
+    if ((cards.subtype === 'datacard' || cards.subtype === 'dualdatacard') && card.$cardType === 'extendCard') {
+      checkAll = card.setting.checkAll === 'show' ? ' mk-checkable mk-extend-card' : ''
+      if (checkAll && cards.wrap.selStyle === 'check square') {
+        checkAll = ' mk-checkable square mk-extend-card'
+      }
+    } else if (cards.subtype === 'datacard') {
+      if (cards.wrap.selStyle === 'check') {
+        checkAll = ' mk-checkable'
+      } else if (cards.wrap.selStyle === 'check square') {
+        checkAll = ' mk-checkable square'
+      }
+    }
+
     return (
       <Col span={card.setting.width || 6}>
-        <div className={'card-item ' + (card.setting.btnControl || '')} style={_style} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
+        <div className={'card-item ' + (card.setting.btnControl || '') + checkAll} style={_style} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
+          <span className="circle-select"></span>
           <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
           <div className="card-control" onDoubleClick={(e) => e.stopPropagation()}>
             <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
diff --git a/src/menu/components/card/cardcomponent/index.scss b/src/menu/components/card/cardcomponent/index.scss
index a32dfaa..62291ee 100644
--- a/src/menu/components/card/cardcomponent/index.scss
+++ b/src/menu/components/card/cardcomponent/index.scss
@@ -62,3 +62,34 @@
     background: rgba(255, 255, 255, 0.55);
   }
 }
+.card-item {
+  .circle-select {
+    position: relative;
+    display: none;
+    width: 16px;
+    height: 16px;
+    border: 1px solid #cccccc;
+    border-radius: 50%;
+    box-sizing: content-box;
+    margin: auto;
+    margin-right: 5px;
+    background-color: #ffffff;
+    transition: border-color 0.2s;
+    cursor: pointer;
+  }
+}
+// square
+.card-item.mk-checkable {
+  display: flex;
+  .circle-select {
+    display: inline-block;
+  }
+  .model-menu-card-cell-list {
+    flex: 1;
+  }
+}
+.card-item.mk-checkable.square {
+  .circle-select {
+    border-radius: 0;
+  }
+}
diff --git a/src/menu/components/card/cardcomponent/options.jsx b/src/menu/components/card/cardcomponent/options.jsx
index f93e6f2..02d46f2 100644
--- a/src/menu/components/card/cardcomponent/options.jsx
+++ b/src/menu/components/card/cardcomponent/options.jsx
@@ -73,7 +73,7 @@
       controlFields: [
         {field: 'transform', values: ['multi']},
       ],
-      forbid: appType === 'mob'
+      forbid: appType === 'mob' || subtype === 'dualdatacard'
     },
     {
       type: 'select',
@@ -91,7 +91,8 @@
         {value: 'opacity', label: '閫忔槑搴�'},
         {value: 'rotateX', label: '绾靛悜灞曞紑'},
         {value: 'rotateY', label: '妯悜灞曞紑'},
-      ]
+      ],
+      forbid: appType === 'mob' || subtype === 'dualdatacard'
     },
     {
       type: 'text',
@@ -109,7 +110,8 @@
       initval: setting.bgField || '',
       tooltip: '鍔ㄦ�佽儗鏅紝鑳屾櫙鍥剧墖鐢卞瓧娈靛�兼帶鍒躲�傝娉ㄦ剰璋冩暣鑳屾櫙鏍峰紡銆�',
       required: false,
-      options: columns
+      options: columns,
+      forbid: cardType === 'extendCard'
     },
     {
       type: ops.length === 0 ? 'radio' : 'select',
@@ -236,6 +238,19 @@
       forbid: appType === 'mob'
     },
     {
+      type: 'radio',
+      field: 'checkAll',
+      label: '鍏ㄩ��',
+      initval: setting.checkAll || 'hidden',
+      tooltip: '鍏ㄩ�変粎鍦ㄦ暟鎹崱鍙閫夛紝涓旈�変腑椋庢牸涓哄嬀閫夋鏃舵湁鏁堛��',
+      required: false,
+      options: [
+        {value: 'hidden', label: '闅愯棌'},
+        {value: 'show', label: '鏄剧ず'},
+      ],
+      forbid: cardType !== 'extendCard'
+    },
+    {
       type: 'table',
       field: 'menus',
       label: '鑿滃崟缁�',
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index 46d05a9..92c55a7 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/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 { Popover, Modal, Pagination } from 'antd'
+import { Popover, Modal, Pagination, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -288,7 +288,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'height', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'height', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -448,7 +448,6 @@
       delete _card.supNodes
     }
 
-    
     if (res.layout === 'flex') {
       _card.wrap.pagestyle = 'page'
     }
@@ -491,9 +490,9 @@
 
       let elements = []
       res.elements && res.elements.forEach(cell => {
-        if (cell.datatype === 'dynamic') {
-          cell.datatype = 'static'
-        }
+        // if (cell.datatype === 'dynamic') {
+        //   cell.datatype = 'static'
+        // }
 
         if (cell.eleType !== 'button') {
           cell.uuid = Utils.getuuid()
@@ -512,9 +511,9 @@
 
       if (appType !== 'mob') {
         res.backElements && res.backElements.forEach(cell => {
-          if (cell.datatype === 'dynamic') {
-            cell.datatype = 'static'
-          }
+          // if (cell.datatype === 'dynamic') {
+          //   cell.datatype = 'static'
+          // }
 
           if (cell.eleType !== 'button') {
             cell.uuid = Utils.getuuid()
@@ -623,7 +622,15 @@
         {card.wrap.pagestyle === 'more' && card.setting.laypage === 'true' ? <div className="mk-more">鏌ョ湅鏇村<DownOutlined/></div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/data-card/options.jsx b/src/menu/components/card/data-card/options.jsx
index 49358f7..a98a24c 100644
--- a/src/menu/components/card/data-card/options.jsx
+++ b/src/menu/components/card/data-card/options.jsx
@@ -237,7 +237,10 @@
         {value: 'backFont', label: '鑳屾櫙+鏂囧瓧'},
         {value: 'font', label: '鏂囧瓧'},
         {value: 'tabs', label: '鏍囩椤�'},
-        ...(subtype === 'datacard' && appType === 'mob' ? [{value: 'check', label: '鍕鹃��'}] : [])
+        ...(subtype === 'datacard' ? [
+          {value: 'check', label: '鍕鹃�夛紙鍦嗘锛�'},
+          {value: 'check square', label: '鍕鹃�夛紙鏂规锛�'}
+        ] : [])
       ],
       forbid: subtype === 'tablecard'
     },
@@ -282,6 +285,19 @@
     },
     {
       type: 'radio',
+      field: 'parity',
+      label: '濂囧伓鑳屾櫙',
+      initval: wrap.parity || 'false',
+      tooltip: '鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
+      required: false,
+      options: [
+        {value: 'false', label: '鏃�'},
+        {value: 'true', label: '鏈�'},
+      ],
+      forbid: subtype === 'propcard'
+    },
+    {
+      type: 'radio',
       field: 'printType',
       label: '缁勪欢绫诲瀷',
       initval: wrap.printType || 'content',
diff --git a/src/menu/components/card/double-data-card/index.jsx b/src/menu/components/card/double-data-card/index.jsx
new file mode 100644
index 0000000..5e709c6
--- /dev/null
+++ b/src/menu/components/card/double-data-card/index.jsx
@@ -0,0 +1,645 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Popover, Modal, Pagination, message } from 'antd'
+import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined } from '@ant-design/icons'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle, getTables } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import Utils from '@/utils/utils.js'
+import getWrapForm from './options'
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const CardComponent = asyncComponent(() => import('../cardcomponent'))
+const DoubleCardComponent = asyncComponent(() => import('../doublecardcomponent'))
+const MobPagination = asyncIconComponent(() => import('@/menu/components/share/mobPagination'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/components/paste'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
+
+const { confirm } = Modal
+
+class DoubleDataCardEditComponent extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    card: null,
+    appType: sessionStorage.getItem('appType'),
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        format: 'array',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: true,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: true,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, width: card.width || 24, title: '', pagestyle: 'page', cardType: '' },
+        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        subColumns: [],
+        scripts: [],
+        action: [],
+        search: [],
+        subcards: [{
+          uuid: Utils.getuuid(),
+          setting: { width: 24, display: 'default', position: 'bottom' },
+          style: {
+            borderWidth: '1px', borderColor: '#e8e8e8',
+            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+            marginLeft: '8px', marginRight: '8px', marginTop: '8px'
+          },
+          elements: [{
+            uuid: Utils.getuuid(),
+            eleType: 'text',
+            datatype: 'static',
+            width: 12,
+            value: '寰幆鍖哄煙'
+          }],
+          backSetting: {width: 24},
+          backStyle: {
+            borderLeftWidth: '1px', borderLeftColor: '#e8e8e8',
+            borderRightWidth: '1px', borderRightColor: '#e8e8e8',
+            borderBottomWidth: '1px', borderBottomColor: '#e8e8e8',
+            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+            marginLeft: '8px', marginRight: '8px'
+          },
+          backElements: [{
+            uuid: Utils.getuuid(),
+            eleType: 'text',
+            datatype: 'static',
+            width: 12,
+            value: '瀛愯〃鍖哄煙'
+          }]
+        }]
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+
+        _card.setting = config.setting
+        _card.columns = config.columns
+        _card.scripts = config.scripts
+
+        _card.subcards = config.subcards.map(scard => {
+          scard.uuid = Utils.getuuid()
+          scard.elements = scard.elements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          scard.backElements = scard.backElements.map(elem => {
+            elem.uuid = Utils.getuuid()
+            return elem
+          })
+          return scard
+        })
+        _card.action = config.action.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+        _card.search = config.search.map(col => {
+          col.uuid = Utils.getuuid()
+          return col
+        })
+      }
+
+      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.errors = []
+    let columns = card.columns.map(c => c.field)
+
+    if (card.setting.interType === 'system' && card.setting.execute !== 'false' && !card.setting.dataresource) {
+      card.errors.push({ level: 0, detail: '鏈缃暟鎹簮锛�'})
+    } else if (card.setting.interType === 'system' && card.setting.execute === 'false' && card.scripts.filter(script => script.status !== 'false').length === 0) {
+      card.errors.push({ level: 0, detail: '鏁版嵁婧愪腑鏃犲彲鐢ㄨ剼鏈紒'})
+    } else if (!card.setting.primaryKey) {
+      card.errors.push({ level: 0, detail: '鏈缃富閿紒'})
+    } else if (!card.setting.subKey) {
+      card.errors.push({ level: 0, detail: '鏈缃瓙琛ㄤ富閿紒'})
+    } else if (!card.setting.subBID) {
+      card.errors.push({ level: 0, detail: '鏈缃瓙琛˙ID锛�'})
+    } else if (!columns.includes(card.setting.primaryKey)) {
+      card.errors.push({ level: 0, detail: '涓婚敭宸插け鏁堬紒'})
+    } else if (!card.setting.supModule) {
+      card.errors.push({ level: 0, detail: '鏈缃笂绾х粍浠讹紒'})
+    }
+    
+    if (card.errors.length === 0) {
+      card.$tables = getTables(card)
+    }
+
+    card.action.forEach(cell => {
+      if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+        if (!cell.modal || cell.modal.fields.length === 0) {
+          card.errors.push({ level: 1, detail: `鎸夐挳鈥�${cell.label}鈥濅腑琛ㄥ崟灏氭湭娣诲姞`})
+        }
+      }
+    })
+
+    card.subcards.forEach((item, i) => {
+      let linkbtn = item.setting.linkbtn || ''
+      item.elements.forEach(cell => {
+        if (cell.eleType === 'button') {
+          if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+            if (!cell.modal || cell.modal.fields.length === 0) {
+              card.errors.push({ level: 1, detail: `鎸夐挳鈥�${cell.label}鈥濅腑琛ㄥ崟灏氭湭娣诲姞`})
+            }
+          }
+          if (linkbtn && linkbtn === cell.uuid) {
+            linkbtn = ''
+          }
+        } else if (cell.datatype === 'dynamic' && cell.field && !columns.includes(cell.field)) {
+          card.errors.push({ level: 1, detail: `鍗$墖涓姩鎬佸瓧娈碘��${cell.field}鈥濇棤鏁坄})
+        }
+      })
+
+      item.backElements.forEach(cell => {
+        if (cell.eleType === 'button') {
+          if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+            if (!cell.modal || cell.modal.fields.length === 0) {
+              card.errors.push({ level: 1, detail: `鎸夐挳鈥�${cell.label}鈥濅腑琛ㄥ崟灏氭湭娣诲姞`})
+            }
+          }
+          if (linkbtn && linkbtn === cell.uuid) {
+            linkbtn = ''
+          }
+        } else if (cell.datatype === 'dynamic' && cell.field && !columns.includes(cell.field)) {
+          card.errors.push({ level: 1, detail: `鍗$墖涓姩鎬佸瓧娈碘��${cell.field}鈥濇棤鏁坄})
+        }
+      })
+
+      if (linkbtn) {
+        card.errors.push({ level: 1, detail: `绗�${i + 1}寮犲崱鐗囦腑缁戝畾鎸夐挳宸插垹闄})
+      }
+    })
+
+    this.setState({
+      card: card
+    })
+
+    this.props.updateConfig(card)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  updateCard = (cell, btn) => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === cell.uuid) return cell
+      return item
+    })
+
+    if (btn) {
+      card.action = card.action.filter(item => item.uuid !== btn.uuid)
+    }
+
+    this.updateComponent(card)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  deleteCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+    let _this = this
+
+    confirm({
+      content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
+      onOk() {
+        card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
+
+        _this.updateComponent(card)
+      },
+      onCancel() {}
+    })
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', ['background', 'height', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
+  }
+
+  getStyle = (style) => {
+    let _card = {...this.state.card, style}
+    
+    this.updateComponent(_card)
+  }
+
+  addSearch = (copy) => {
+    const { card } = this.state
+
+    let newcard = {}
+
+    if (copy) {
+      newcard = copy
+      newcard.focus = true
+    } else {
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+  
+      newcard.label = 'label'
+      newcard.type = 'select'
+      newcard.resourceType = '0'
+      newcard.options = []
+      newcard.orderType = 'asc'
+      newcard.match = '='
+    }
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎼滅储
+    MKEmitter.emit('addSearch', card.uuid, newcard)
+  }
+
+  addButton = (copy) => {
+    const { card } = this.state
+
+    let newcard = {}
+
+    if (copy) {
+      newcard = copy
+      newcard.focus = true
+    } else {
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      newcard.label = 'label'
+      newcard.Ot = 'requiredSgl'
+      newcard.OpenType = 'pop'
+      newcard.icon = ''
+      newcard.class = 'green'
+      newcard.intertype = card.setting.interType || 'system'
+      newcard.innerFunc = card.setting.innerFunc || ''
+      newcard.sysInterface = card.setting.sysInterface || ''
+      newcard.outerFunc = card.setting.outerFunc || ''
+      newcard.interface = card.setting.interface || ''
+      newcard.execSuccess = 'grid'
+      newcard.execError = 'never'
+      newcard.verify = null
+      newcard.show = 'button'
+      newcard.style = {marginRight: '15px'}
+    }
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
+    MKEmitter.emit('addButton', card.uuid, newcard)
+  }
+
+  setSubConfig = (item) => {
+    const { card, appType } = this.state
+    let btn = fromJS(item).toJS()
+
+    if (btn.OpenType === 'pop' || btn.execMode === 'pop') {
+      if (!btn.modal) {
+        btn.modal = {
+          setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
+          tables: [],
+          groups: [],
+          fields: []
+        }
+      }
+      MKEmitter.emit('changeModal', card, btn)
+    } else if (btn.OpenType === 'popview' && appType !== 'mob') {
+      MKEmitter.emit('changePopview', card, btn)
+    }
+  }
+
+  addCard = (copy) => {
+    let card = fromJS(this.state.card).toJS()
+    let newcard = {}
+
+    if (copy) { // 绮樿创
+      newcard = copy
+    } else {
+      let height = card.subcards[0].style.height
+      if (height === 'auto') {
+        height = '100px'
+      }
+  
+      newcard = {
+        uuid: Utils.getuuid(),
+        $cardType: 'extendCard',
+        setting: { width: 24, click: ''},
+        style: {
+          height,
+          borderWidth: '1px', borderColor: '#e8e8e8',
+          paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
+          marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+        },
+        backStyle: {},
+        elements: [],
+        backElements: []
+      }
+    }
+
+    card.subcards.push(newcard)
+
+    this.updateComponent(card)
+  }
+
+  move = (item, direction) => {
+    let card = fromJS(this.state.card).toJS()
+
+    let dragIndex = card.subcards.findIndex(c => c.uuid === item.uuid)
+    let hoverIndex = null
+
+    if (direction === 'left') {
+      hoverIndex = dragIndex - 1
+    } else {
+      hoverIndex = dragIndex + 1
+    }
+
+    if (hoverIndex === -1 || hoverIndex === card.subcards.length) return 
+
+    card.subcards.splice(hoverIndex, 0, ...card.subcards.splice(dragIndex, 1))
+
+    this.updateComponent(card)
+  }
+
+  getWrapForms = () => {
+    const { card } = this.state
+    
+    return getWrapForm(card.wrap, card.columns, card.setting)
+  }
+
+  updateWrap = (res) => {
+    const { card } = this.state
+
+    let _card = {...card, wrap: res}
+    
+    if (res.layout === 'flex') {
+      _card.wrap.pagestyle = 'page'
+    }
+    
+    if (res.selStyle === 'tabs' && card.wrap.selStyle !== 'tabs') {
+      Object.keys(_card.style).forEach(key => {
+        if (/^border/.test(key)) {
+          delete _card.style[key]
+        }
+      })
+      _card.style.borderBottomColor = '#eeeeee'
+      _card.style.borderBottomWidth = '1px'
+      _card.style.paddingBottom = '0px'
+
+      _card.subcards.forEach(item => {
+        delete item.style.marginBottom
+      })
+      
+      this.setState({card: {..._card, subcards: []}}, () => {
+        this.updateComponent(_card)
+      })
+    } else {
+      this.updateComponent(_card)
+    }
+  }
+
+  pasteComponent = (res, resolve) => {
+    const { card, appType } = this.state
+
+    let type = res.copyType
+    delete res.copyType
+
+    if (type === 'cardcell') {
+      res.uuid = Utils.getuuid()
+      res.setting = res.setting || {}
+      res.$cardType = 'extendCard'
+      res.setting.width = res.setting.width || 6
+
+      let mobtypes = ['pop', 'prompt', 'exec', 'innerpage', 'funcbutton']
+
+      let elements = []
+      res.elements && res.elements.forEach(cell => {
+        // if (cell.datatype === 'dynamic') {
+        //   cell.datatype = 'static'
+        // }
+
+        if (cell.eleType !== 'button') {
+          cell.uuid = Utils.getuuid()
+          elements.push(cell)
+        } else if (appType === 'mob' && !mobtypes.includes(cell.OpenType)) {
+          return
+        } else {
+          cell.uuid = Utils.getuuid()
+          elements.push(cell)
+        }
+      })
+
+      res.elements = elements
+
+      let backElements = []
+
+      if (appType !== 'mob') {
+        res.backElements && res.backElements.forEach(cell => {
+          // if (cell.datatype === 'dynamic') {
+          //   cell.datatype = 'static'
+          // }
+
+          if (cell.eleType !== 'button') {
+            cell.uuid = Utils.getuuid()
+            backElements.push(cell)
+          } else if (appType === 'mob' && !mobtypes.includes(cell.OpenType)) {
+            return
+          } else {
+            cell.uuid = Utils.getuuid()
+            backElements.push(cell)
+          }
+        })
+      }
+
+      res.backElements = backElements
+
+      resolve({status: true})
+
+      this.addCard(res)
+    } else if (type === 'search' || type === 'form') {
+      if (appType === 'mob') {
+        resolve({status: false, message: '绉诲姩绔暟鎹崱涓嶆敮鎸佹坊鍔犳悳绱㈡潯浠躲��'})
+      } else {
+        res.uuid = Utils.getuuid()
+        let keys = card.search.map(item => item.field.toLowerCase())
+  
+        if (type === 'form') {
+          if (['number', 'switch', 'textarea', 'fileupload', 'hint', 'color', 'funcvar'].includes(res.type)) {
+            res.type = 'text'
+          } else if (res.type === 'radio') {
+            res.type = 'select'
+          } else if (res.type === 'checkbox') {
+            res.type = 'multiselect'
+          } else if (res.type === 'datetime') {
+            res.type = 'date'
+          }
+        }
+  
+        if (res.field && keys.includes(res.field.toLowerCase())) {
+          resolve({status: false, message: '鎼滅储瀛楁宸插瓨鍦紒'})
+          return
+        }
+
+        resolve({status: true})
+
+        this.addSearch(res)
+      }
+    } else if (type === 'action') {
+      if (appType === 'mob' && !['pop', 'prompt', 'exec', 'innerpage'].includes(res.OpenType)) {
+        resolve({status: false, message: '绉诲姩绔笉鏀寔姝ょ被鍨嬬殑鎸夐挳銆�'})
+      } else {
+        resolve({status: true})
+    
+        res.uuid = Utils.getuuid()
+        this.addButton(res)
+      }
+    }
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card.uuid, null, (style) => {
+        let _card = {...this.state.card}
+        _card.style = {..._card.style, ...style}
+
+        this.setState({ card: _card })
+        this.props.updateConfig(_card)
+      })
+    }
+  }
+
+  render() {
+    const { card, appType } = this.state
+
+    let _style = resetStyle(card.style)
+
+    let extraName = ''
+    card.subcards.forEach(subcard => {
+      if (subcard.$cardType === 'extendCard') return
+      if (subcard.setting.controlIcon === 'left') {
+        extraName = ' mk-control-icon'
+      }
+    })
+
+    return (
+      <div className={'menu-double-data-card-edit-box ' + appType} style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <NormalHeader config={card} updateComponent={this.updateComponent}/>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <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}>
+              <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
+            </NormalForm>
+            <CopyComponent type="datacard" card={card}/>
+            <PasteComponent options={['action', 'search', 'form', 'cardcell']} updateConfig={this.pasteComponent} />
+            <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <DeleteOutlined className="close" title="鍒犻櫎缁勪欢" onClick={() => this.props.deletecomponent(card.uuid)} />
+            <SettingComponent config={card} updateConfig={this.updateComponent} />
+          </div>
+        } trigger="hover">
+          <ToolOutlined />
+        </Popover>
+        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
+        <div className={'select-' + card.wrap.selStyle + extraName}>
+          {card.subcards.map(subcard => {
+            if (subcard.$cardType === 'extendCard') {
+              return (<CardComponent key={subcard.uuid} cards={card} card={subcard} move={this.move} updateElement={this.updateCard} deleteElement={this.deleteCard}/>)
+            } else {
+              return (<DoubleCardComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard}/>)
+            }
+          })}
+        </div>
+        <div style={{clear: 'both'}}></div>
+        {card.wrap.pagestyle === 'page' && card.setting.laypage === 'true' && appType !== 'mob' ? <Pagination total={85} size="small" showTotal={total => `鍏� ${total} 鏉} pageSize={20} defaultCurrent={1}/> : null}
+        {card.wrap.pagestyle === 'page' && card.setting.laypage === 'true' && appType === 'mob' ? <MobPagination /> : null}
+        {card.wrap.pagestyle === 'more' && card.setting.laypage === 'true' ? <div className="mk-more">鏌ョ湅鏇村<DownOutlined/></div> : null}
+        <div className="component-name">
+          <div className="center">
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
+            <div className="content">
+              {card.errors && card.errors.map((err, index) => {
+                if (err.level === 0) {
+                  return <span key={index} className="error">{err.detail}</span>
+                } else {
+                  return <span key={index} className="waring">{err.detail}锛�</span>
+                }
+              })}
+            </div>
+          </div>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default DoubleDataCardEditComponent
\ No newline at end of file
diff --git a/src/menu/components/card/double-data-card/index.scss b/src/menu/components/card/double-data-card/index.scss
new file mode 100644
index 0000000..40ea29c
--- /dev/null
+++ b/src/menu/components/card/double-data-card/index.scss
@@ -0,0 +1,148 @@
+.menu-double-data-card-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 20px;
+  overflow-y: auto;
+  
+  >.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);
+  }
+
+  .card-item, .card-item-wrap {
+    overflow: hidden;
+    position: relative;
+    background-color: #ffffff;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    min-height: 20px;
+  }
+  .card-item.hover:not(:hover) {
+    button {
+      opacity: 0;
+      transition: opacity 0.3s;
+    }
+  }
+  
+  .card-item:hover {
+    box-shadow: 0px 0px 2px #1890ff;
+  }
+
+  .model-menu-card-cell-list .card-detail-row > .anticon-plus {
+    position: absolute;
+    right: -30px;
+    font-size: 16px;
+  }
+  .model-menu-action-list {
+    line-height: 40px;
+    .ant-row > .anticon-plus {
+      position: absolute;
+      right: -30px;
+      font-size: 16px;
+    }
+  }
+  .ant-pagination {
+    float: right;
+    margin: 10px;
+  }
+
+  .model-menu-action-list {
+    .page-card {
+      line-height: 55px;
+    }
+  }
+  .normal-pagination {
+    .am-button::before {
+      display: none;
+    }
+    .am-button {
+      border: none;
+      font-size: 16px;
+    }
+  }
+  // .float-center {
+  //   text-align: center;
+  //   >.ant-col {
+  //     display: inline-block;
+  //     float: none;
+  //     text-align: left;
+  //     vertical-align: top;
+  //   }
+  // }
+  // .float-right {
+  //   text-align: right;
+  //   >.ant-col {
+  //     display: inline-block;
+  //     float: none;
+  //     text-align: left;
+  //     vertical-align: top;
+  //   }
+  // }
+  .select-tabs {
+    .card-item {
+      border-top: none!important;
+      border-left: none!important;
+      border-right: none!important;
+      border-radius: 0px!important;
+      border-bottom: 2px solid transparent!important;
+    }
+  }
+  .mk-more {
+    text-align: center;
+    line-height: 40px;
+    .anticon-down {
+      margin-left: 2px;
+    }
+  }
+  .select-check.mk-control-icon {
+    .mk-extend-card {
+      >.circle-select {
+        margin-right: 35px;
+      }
+    }
+  }
+}
+
+.menu-double-data-card-edit-box::-webkit-scrollbar {
+  width: 7px;
+  height: 7px;
+}
+.menu-double-data-card-edit-box::-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);
+}
+.menu-double-data-card-edit-box::-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);
+}
+.menu-double-data-card-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-double-data-card-edit-box.mob {
+  .model-menu-action-list {
+    .page-card {
+      line-height: 40px;
+      margin-top: 5px;
+    }
+  }
+}
+.menu-double-data-card-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/card/double-data-card/options.jsx b/src/menu/components/card/double-data-card/options.jsx
new file mode 100644
index 0000000..704da63
--- /dev/null
+++ b/src/menu/components/card/double-data-card/options.jsx
@@ -0,0 +1,240 @@
+/**
+ * @description Wrap琛ㄥ崟閰嶇疆淇℃伅
+ */
+export default function (wrap, columns = [], setting) {
+  let appType = sessionStorage.getItem('appType')
+  // let MenuType = ''
+  // let menu = window.GLOB.customMenu
+  let laypage = setting && setting.laypage !== 'false'
+
+  // if (menu.parentId === 'BillPrintTemp') {
+  //   MenuType = 'billPrint'
+  // }
+
+  let roleList = sessionStorage.getItem('sysRoles')
+
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch (e) {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  let menulist = []
+
+  if (appType === 'mob') {
+    menulist = sessionStorage.getItem('appMenus')
+    if (menulist) {
+      try {
+        menulist = JSON.parse(menulist)
+      } catch (e) {
+        menulist = []
+      }
+    } else {
+      menulist = []
+    }
+  }
+
+  const cardWrapForm = [
+    {
+      type: 'text',
+      field: 'title',
+      label: '鏍囬',
+      initval: wrap.title || '',
+      required: false
+    },
+    {
+      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: 'radio',
+    //   field: 'layout',
+    //   label: '鍗$墖甯冨眬',
+    //   initval: wrap.layout || 'grid',
+    //   tooltip: appType === 'mob' ? '寮规�у竷灞�鏃讹紝婊戝姩鍔犺浇鏃犳晥' : '',
+    //   required: false,
+    //   options: [
+    //     {value: 'grid', label: '鏍呮牸甯冨眬'},
+    //     {value: 'flex', label: '寮规�у竷灞�'},
+    //   ],
+    //   controlFields: [
+    //     {field: 'printHeight', values: ['flex']},
+    //     {field: 'cardFloat', values: ['grid']},
+    //   ]
+    // },
+    {
+      type: 'radio',
+      field: 'pagestyle',
+      label: '鍒嗛〉椋庢牸',
+      initval: wrap.pagestyle || 'page',
+      tooltip: '鏁版嵁婧愰�夋嫨鍒嗛〉鏃舵湁鏁堛�傛敞锛氬脊鎬у竷灞�鏃跺浐瀹氫负椤电爜銆�',
+      required: false,
+      disabled: !laypage,
+      options: [
+        {value: 'page', label: '椤电爜'},
+        {value: 'slide', label: '婊戝姩鍔犺浇', forbid: appType !== 'mob' || sessionStorage.getItem('editMenuType') === 'popview'},
+        {value: 'more', label: '鏌ョ湅鏇村'},
+      ],
+      controlFields: [
+        {field: 'slidetip', values: ['slide']},
+      ],
+    },
+    {
+      type: 'radio',
+      field: 'cardType',
+      label: '鏁版嵁閫夋嫨',
+      initval: wrap.cardType || '',
+      required: false,
+      options: [
+        {value: '', label: '涓嶅彲閫�'},
+        {value: 'radio', label: '鍗曢��'},
+        {value: 'checkbox', label: '澶氶��'},
+      ],
+      controlFields: [
+        {field: 'selected', values: ['radio', 'checkbox']},
+        {field: 'selStyle', values: ['radio', 'checkbox']},
+      ],
+    },
+    {
+      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: 'select',
+      field: 'selStyle',
+      label: '閫変腑椋庢牸',
+      initval: wrap.selStyle || 'active',
+      tooltip: '瀛樺湪杈规鏃讹紝杈规浼氫娇鐢ㄧ郴缁熻壊銆�',
+      required: false,
+      options: [
+        {value: 'none', label: '鏃�'},
+        {value: 'active', label: '澶栭槾褰�'},
+        {value: 'backFont', label: '鑳屾櫙+鏂囧瓧'},
+        {value: 'font', label: '鏂囧瓧'},
+        {value: 'check', label: '鍕鹃�夛紙鍦嗘锛�'},
+        {value: 'check square', label: '鍕鹃�夛紙鏂规锛�'}
+      ]
+    },
+    {
+      type: 'radio',
+      field: 'parity',
+      label: '濂囧伓鑳屾櫙',
+      initval: wrap.parity || 'false',
+      tooltip: '鍋舵暟琛屼細娣诲姞鑳屾櫙鑹层��',
+      required: false,
+      options: [
+        {value: 'false', label: '鏃�'},
+        {value: 'true', label: '鏈�'},
+      ],
+    },
+    // {
+    //   type: 'number',
+    //   field: 'printHeight',
+    //   label: '鎹㈢畻楂樺害',
+    //   initval: wrap.printHeight || '',
+    //   tooltip: '褰撳墠鏁版嵁鍗¢珮搴︾浉褰撲簬鍑犳潯鏁版嵁銆�',
+    //   required: false,
+    //   forbid: MenuType !== 'billPrint'
+    // },
+    {
+      type: 'radio',
+      field: 'empty',
+      label: '绌哄�奸殣钘�',
+      initval: wrap.empty || 'show',
+      tooltip: '褰撴煡璇㈡暟鎹负绌烘椂锛岄殣钘忚缁勪欢銆�',
+      required: false,
+      options: [
+        {value: 'show', label: '鍚�'},
+        {value: 'hidden', label: '鏄�'},
+      ],
+    },
+    {
+      type: 'select',
+      field: 'controlField',
+      label: '绂佺敤瀛楁',
+      initval: wrap.controlField || '',
+      tooltip: '鐢ㄤ簬鎺у埗琛屾暟鎹槸鍚﹀彲閫夋嫨銆�',
+      required: false,
+      allowClear: true,
+      options: columns,
+      controlFields: [
+        {field: 'controlVal', notNull: true},
+      ],
+    },
+    {
+      type: 'text',
+      field: 'controlVal',
+      label: '绂佺敤鍊�',
+      initval: wrap.controlVal || '',
+      tooltip: '褰撳瓧娈靛�间笌绂佺敤鍊肩浉绛夋椂锛岃鏁版嵁浼氱鐢紝澶氫釜鍊肩敤閫楀彿鍒嗛殧銆�',
+      required: false
+    },
+    {
+      type: 'radio',
+      field: 'permission',
+      label: '鏉冮檺楠岃瘉',
+      initval: wrap.permission || 'false',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
+      ],
+      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
+    },
+    {
+      type: 'multiselect',
+      field: 'blacklist',
+      label: '榛戝悕鍗�',
+      initval: wrap.blacklist || [],
+      required: false,
+      options: roleList,
+      forbid: !!appType
+    },
+    {
+      type: 'text',
+      field: 'slidetip',
+      label: '搴曢儴鎻愮ず',
+      initval: wrap.slidetip || wrap.slidetip === '' ? wrap.slidetip : '娌℃湁鏇村浜�',
+      tooltip: '婊戝姩鍔犺浇鑷冲簳閮ㄦ椂鐨勬彁绀轰俊鎭��',
+      required: false,
+      forbid: !laypage || appType !== 'mob'
+    },
+  ]
+
+  return cardWrapForm.filter(item => {
+    if (['pagestyle'].includes(item.field)) {
+      item.options = item.options.filter(option => !option.forbid)
+    }
+
+    return !item.forbid
+  })
+} 
\ No newline at end of file
diff --git a/src/menu/components/card/doublecardcomponent/index.jsx b/src/menu/components/card/doublecardcomponent/index.jsx
new file mode 100644
index 0000000..f6d1544
--- /dev/null
+++ b/src/menu/components/card/doublecardcomponent/index.jsx
@@ -0,0 +1,318 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Popover, Col } from 'antd'
+import { UpOutlined, PlusOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, FontColorsOutlined } from '@ant-design/icons'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import getSettingForm from './options'
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteController = asyncIconComponent(() => import('@/components/paste'))
+
+class DoubleCardBoxComponent extends Component {
+  static propTpyes = {
+    cards: PropTypes.object,         // 鍗$墖琛岄厤缃俊鎭�
+    card: PropTypes.object,          // 鍗$墖閰嶇疆淇℃伅
+    updateElement: PropTypes.func    // 鑿滃崟閰嶇疆鏇存柊
+  }
+
+  state = {
+    card: null,            // 鍗$墖淇℃伅锛屽寘鎷鍙嶉潰
+    appType: sessionStorage.getItem('appType'),
+    visible: false,
+    side: ''
+  }
+
+  /**
+   * @description 鎼滅储鏉′欢鍒濆鍖�
+   */
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    this.setState({
+      card: fromJS(card).toJS()
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    const { cards } = this.props
+    
+    return !is(fromJS(cards), fromJS(nextProps.cards)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  getStyle = (style) => {
+    const { card, side } = this.state
+
+    let _card = fromJS(card).toJS()
+    if (side === 'sub') {
+      _card.backStyle = style
+    } else {
+      _card.style = style
+    }
+
+    this.setState({
+      card: _card
+    })
+
+    this.props.updateElement(_card)
+  }
+
+  updateCard = (elements, btn, type) => {
+    const { card } = this.state
+
+    let _card = {}
+
+    if (type === 'sub') {
+      _card = {...card, backElements: elements}
+    } else {
+      _card = {...card, elements: elements}
+    }
+
+    this.setState({
+      card: _card
+    })
+
+    this.props.updateElement(_card, btn)
+  }
+  
+  addElement = (type) => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.eleType = 'text'
+    newcard.datatype = 'dynamic'
+    newcard.height = 1
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+    MKEmitter.emit('cardAddElement', card.uuid, newcard, type)
+  }
+
+  addButton = (type) => {
+    const { card } = this.state
+
+    let newcard = {eleType: 'button', label: 'button', verify: null, show: 'link', sqlType: '', Ot: 'requiredSgl', OpenType: 'prompt', icon: '', class: 'primary', intertype: 'system', execSuccess: 'grid', execError: 'never', popClose: 'never'}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+    MKEmitter.emit('cardAddElement', card.uuid, newcard, type)
+  }
+
+  changeStyle = (type) => {
+    const { card } = this.state
+
+    let _style = null
+    let options = ['height', 'background', 'border', 'padding', 'margin', 'shadow']
+
+    if (type === 'sub') {
+      _style = fromJS(card.backStyle).toJS()
+    } else {
+      _style = fromJS(card.style).toJS()
+    }
+
+    this.setState({side: type})
+
+    MKEmitter.emit('changeStyle', options, _style, this.getStyle)
+  }
+
+  getSettingForms = () => {
+    const { cards } = this.props
+    const { card } = this.state
+
+    let buttons = []
+    card.elements.forEach(item => {
+      if (item.eleType === 'button') {
+        buttons.push({
+          value: item.uuid,
+          label: item.label
+        })
+      }
+    })
+
+    return getSettingForm(card.setting, buttons, cards.columns, 'main')
+  }
+
+  getBackSettingForms = () => {
+    const { cards } = this.props
+    const { card } = this.state
+
+    let buttons = []
+    card.backElements.forEach(item => {
+      if (item.eleType === 'button') {
+        buttons.push({
+          value: item.uuid,
+          label: item.label
+        })
+      }
+    })
+
+    return getSettingForm(card.backSetting, buttons, cards.subColumns)
+  }
+
+  updateSetting = (res, type) => {
+    const { card, appType } = this.state
+
+    if (appType === '' && res.menu) {
+      let list = null
+      try {
+        list = JSON.parse(sessionStorage.getItem('thdMenuList')) || []
+      } catch (e) {
+        list = []
+      }
+
+      let id = res.menu[res.menu.length - 1]
+
+      list.forEach(item => {
+        if (item.MenuID === id) {
+          res.MenuID = id
+          res.MenuName = item.MenuName
+          res.MenuNo = item.MenuNo
+          res.tabType = item.type
+        }
+      })
+    }
+
+    let _card = {...card}
+
+    if (type === 'sub') {
+      _card.backSetting = res
+    } else {
+      _card.setting = res
+    }
+
+    this.setState({
+      card: _card
+    })
+
+    this.props.updateElement(_card)
+  }
+
+  paste = (element, resolve, type) => {
+    const { card } = this.state
+
+    let _uuid = Utils.getuuid()
+    
+    if (element.copyType === 'action') {
+      element.eleType = 'button'
+    }
+
+    element.uuid = _uuid
+    element.focus = true
+
+    resolve({status: true})
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+    MKEmitter.emit('cardAddElement', card.uuid, element, type)
+  }
+
+  doubleClickCard = (type) => {
+    const { card } = this.state
+
+    if (type !== 'sub' && card.setting.click === 'menu' && card.setting.menu) {
+      MKEmitter.emit('changeEditMenu', {MenuID: card.setting.menu})
+    } else if (type === 'sub' && card.backSetting.click === 'menu' && card.backSetting.menu) {
+      MKEmitter.emit('changeEditMenu', {MenuID: card.backSetting.menu})
+    }
+  }
+
+  render() {
+    const { cards } = this.props
+    const { card } = this.state
+
+    let _style = {...card.style}
+    let _backStyle = {...card.backStyle}
+    let _wrapStyle = {}
+
+    _style = resetStyle(_style)
+    _backStyle = resetStyle(_backStyle)
+
+    if (card.setting.position === 'inner') {
+      Object.keys(_style).forEach(key => {
+        if (!/^(margin|border|box)/.test(key)) return
+        _wrapStyle[key] = _style[key]
+        delete _style[key]
+      })
+    }
+
+    let checkAll = ''
+    let mainBox = ''
+    if (cards.wrap.selStyle === 'check') {
+      checkAll = 'mk-checkable'
+    } else if (cards.wrap.selStyle === 'check square') {
+      checkAll = 'mk-checkable square'
+    } else if (card.setting.display !== 'default' && card.setting.controlIcon === 'left') {
+      mainBox = 'flex-card '
+    }
+
+    return (
+      <Col span={card.setting.width || 24}>
+        <div className="card-item-wrap" style={_wrapStyle}>
+          <div className={`card-item ${card.setting.btnControl || ''} ${checkAll} mk-${card.setting.display} ${mainBox}`} style={_style} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
+            <span className="circle-select"></span>
+            {card.setting.controlIcon === 'left' ? <PlusSquareOutlined /> : <UpOutlined />}
+            <div className="card-control" onDoubleClick={(e) => e.stopPropagation()}>
+              <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                <div className="mk-popover-control">
+                  <PlusOutlined className="plus" title="娣诲姞鍏冪礌" onClick={() => this.addElement('main')} />
+                  <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={() => this.addButton('main')} />
+                  <NormalForm title={'寰幆鍗$墖璁剧疆'} width={950} update={(res) => this.updateSetting(res)} getForms={this.getSettingForms}>
+                    <EditOutlined className="edit" title="缂栬緫"/>
+                  </NormalForm>
+                  <CopyComponent type="cardcell" card={card}/>
+                  <PasteController options={['action', 'customCardElement']} 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)}/>
+          </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}>
+              <div className="card-control" onDoubleClick={(e) => e.stopPropagation()}>
+                <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                  <div className="mk-popover-control">
+                    <PlusOutlined className="plus" title="娣诲姞鍏冪礌" onClick={() => this.addElement('sub')} />
+                    <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={() => this.addButton('sub')} />
+                    <NormalForm title={'寰幆瀛愬崱鐗囪缃�'} width={950} update={(res) => this.updateSetting(res, 'sub')} getForms={this.getBackSettingForms}>
+                      <EditOutlined className="edit" title="缂栬緫"/>
+                    </NormalForm>
+                    <CopyComponent type="cardcell" card={card}/>
+                    <PasteController options={['action', 'customCardElement']} 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')}/>
+            </div>
+          </Col>
+        </div>
+      </Col>
+    )
+  }
+}
+
+export default DoubleCardBoxComponent
\ No newline at end of file
diff --git a/src/menu/components/card/doublecardcomponent/index.scss b/src/menu/components/card/doublecardcomponent/index.scss
new file mode 100644
index 0000000..344ab73
--- /dev/null
+++ b/src/menu/components/card/doublecardcomponent/index.scss
@@ -0,0 +1,118 @@
+.menus-detail-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 200px;
+    .menu-line {
+      display: flex;
+      div {
+        padding: 16px 16px;
+        border-top: 1px solid #e8e8e8;
+        border-left: 1px solid #e8e8e8;
+        word-break: break-all;
+      }
+      div:last-child {
+        border-right: 1px solid #e8e8e8;
+      }
+      .sort {
+        width: 10%;
+        text-align: center;
+      }
+      .sign {
+        width: 35%;
+      }
+      .name {
+        width: 35%;
+      }
+      .action {
+        width: 20%;
+        text-align: center;
+        span {
+          display: inline-block;
+          padding: 0 10px;
+          cursor: pointer;
+          color: #1890ff;
+        }
+      }
+    }
+    .menu-line:first-child {
+      background-color: #fafafa;
+    }
+    .menu-line:last-child {
+      div {
+        border-bottom: 1px solid #e8e8e8;
+      }
+    }
+  }
+}
+
+.card-control {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  .anticon-tool {
+    position: absolute;
+    left: 1px;
+    top: 1px;
+    padding: 1px;
+    z-index: 2;
+    font-size: 16px;
+    cursor: pointer;
+    background: rgba(255, 255, 255, 0.55);
+  }
+}
+
+.card-item {
+  >.circle-select {
+    position: relative;
+    display: none;
+    width: 16px;
+    height: 16px;
+    border: 1px solid #cccccc;
+    border-radius: 50%;
+    box-sizing: content-box;
+    margin: auto;
+    margin-right: 5px;
+    background-color: #ffffff;
+    transition: border-color 0.2s;
+    cursor: pointer;
+  }
+  >.anticon-up {
+    position: absolute;
+    bottom: 10px;
+    right: 10px;
+    display: none;
+  }
+  >.anticon-plus-square {
+    margin: auto;
+    width: 30px;
+    font-size: 18px;
+  }
+}
+// square
+.card-item.mk-checkable {
+  display: flex;
+  .circle-select {
+    display: inline-block;
+  }
+  .model-menu-card-cell-list {
+    flex: 1;
+  }
+}
+.card-item.flex-card {
+  display: flex;
+  .model-menu-card-cell-list {
+    flex: 1;
+  }
+}
+.card-item.mk-checkable.square {
+  .circle-select {
+    border-radius: 0;
+  }
+}
+.card-item.mk-unfold, .card-item.mk-collapse {
+  >.anticon-up {
+    display: inline-block;
+  }
+}
diff --git a/src/menu/components/card/doublecardcomponent/options.jsx b/src/menu/components/card/doublecardcomponent/options.jsx
new file mode 100644
index 0000000..38a169d
--- /dev/null
+++ b/src/menu/components/card/doublecardcomponent/options.jsx
@@ -0,0 +1,194 @@
+/**
+ * @description Setting琛ㄥ崟閰嶇疆淇℃伅
+ */
+export default function (setting, buttons = [], columns, type) {
+  let appType = sessionStorage.getItem('appType')
+  let menulist = []
+
+  if (appType) {
+    menulist = sessionStorage.getItem('appMenus')
+    if (menulist) {
+      try {
+        menulist = JSON.parse(menulist)
+      } catch (e) {
+        menulist = []
+      }
+    } else {
+      menulist = []
+    }
+  } else {
+    menulist = sessionStorage.getItem('fstMenuList')
+    if (menulist) {
+      try {
+        menulist = JSON.parse(menulist)
+      } catch (e) {
+        menulist = []
+      }
+    } else {
+      menulist = []
+    }
+  }
+
+  const cardSettingForm = [
+    {
+      type: 'number',
+      field: 'width',
+      label: '鍗$墖瀹藉害',
+      initval: setting.width || 24,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      precision: 0,
+      required: true
+    },
+    {
+      type: 'radio',
+      field: 'display',
+      label: '瀛愯〃鏄剧ず',
+      initval: setting.display || 'default',
+      tooltip: '灞曞紑涓庡悎骞朵负鐢ㄦ埛鍙嚜琛屽垏鎹€��',
+      required: false,
+      options: [
+        {value: 'default', label: '榛樿'},
+        {value: 'unfold', label: '灞曞紑'},
+        {value: 'collapse', label: '鍚堝苟'},
+      ],
+      controlFields: [
+        // {field: 'position', values: ['default']},
+        {field: 'controlIcon', values: ['unfold', 'collapse']},
+      ],
+      forbid: type !== 'main'
+    },
+    {
+      type: 'radio',
+      field: 'controlIcon',
+      label: '鎺у埗鍥炬爣',
+      initval: setting.controlIcon || 'left',
+      required: false,
+      options: [
+        {value: 'left', label: '宸︿晶'},
+        {value: 'right', label: '鍙充晶'},
+      ],
+      forbid: type !== 'main'
+    },
+    {
+      type: 'radio',
+      field: 'position',
+      label: '瀛愯〃浣嶇疆',
+      initval: setting.position || 'bottom',
+      required: false,
+      options: [
+        {value: 'bottom', label: '涓昏〃涓嬫柟'},
+        {value: 'inner', label: '涓昏〃鍐�'},
+      ],
+      forbid: type !== 'main'
+    },
+    {
+      type: 'select',
+      field: 'bgField',
+      label: '鑳屾櫙鍥�',
+      initval: setting.bgField || '',
+      tooltip: '鍔ㄦ�佽儗鏅紝鑳屾櫙鍥剧墖鐢卞瓧娈靛�兼帶鍒躲�傝娉ㄦ剰璋冩暣鑳屾櫙鏍峰紡銆�',
+      required: false,
+      options: columns
+    },
+    {
+      type: 'select',
+      field: 'click',
+      label: '鐐瑰嚮浜嬩欢',
+      initval: setting.click || '',
+      required: false,
+      options: [
+        {value: '', label: '鏃�'},
+        {value: 'menu', label: '鑿滃崟'},
+        {value: 'link', label: '閾炬帴'},
+        {value: 'button', label: '鎸夐挳'},
+        {value: 'unfold', label: '瀛愯〃缂╂斁', disabled: type !== 'main'},
+      ],
+      controlFields: [
+        {field: 'menu', values: ['menu']},
+        {field: 'linkurl', values: ['link']},
+        {field: 'open', values: ['menu', 'link']},
+        {field: 'joint', values: ['menu', 'link']},
+        {field: 'linkbtn', values: ['button']},
+        {field: 'clickType', values: ['button', 'unfold']},
+      ]
+    },
+    {
+      type: appType ? 'select' : 'cascader',
+      field: 'menu',
+      label: '鍏宠仈鑿滃崟',
+      initval: setting.menu || (appType ? '' : []),
+      required: true,
+      extendName: 'MenuNo',
+      options: menulist,
+    },
+    {
+      type: 'textarea',
+      field: 'linkurl',
+      label: '閾炬帴',
+      initval: setting.linkurl || '',
+      required: true,
+      options: [],
+      span: 24
+    },
+    {
+      type: 'radio',
+      field: 'open',
+      label: '鎵撳紑鏂瑰紡',
+      initval: setting.open || 'blank',
+      required: false,
+      options: [
+        {value: 'blank', label: appType !== 'mob' ? '鏂扮獥鍙�' : '鏂伴〉闈�'},
+        {value: 'self', label: appType !== 'mob' ? '褰撳墠绐楀彛' : '褰撳墠椤甸潰'},
+      ],
+      forbid: appType !== 'pc' && appType !== 'mob'
+    },
+    {
+      type: 'radio',
+      field: 'joint',
+      label: '鍙傛暟鎷兼帴',
+      initval: setting.joint || 'true',
+      required: false,
+      options: [
+        {value: 'true', label: '鏄�'},
+        {value: 'false', label: '鍚�'},
+      ],
+    },
+    {
+      type: 'select',
+      field: 'linkbtn',
+      label: '鍏宠仈鎸夐挳',
+      initval: setting.linkbtn || '',
+      required: true,
+      options: buttons
+    },
+    {
+      type: 'radio',
+      field: 'clickType',
+      label: '瑙﹀彂鏂瑰紡',
+      initval: setting.clickType || 'normal',
+      required: false,
+      options: [
+        {value: 'normal', label: '鍗曞嚮'},
+        {value: 'multi', label: '鍙屽嚮'},
+      ],
+      forbid: appType === 'mob'
+    },
+    {
+      type: 'radio',
+      field: 'btnControl',
+      label: '鎸夐挳鎺у埗',
+      initval: setting.btnControl || 'show',
+      tooltip: '鍙缃寜閽樉绀鸿鍒欙紝涓�鐩存樉绀烘垨榧犳爣鎮诞鏃舵樉绀恒��',
+      required: false,
+      options: [
+        {value: 'show', label: '姝e父鏄剧ず'},
+        {value: 'hover', label: '鎮诞鏄剧ず'},
+      ],
+      forbid: appType === 'mob'
+    }
+  ]
+
+  return cardSettingForm
+} 
\ No newline at end of file
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
index 909dfa3..5508f0a 100644
--- a/src/menu/components/card/prop-card/index.jsx
+++ b/src/menu/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 { Popover, Modal } from 'antd'
+import { Popover, Modal, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, ClockCircleOutlined, HeatMapOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -304,7 +304,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -530,7 +530,15 @@
         {card.wrap.display === 'hidden' ? <HeatMapOutlined className="prop-hidden"/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/card/table-card/index.jsx b/src/menu/components/card/table-card/index.jsx
index 5596f30..3c014f4 100644
--- a/src/menu/components/card/table-card/index.jsx
+++ b/src/menu/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 { Popover, Modal, Pagination } from 'antd'
+import { Popover, Modal, Pagination, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -254,7 +254,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -513,7 +513,15 @@
         {card.setting.laypage === 'true' && card.wrap.pagestyle === 'more' ? <div className="mk-more">鏌ョ湅鏇村<DownOutlined/></div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/carousel/data-card/index.jsx b/src/menu/components/carousel/data-card/index.jsx
index dceb119..5a1eee0 100644
--- a/src/menu/components/carousel/data-card/index.jsx
+++ b/src/menu/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 { Popover, Modal } from 'antd'
+import { Popover, Modal, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -268,7 +268,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/carousel/data-card/options.jsx b/src/menu/components/carousel/data-card/options.jsx
index e6ac38e..8c6e414 100644
--- a/src/menu/components/carousel/data-card/options.jsx
+++ b/src/menu/components/carousel/data-card/options.jsx
@@ -79,6 +79,7 @@
       field: 'modalContent',
       label: '寮圭獥鍐呭',
       initval: wrap.modalContent || 'message',
+      tooltip: '浣跨敤绯荤粺鏇存柊鏃讹紝濡傛灉杩斿洖鍊肩殑ErrCode涓�-1锛屽彧浼氬仛绯荤粺閰嶇疆鏇存柊涓嶄細鏄剧ず寮圭獥銆傛敞锛氭暟鎹簮浣跨敤鍚屾鏌ヨ鏃舵棤鏁堛��',
       required: false,
       options: [
         {value: 'message', label: '娑堟伅鎻愰啋'},
diff --git a/src/menu/components/carousel/prop-card/index.jsx b/src/menu/components/carousel/prop-card/index.jsx
index 8efdbe0..9b25463 100644
--- a/src/menu/components/carousel/prop-card/index.jsx
+++ b/src/menu/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 { Popover, Modal, Carousel } from 'antd'
+import { Popover, Modal, Carousel, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, ClockCircleOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -338,7 +338,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-G6/index.jsx b/src/menu/components/chart/antv-G6/index.jsx
index 82d8bf3..81c0e09 100644
--- a/src/menu/components/chart/antv-G6/index.jsx
+++ b/src/menu/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 { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import G6 from '@antv/g6'
 
@@ -1424,7 +1424,15 @@
         <div className="canvas" id={card.uuid + 'canvas'} ref={ref => this.wrap = ref}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-bar/chartcompile/index.jsx b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
index 7feda4a..f0bfcc6 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
-import { QuestionCircleOutlined, EditOutlined } from '@ant-design/icons'
+import { QuestionCircleOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'
 
 import Utils from '@/utils/utils.js'
 import { chartColors } from '@/utils/option.js'
@@ -44,6 +44,18 @@
         inputType: 'color',
         editable: true,
         width: '40%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
+    barColorColumns: [
+      {
+        title: '棰滆壊',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '70%',
         render: (text, record) => {
           return (<div style={{width: '80px', height: '23px', background: text}}></div>)
         }
@@ -745,10 +757,28 @@
     this.setState({plot})
   }
 
+  addbarColor = () => {
+    let plot = fromJS(this.state.plot).toJS()
+    plot.barcolors = plot.barcolors || []
+
+    plot.barcolors.push({
+      uuid: Utils.getuuid(),
+      color: 'rgb(91, 143, 249)'
+    })
+
+    this.setState({plot})
+  }
+
   changeColor = (colors) => {
     const { plot } = this.state
 
     this.setState({plot: {...plot, colors}})
+  }
+
+  changebarColor = (colors) => {
+    const { plot } = this.state
+
+    this.setState({plot: {...plot, barcolors: colors}})
   }
 
   changeCustom = (customs) => {
@@ -759,7 +789,7 @@
 
   render() {
     const { config } = this.props
-    const { view, visible, datatype, plot, ramp, colorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist } = this.state
+    const { view, visible, datatype, plot, ramp, colorColumns, barColorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -818,9 +848,14 @@
                 {datatype === 'statistics' ? <Button className="color-add mk-green" onClick={this.addColor}>娣诲姞</Button> : null}
                 {datatype === 'statistics' ? <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={ramp ==='true' ? rampStatColorColumns : statColorColumns} onChange={this.changeColor}/> : null}
                 {datatype !== 'statistics' ? <EditTable actions={['edit']} data={plot.colors || []} columns={ramp ==='true' ? rampColorColumns : colorColumns} onChange={this.changeColor}/> : null}
+                {plot.chartType === 'bar' && plot.datatype === 'query' ? <div className="mk-bar-colors">
+                  <p>鏌卞舰棰滆壊锛氬彲鏍规嵁鏌卞浘搴忓彿璁剧疆棰滆壊锛堣璁剧疆鏌卞舰瀹藉害锛夈�傛敞锛氫娇鐢ㄨ嚜瀹氫箟鍥惧舰璁剧疆鎴栧鏍规煴鍥炬椂鏃犳晥銆�</p>
+                  <div className="bar-color-add"><PlusOutlined onClick={this.addbarColor}/></div>
+                  <EditTable actions={['edit', 'move', 'del']} data={plot.barcolors || []} columns={barColorColumns} onChange={this.changebarColor}/>
+                </div> : null}
               </div>
             </TabPane> : null}
-            {plot ? <TabPane tab="鑷畾涔夎缃�" disabled={datatype === 'statistics'} key="custom">
+            {plot ? <TabPane tab="鑷畾涔夊浘褰㈣缃�" disabled={datatype === 'statistics'} key="custom">
               <Col span={12}>
                 <Form {...formItemLayout}>
                   <Form.Item label="鏄惁鍚敤" style={{marginBottom: 10}}>
diff --git a/src/menu/components/chart/antv-bar/chartcompile/index.scss b/src/menu/components/chart/antv-bar/chartcompile/index.scss
index abcff08..4fe430a 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/index.scss
+++ b/src/menu/components/chart/antv-bar/chartcompile/index.scss
@@ -22,6 +22,17 @@
   .ant-table-column-title {
     white-space: nowrap;
   }
+  .mk-bar-colors {
+    padding-top: 30px;
+
+    .bar-color-add {
+      text-align: right;
+      color: #26C281;
+      font-size: 24px;
+      padding-right: 10px;
+      margin-top: -40px;
+    }
+  }
 }
 
 
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 082b5fa..8f865eb 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/src/menu/components/chart/antv-bar/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, message } from 'antd'
 import { PlusCircleOutlined, PlusSquareOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 import DataSet from '@antv/data-set'
@@ -1384,7 +1384,15 @@
         /> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-dashboard/index.jsx b/src/menu/components/chart/antv-dashboard/index.jsx
index 33c7c2e..b66d1d3 100644
--- a/src/menu/components/chart/antv-dashboard/index.jsx
+++ b/src/menu/components/chart/antv-dashboard/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, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import { Chart, registerShape } from '@antv/g2'
 
@@ -553,7 +553,15 @@
         <div className="canvas" id={card.uuid + 'dashboard'}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index a7e3f8a..3f269b4 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/src/menu/components/chart/antv-pie/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, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined, PlusCircleOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 import DataSet, { DataView } from '@antv/data-set'
@@ -727,7 +727,15 @@
         <div className="canvas" id={card.uuid + 'canvas'}></div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/chart/antv-scatter/index.jsx b/src/menu/components/chart/antv-scatter/index.jsx
index 2534961..79b4684 100644
--- a/src/menu/components/chart/antv-scatter/index.jsx
+++ b/src/menu/components/chart/antv-scatter/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, message } from 'antd'
 import { ToolOutlined, DeleteOutlined, FontColorsOutlined, PlusCircleOutlined, PlusSquareOutlined } from '@ant-design/icons'
 import { Chart } from '@antv/g2'
 
@@ -399,7 +399,15 @@
         {appType !== 'mob' ? <ActionComponent config={card} updateaction={this.updateComponent}/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/code/sandbox/index.jsx b/src/menu/components/code/sandbox/index.jsx
index d633dd7..cced2c3 100644
--- a/src/menu/components/code/sandbox/index.jsx
+++ b/src/menu/components/code/sandbox/index.jsx
@@ -128,7 +128,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
diff --git a/src/menu/components/editor/braft-editor/index.jsx b/src/menu/components/editor/braft-editor/index.jsx
index b032aec..444a206 100644
--- a/src/menu/components/editor/braft-editor/index.jsx
+++ b/src/menu/components/editor/braft-editor/index.jsx
@@ -46,7 +46,7 @@
         name: card.name,
         subtype: card.subtype,
         setting: { interType: 'system' },
-        wrap: { name: card.name, datatype: 'dynamic', width: card.width || 24, encryption: 'true', minHeight: 100 },
+        wrap: { name: card.name, datatype: 'dynamic', width: card.width || 24, encryption: 'true' },
         style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
         headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
         columns: [],
@@ -76,6 +76,10 @@
     }
   }
 
+  componentDidMount() {
+    MKEmitter.addListener('mkUpdateInter', this.mkUpdateInter)
+  }
+
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.state), fromJS(nextState))
   }
@@ -86,6 +90,21 @@
   componentWillUnmount () {
     this.setState = () => {
       return
+    }
+    MKEmitter.removeListener('mkUpdateInter', this.mkUpdateInter)
+  }
+
+  mkUpdateInter = (inter, split) => {
+    const { card } = this.state
+    
+    if (card.wrap.datatype === 'public' && card.wrap.publicId === inter.uuid) {
+      let _card = {...card, columns: fromJS(inter.columns).toJS()}
+
+      split.delay = split.delay + 10
+
+      setTimeout(() => {
+        this.updateComponent(_card)
+      }, split.delay)
     }
   }
 
@@ -128,7 +147,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -144,7 +163,21 @@
   }
 
   updateWrap = (res) => {
-    this.updateComponent({...this.state.card, wrap: res})
+    const { card } = this.state
+
+    let _card = {...card, wrap: res}
+
+    if (res.datatype === 'public') {
+      let interfaces = window.GLOB.customMenu.interfaces || []
+
+      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
+
+      if (d) {
+        _card.columns = fromJS(d.columns).toJS()
+      }
+    }
+
+    this.updateComponent(_card)
   }
 
   clickComponent = (e) => {
@@ -164,16 +197,13 @@
     const { card } = this.state
 
     let style = {...card.style}
-    if (card.wrap.minHeight) {
-      style.minHeight = card.wrap.minHeight
-    }
 
     return (
       <div className="menu-normal-editor-box" style={style} onClick={this.clickComponent} id={card.uuid}>
         <NormalHeader hideSearch="true" config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
-            <NormalForm title="瀵屾枃鏈缃�" width={700} update={this.updateWrap} getForms={this.getWrapForms}>
+            <NormalForm title="瀵屾枃鏈缃�" width={750} update={this.updateWrap} getForms={this.getWrapForms}>
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="normaltable" card={card}/>
@@ -181,8 +211,7 @@
             <UserComponent config={card}/>
             <DeleteOutlined className="close" title="鍒犻櫎缁勪欢" onClick={() => this.props.deletecomponent(card.uuid)} />
             <EditorContent config={card} updateConfig={this.updateComponent}/>
-            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
-            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
+            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/>}
           </div>
         } trigger="hover">
           <ToolOutlined />
diff --git a/src/menu/components/editor/braft-editor/options.jsx b/src/menu/components/editor/braft-editor/options.jsx
index 9e7094f..3c33098 100644
--- a/src/menu/components/editor/braft-editor/options.jsx
+++ b/src/menu/components/editor/braft-editor/options.jsx
@@ -4,6 +4,19 @@
 export default function (wrap, columns) {
   let appType = sessionStorage.getItem('appType')
   let roleList = sessionStorage.getItem('sysRoles')
+  let menu = window.GLOB.customMenu
+
+  let interfaces = []
+  if (menu.interfaces) {
+    menu.interfaces.forEach(item => {
+      if (item.status === 'true') {
+        interfaces.push({
+          value: item.uuid,
+          label: item.name
+        })
+      }
+    })
+  }
 
   if (roleList) {
     try {
@@ -52,18 +65,29 @@
       options: [
         {value: 'dynamic', label: '鍔ㄦ��'},
         {value: 'static', label: '闈欐��'},
+        {value: 'public', label: '鍏叡鏁版嵁婧�'},
       ],
       controlFields: [
-        {field: 'field', values: ['dynamic']},
-        {field: 'encryption', values: ['dynamic']},
+        {field: 'field', values: ['dynamic', 'public']},
+        {field: 'empty', values: ['dynamic', 'public']},
+        {field: 'publicId', values: ['public']},
+        {field: 'encryption', values: ['dynamic', 'public']},
       ]
+    },
+    {
+      type: 'select',
+      field: 'publicId',
+      label: '鏁版嵁婧�',
+      initval: wrap.publicId || '',
+      required: true,
+      options: interfaces
     },
     {
       type: 'select',
       field: 'field',
       label: '鏂囨湰瀛楁',
       initval: wrap.field || '',
-      tooltip: '閫夋嫨鍔ㄦ�佸�兼椂锛岄渶璁剧疆鏂囨湰瀛楁鎵嶅彲鐢熸晥銆�',
+      tooltip: '閫夋嫨鍔ㄦ�佸�兼椂锛岄渶璁剧疆鏂囨湰瀛楁鎵嶅彲鐢熸晥锛屼娇鐢ㄥ叕鍏辨暟鎹簮鏃讹紝闇�鍏堜繚瀛樻暟鎹簮鍚庡啀閫夊彇鏂囨湰瀛楁銆�',
       required: false,
       options: columns
     },
@@ -80,14 +104,17 @@
       ]
     },
     {
-      type: 'number',
-      field: 'minHeight',
-      label: '鏈�灏忛珮搴�',
-      initval: wrap.minHeight || '',
-      min: 0,
-      max: 3000,
-      precision: 0,
-      required: false
+      type: 'radio',
+      field: 'empty',
+      label: '绌哄�奸殣钘�',
+      initval: wrap.empty || 'show',
+      tooltip: '褰撴煡璇㈡暟鎹负绌烘椂锛岄殣钘忚缁勪欢銆�',
+      required: false,
+      skip: true,
+      options: [
+        {value: 'show', label: '鍚�'},
+        {value: 'hidden', label: '鏄�'},
+      ],
     },
     {
       type: 'radio',
diff --git a/src/menu/components/form/dragtitle/card.jsx b/src/menu/components/form/dragtitle/card.jsx
index 090ccd1..c8b980c 100644
--- a/src/menu/components/form/dragtitle/card.jsx
+++ b/src/menu/components/form/dragtitle/card.jsx
@@ -9,9 +9,10 @@
 import './index.scss'
 
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
+const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 
-const Card = ({ id, card, sort, active, moveCard, findCard, closeCard, selectCard, updateGroup }) => {
+const Card = ({ id, card, sort, labelSize, active, moveCard, findCard, closeCard, selectCard, updateGroup, pasteForm }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'form', id, originalIndex },
@@ -68,6 +69,10 @@
     updateGroup(_card)
   }
 
+  let style = {fontSize: labelSize}
+  let s = labelSize * 1.5 + 'px'
+  let sortStyle = {width: s, height: s, lineHeight: s, borderRadius: s}
+
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
@@ -75,12 +80,13 @@
           <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
         </NormalForm>
         <CopyComponent type="formgroup" card={card}/>
+        <PasteComponent options={['form', 'forms']} updateConfig={(res) => pasteForm(res, id)} />
         <CloseOutlined className="close" type="close" onClick={close} />
       </div>
     } trigger="hover">
       <div className={'page-card ' + (active ? 'active' : '')} onClick={select} style={{ opacity: opacity}}>
-        <div ref={node => drag(drop(node))}>
-          <span className="form-sort">{sort}</span>
+        <div ref={node => drag(drop(node))} style={style}>
+          <span className="form-sort" style={sortStyle}>{sort}</span>
           {card.setting.title}
         </div>
       </div>
diff --git a/src/menu/components/form/dragtitle/index.jsx b/src/menu/components/form/dragtitle/index.jsx
index 96a6e7f..1298f75 100644
--- a/src/menu/components/form/dragtitle/index.jsx
+++ b/src/menu/components/form/dragtitle/index.jsx
@@ -4,7 +4,7 @@
 import Card from './card'
 import './index.scss'
 
-const Container = ({list, selectId, tabtype, handleList, handleGroup, closeGroup, selectGroup}) => {
+const Container = ({list, labelSize, selectId, tabtype, handleList, handleGroup, handleForm, closeGroup, selectGroup}) => {
   const [cards, setCards] = useState(list)
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
@@ -33,6 +33,11 @@
     closeGroup(card)
   }
 
+  const pasteForm = (res, id) => {
+    const { card } = findCard(id)
+    handleForm(card, res)
+  }
+
   const selectCard = id => {
     const { card } = findCard(id)
     selectGroup(card)
@@ -45,11 +50,13 @@
           id={card.uuid}
           key={card.uuid}
           sort={i + 1}
+          labelSize={labelSize}
           active={card.uuid === selectId}
           card={card}
           moveCard={moveCard}
           closeCard={closeCard}
           updateGroup={handleGroup}
+          pasteForm={pasteForm}
           findCard={findCard}
           selectCard={selectCard}
         />
diff --git a/src/menu/components/form/dragtitle/index.scss b/src/menu/components/form/dragtitle/index.scss
index 9921c52..f1c1799 100644
--- a/src/menu/components/form/dragtitle/index.scss
+++ b/src/menu/components/form/dragtitle/index.scss
@@ -2,6 +2,10 @@
   display: flex;
   line-height: 30px;
   min-height: 50px;
+  font-weight: inherit;
+  div {
+    font-weight: inherit;
+  }
   .page-card {
     position: relative;
     flex: 1;
diff --git a/src/menu/components/form/simple-form/index.jsx b/src/menu/components/form/simple-form/index.jsx
index a6de6f5..2b1e483 100644
--- a/src/menu/components/form/simple-form/index.jsx
+++ b/src/menu/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 { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -125,6 +125,7 @@
     card.width = card.wrap.width
     card.name = card.wrap.name
     card.errors = []
+    let idCtrl = false
 
     if (card.wrap.datatype !== 'static') {
       let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -151,6 +152,9 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ叧鑱斾富琛ㄢ��${m.label}鈥濇槸鍚︽湁鏁坄})
           }
@@ -163,12 +167,17 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ叧鑱斾富琛ㄢ��${m.label}鈥濇槸鍚︽湁鏁坄})
           }
         })
       })
     }
+
+    card.idCtrl = idCtrl
 
     this.setState({
       card: card
@@ -194,7 +203,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -340,35 +349,28 @@
     let index = null
     uniq.set(_form.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     card.subcards[0].fields.forEach((item, i) => {
       if (_form.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && _item.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
       if (_form.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
       
@@ -378,19 +380,15 @@
         uniq.set(item.field, true)
 
         _linkableFields.push({
-          value: item.field,
-          text: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          field: item.field,
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
-          value: item.field,
-          text: _linkIndex + '銆�' + label
+          field: item.field,
+          label: item.label
         })
-
-        _linkIndex++
       }
     })
-
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
 
     if (index !== null) {
       if (index === 0) {
@@ -406,9 +404,8 @@
 
         _linkableFields.push({
           field: col.field,
-          label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+          label: col.label + '-鏄剧ず鍒�'
         })
-        _linkIndex++
       }
     })
 
@@ -473,7 +470,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -518,7 +515,7 @@
     let _config = fromJS(this.state.card).toJS()
 
     if (res.subButton) {
-      let _this = this
+      let that = this
 
       _config.subcards[0].setting.focus = res.focus
       _config.subcards[0].setting.cache = res.cache
@@ -539,12 +536,38 @@
       })
 
       confirm({
-        content: `鏇挎崲琛ㄥ崟鍙婃寜閽厤缃紵`,
+        content: '鏇挎崲琛ㄥ崟鍙婃寜閽厤缃紵',
         onOk() {
-          _this.updateComponent(_config)
+          that.updateComponent(_config)
         },
         onCancel() {}
       })
+      return
+    } else if (res.fields) {
+      if (_config.subcards[0].fields.length > 0) {
+        let that = this
+        _config.subcards[0].fields = res.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        confirm({
+          title: '纭畾鏇挎崲琛ㄥ崟鍚楋紵',
+          content: '鍘熻〃鍗曞皢鍒犻櫎銆�',
+          onOk() {
+            that.updateComponent(_config)
+          },
+          onCancel() {}
+        })
+      } else {
+        _config.subcards[0].fields = res.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        this.updateComponent(_config)
+      }
+
       return
     }
 
@@ -648,7 +671,7 @@
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="simpleform" card={card}/>
-            <PasteComponent config={card} options={['form', 'formgroup']} updateConfig={this.pasteForm} />
+            <PasteComponent config={card} options={['form', 'forms', 'formgroup']} updateConfig={this.pasteForm} />
             <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
             <UserComponent config={card}/>
             <DeleteOutlined className="close" title="鍒犻櫎缁勪欢" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -658,7 +681,7 @@
         } trigger="hover">
           <ToolOutlined />
         </Popover>
-        <div className="form-area">
+        <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
           <PlusOutlined className="plus" title="娣诲姞琛ㄥ崟" onClick={this.addForm}/>
           <FieldsComponent config={card.subcards[0]} type="form" plusFields={this.plusFields} />
           <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>娓呯┖</span>
@@ -687,7 +710,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/form/simple-form/index.scss b/src/menu/components/form/simple-form/index.scss
index bf874bf..5911202 100644
--- a/src/menu/components/form/simple-form/index.scss
+++ b/src/menu/components/form/simple-form/index.scss
@@ -66,6 +66,17 @@
       background-color: transparent;
     }
   }
+  // .form-area.mk-shadow {
+  //   .mob-form {
+  //     .am-list-line {
+  //       border: none!important;
+
+  //       .am-input-control {
+  //         background-color: var(--mk-sys-color1);
+  //       }
+  //     }
+  //   }
+  // }
 }
 .menu-normal-form-edit-box::after {
   display: block;
diff --git a/src/menu/components/form/simple-form/options.jsx b/src/menu/components/form/simple-form/options.jsx
index 760d969..2197555 100644
--- a/src/menu/components/form/simple-form/options.jsx
+++ b/src/menu/components/form/simple-form/options.jsx
@@ -84,6 +84,7 @@
         {value: 'static', label: '闈欐��'},
       ],
       controlFields: [
+        {field: 'empty', values: ['dynamic']},
         {field: 'supModule', values: ['static']},
       ]
     },
@@ -158,6 +159,18 @@
     },
     {
       type: 'radio',
+      field: 'formStyle',
+      label: '琛ㄥ崟鏍峰紡',
+      initval: wrap.formStyle || '',
+      required: false,
+      options: [
+        {value: '', label: '榛樿'},
+        {value: 'shadow', label: '闃村奖'},
+      ],
+      forbid: appType !== 'mob'
+    },
+    {
+      type: 'radio',
       field: 'goback',
       label: '绌哄�艰繑鍥�',
       initval: wrap.goback || 'false',
@@ -171,6 +184,19 @@
     },
     {
       type: 'radio',
+      field: 'empty',
+      label: '绌哄�奸殣钘�',
+      initval: wrap.empty || 'show',
+      tooltip: '褰撴煡璇㈡暟鎹负绌烘椂锛岄殣钘忚缁勪欢銆�',
+      required: false,
+      skip: true,
+      options: [
+        {value: 'show', label: '鍚�'},
+        {value: 'hidden', label: '鏄�'},
+      ],
+    },
+    {
+      type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
       initval: wrap.permission || 'false',
diff --git a/src/menu/components/form/step-form/index.jsx b/src/menu/components/form/step-form/index.jsx
index 55dd906..3f37ddf 100644
--- a/src/menu/components/form/step-form/index.jsx
+++ b/src/menu/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 { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -132,6 +132,7 @@
     card.width = card.wrap.width
     card.name = card.wrap.name
     card.errors = []
+    let idCtrl = false
 
     if (card.wrap.datatype !== 'static') {
       let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -158,6 +159,9 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ垎缁勨��${item.setting.title}鈥濅腑鍏宠仈涓昏〃鈥�${m.label}鈥濇槸鍚︽湁鏁坄})
           }
@@ -170,12 +174,17 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ垎缁勨��${item.setting.title}鈥濅腑鍏宠仈涓昏〃鈥�${m.label}鈥濇槸鍚︽湁鏁坄})
           }
         })
       })
     }
+
+    card.idCtrl = idCtrl
 
     this.setState({
       card: card
@@ -201,7 +210,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -441,36 +450,29 @@
     let index = null
     uniq.set(_form.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     group.fields.forEach((item, i) => {
       if (_form.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && _item.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
 
       if (_item.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
       
@@ -481,17 +483,14 @@
 
         _linkableFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
-        _linkIndex++
       }
     })
-
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
 
     if (index !== null) {
       if (index === 0) {
@@ -507,9 +506,8 @@
 
         _linkableFields.push({
           field: col.field,
-          label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+          label: col.label + '-鏄剧ず鍒�'
         })
-        _linkIndex++
       }
     })
 
@@ -574,7 +572,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -699,6 +697,98 @@
     this.updateComponent(_card)
   }
 
+  clearGroup = () => {
+    let group = fromJS(this.state.group).toJS()
+    let card = fromJS(this.state.card).toJS()
+    let _this = this
+
+    group.fields = []
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === group.uuid) {
+        return group
+      }
+      return item
+    })
+
+    confirm({
+      content: `纭畾娓呯┖琛ㄥ崟鍚楋紵`,
+      onOk() {
+        _this.setState({group})
+        _this.updateComponent(card)
+      },
+      onCancel() {}
+    })
+  }
+
+  parseForm = (g, res) => {
+    let _group = fromJS(g).toJS()
+    let _confirm = false
+
+    if (res.copyType === 'form') {
+      let fieldrepet = false // 瀛楁閲嶅
+      res.uuid = Utils.getuuid()
+  
+      _group.fields.forEach(item => {
+        if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
+          fieldrepet = true
+        }
+      })
+  
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁宸插瓨鍦紒',
+          duration: 10
+        })
+        return
+      }
+      _group.fields.push(res)
+    } else {
+      if (_group.fields.length > 0) {
+        _confirm = true
+      }
+
+      _group.fields = res.fields.map(item => {
+        item.uuid = Utils.getuuid()
+        return item
+      })
+    }
+
+    if (_confirm) {
+      let that = this
+      confirm({
+        title: '纭畾鏇挎崲琛ㄥ崟鍚楋紵',
+        content: '鍘熻〃鍗曞皢鍒犻櫎銆�',
+        onOk() {
+          that.updateForms(_group)
+        },
+        onCancel() {}
+      })
+    } else {
+      this.updateForms(_group)
+    }
+  }
+
+  updateForms = (_group) => {
+    const { group } = this.state
+    let card = fromJS(this.state.card).toJS()
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === _group.uuid) {
+        return _group
+      }
+      return item
+    })
+
+    if (_group.uuid === group.uuid) {
+      this.setState({group: _group})
+      this.updateComponent(card)
+    } else {
+      this.updateComponent(card)
+    }
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -714,6 +804,11 @@
 
   render() {
     const { card, group, appType } = this.state
+
+    let labelSize = 14
+    if (card.style.fontSize) {
+      labelSize = parseInt(card.style.fontSize)
+    }
 
     return (
       <div className="menu-normal-form-edit-box" style={resetStyle(card.style)} onClick={this.clickComponent} id={card.uuid}>
@@ -736,15 +831,18 @@
         </Popover>
         <FormTitle
           list={card.subcards}
+          labelSize={labelSize}
           selectId={group ? group.uuid : ''}
           handleList={this.changecards}
           handleGroup={this.changeGroup}
+          handleForm={this.parseForm}
           closeGroup={this.closeGroup}
           selectGroup={this.selectGroup}
         />
-        {group ? <div className="form-area">
+        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
           <PlusOutlined className="plus" title="娣诲姞琛ㄥ崟" onClick={this.addForm}/>
           <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
+          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>娓呯┖</span>
           <Switch checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
           {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1鍒�</Button> : null}
           {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2鍒�</Button> : null}
@@ -770,7 +868,15 @@
         </div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/form/step-form/index.scss b/src/menu/components/form/step-form/index.scss
index 8ca4c7c..40539f2 100644
--- a/src/menu/components/form/step-form/index.scss
+++ b/src/menu/components/form/step-form/index.scss
@@ -15,6 +15,7 @@
     top: 1px;
     cursor: pointer;
     padding: 5px;
+    color: rgba(0, 0, 0, 0.65);
     background: rgba(255, 255, 255, 0.55);
   }
 
@@ -25,6 +26,7 @@
   }
   .form-area {
     position: relative;
+    font-size: 14px;
     .page-card {
       background: transparent;
     }
diff --git a/src/menu/components/form/step-form/options.jsx b/src/menu/components/form/step-form/options.jsx
index 48f3daf..dae0a31 100644
--- a/src/menu/components/form/step-form/options.jsx
+++ b/src/menu/components/form/step-form/options.jsx
@@ -61,6 +61,7 @@
         {value: 'static', label: '闈欐��'},
       ],
       controlFields: [
+        {field: 'empty', values: ['dynamic']},
         {field: 'supModule', values: ['static']},
       ]
     },
@@ -84,8 +85,22 @@
       options: [
         {value: 'show', label: '鏄剧ず'},
         {value: 'hidden', label: '闅愯棌'},
-      ]
+      ],
+      // controlFields: [
+      //   {field: 'labelSize', values: ['show']},
+      // ]
     },
+    // {
+    //   type: 'number',
+    //   field: 'labelSize',
+    //   label: '鍚嶇О澶у皬',
+    //   initval: wrap.labelSize || '',
+    //   tooltip: '鍒嗙粍鍚嶇О瀛椾綋澶у皬銆�',
+    //   min: 12,
+    //   max: 50,
+    //   precision: 0,
+    //   required: false
+    // },
     {
       type: 'radio',
       field: 'tabtype',
@@ -109,6 +124,18 @@
     },
     {
       type: 'radio',
+      field: 'formStyle',
+      label: '琛ㄥ崟鏍峰紡',
+      initval: wrap.formStyle || '',
+      required: false,
+      options: [
+        {value: '', label: '榛樿'},
+        {value: 'shadow', label: '闃村奖'},
+      ],
+      forbid: appType !== 'mob'
+    },
+    {
+      type: 'radio',
       field: 'goback',
       label: '绌哄�艰繑鍥�',
       initval: wrap.goback || 'false',
@@ -122,6 +149,19 @@
     },
     {
       type: 'radio',
+      field: 'empty',
+      label: '绌哄�奸殣钘�',
+      initval: wrap.empty || 'show',
+      tooltip: '褰撴煡璇㈡暟鎹负绌烘椂锛岄殣钘忚缁勪欢銆�',
+      required: false,
+      skip: true,
+      options: [
+        {value: 'show', label: '鍚�'},
+        {value: 'hidden', label: '鏄�'},
+      ],
+    },
+    {
+      type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
       initval: wrap.permission || 'false',
diff --git a/src/menu/components/form/tab-form/index.jsx b/src/menu/components/form/tab-form/index.jsx
index a354870..65b84aa 100644
--- a/src/menu/components/form/tab-form/index.jsx
+++ b/src/menu/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 { Popover, Modal, Button, Switch, notification } from 'antd'
+import { Popover, Modal, Button, Switch, notification, message } from 'antd'
 import { PlusOutlined, SettingOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -144,6 +144,7 @@
     card.width = card.wrap.width
     card.name = card.wrap.name
     card.errors = []
+    let idCtrl = false
 
     if (card.wrap.datatype !== 'static') {
       let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -170,6 +171,9 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ垎缁勨��${item.setting.title}鈥濅腑鍏宠仈涓昏〃鈥�${m.label}鈥濇槸鍚︽湁鏁坄})
           }
@@ -182,12 +186,17 @@
 
       card.subcards.forEach(item => {
         item.fields.forEach(m => {
+          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
+            idCtrl = true
+          }
           if (m.type === 'linkMain' && !supModule) {
             card.errors.push({ level: 1, detail: `璇锋鏌ュ垎缁勨��${item.setting.title}鈥濅腑鍏宠仈涓昏〃鈥�${m.label}鈥濇槸鍚︽湁鏁坄})
           }
         })
       })
     }
+
+    card.idCtrl = idCtrl
 
     this.setState({
       card: card
@@ -213,7 +222,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -447,35 +456,28 @@
     let index = null
     uniq.set(_form.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     group.fields.forEach((item, i) => {
       if (_form.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && _item.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
       if (_form.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
       
@@ -485,19 +487,15 @@
         uniq.set(item.field, true)
 
         _linkableFields.push({
-          value: item.field,
-          text: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          field: item.field,
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
-          value: item.field,
-          text: _linkIndex + '銆�' + label
+          field: item.field,
+          label: item.label
         })
-
-        _linkIndex++
       }
     })
-
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
 
     if (index !== null) {
       if (index === 0) {
@@ -513,9 +511,8 @@
 
         _linkableFields.push({
           field: col.field,
-          label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+          label: col.label + '-鏄剧ず鍒�'
         })
-        _linkIndex++
       }
     })
 
@@ -580,7 +577,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -725,6 +722,74 @@
     })
   }
 
+  parseForm = (g, res) => {
+    let _group = fromJS(g).toJS()
+    let _confirm = false
+
+    if (res.copyType === 'form') {
+      let fieldrepet = false // 瀛楁閲嶅
+      res.uuid = Utils.getuuid()
+  
+      _group.fields.forEach(item => {
+        if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
+          fieldrepet = true
+        }
+      })
+  
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁宸插瓨鍦紒',
+          duration: 10
+        })
+        return
+      }
+      _group.fields.push(res)
+    } else {
+      if (_group.fields.length > 0) {
+        _confirm = true
+      }
+
+      _group.fields = res.fields.map(item => {
+        item.uuid = Utils.getuuid()
+        return item
+      })
+    }
+
+    if (_confirm) {
+      let that = this
+      confirm({
+        title: '纭畾鏇挎崲琛ㄥ崟鍚楋紵',
+        content: '鍘熻〃鍗曞皢鍒犻櫎銆�',
+        onOk() {
+          that.updateForms(_group)
+        },
+        onCancel() {}
+      })
+    } else {
+      this.updateForms(_group)
+    }
+  }
+
+  updateForms = (_group) => {
+    const { group } = this.state
+    let card = fromJS(this.state.card).toJS()
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === _group.uuid) {
+        return _group
+      }
+      return item
+    })
+
+    if (_group.uuid === group.uuid) {
+      this.setState({group: _group})
+      this.updateComponent(card)
+    } else {
+      this.updateComponent(card)
+    }
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -740,6 +805,11 @@
 
   render() {
     const { card, group, appType } = this.state
+
+    let labelSize = 14
+    if (card.style.fontSize) {
+      labelSize = parseInt(card.style.fontSize)
+    }
 
     return (
       <div className="menu-normal-form-edit-box" style={resetStyle(card.style)} onClick={this.clickComponent} id={card.uuid}>
@@ -762,14 +832,16 @@
         </Popover>
         <FormTitle
           list={card.subcards}
+          labelSize={labelSize}
           tabtype={card.wrap.tabtype || ''}
           selectId={group ? group.uuid : ''}
           handleList={this.changecards}
           handleGroup={this.updateGroup}
+          handleForm={this.parseForm}
           closeGroup={this.closeGroup}
           selectGroup={this.selectGroup}
         />
-        {group ? <div className="form-area">
+        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
           <PlusOutlined className="plus" title="娣诲姞琛ㄥ崟" onClick={this.addForm}/>
           <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
           <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>娓呯┖</span>
@@ -798,7 +870,15 @@
         </div> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/form/tab-form/index.scss b/src/menu/components/form/tab-form/index.scss
index 8ca4c7c..ffb7696 100644
--- a/src/menu/components/form/tab-form/index.scss
+++ b/src/menu/components/form/tab-form/index.scss
@@ -25,6 +25,7 @@
   }
   .form-area {
     position: relative;
+    font-size: 14px;
     .page-card {
       background: transparent;
     }
diff --git a/src/menu/components/group/groupcomponents/card.jsx b/src/menu/components/group/groupcomponents/card.jsx
index 2c62e1e..7dbdbb0 100644
--- a/src/menu/components/group/groupcomponents/card.jsx
+++ b/src/menu/components/group/groupcomponents/card.jsx
@@ -25,6 +25,7 @@
 const CustomChart = asyncComponent(() => import('@/menu/components/chart/chart-custom'))
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -88,6 +89,8 @@
       return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
diff --git a/src/menu/components/group/normal-group/index.jsx b/src/menu/components/group/normal-group/index.jsx
index 0544f9d..b635bea 100644
--- a/src/menu/components/group/normal-group/index.jsx
+++ b/src/menu/components/group/normal-group/index.jsx
@@ -1,8 +1,8 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Button } from 'antd'
-import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, PrinterOutlined } from '@ant-design/icons'
+import { Popover, Button, Modal } from 'antd'
+import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, PrinterOutlined, UngroupOutlined } from '@ant-design/icons'
 
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
@@ -11,6 +11,7 @@
 import getSettingForm from './options'
 import './index.scss'
 
+const { confirm } = Modal
 const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
@@ -21,6 +22,7 @@
   static propTpyes = {
     group: PropTypes.object,
     deletecomponent: PropTypes.func,
+    unGroup: PropTypes.func,
     updateConfig: PropTypes.func,
   }
 
@@ -70,7 +72,7 @@
   changeStyle = () => {
     const { group } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], group.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], group.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -129,6 +131,36 @@
     this.updateComponent(group)
   }
 
+  unGroup = () => {
+    const { group } = this.state
+
+    if (group.components.length === 0) return
+
+    const _this = this
+    confirm({
+      title: '纭畾閲婃斁鍒嗙粍鍏冪礌鍚楋紵',
+      content: '',
+      onOk() {
+        _this.props.unGroup(group.uuid)
+
+        setTimeout(() => {
+          _this.updataGroup()
+        }, 10)
+      },
+      onCancel() {}
+    })
+  }
+
+  updataGroup = () => {
+    const { group } = this.props
+
+    if (group.components.length === 0) {
+      this.setState({
+        group: fromJS(group).toJS()
+      })
+    }
+  }
+
   render() {
     const { group } = this.state
     let _style = resetStyle(group.style)
@@ -147,6 +179,7 @@
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="tabs" card={group}/>
+            <UngroupOutlined title="閲婃斁" style={group.components.length > 0 ? {color: '#32c5d2'} : {color: '#eeeeee', cursor: 'not-allowed'}} onClick={this.unGroup}/>
             <PasteComponent insert={this.insert} />
             <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
             <DeleteOutlined className="close" title="delete" onClick={() => this.props.deletecomponent(group.uuid)} />
diff --git a/src/menu/components/group/paste/index.jsx b/src/menu/components/group/paste/index.jsx
index 05b5104..77f15d1 100644
--- a/src/menu/components/group/paste/index.jsx
+++ b/src/menu/components/group/paste/index.jsx
@@ -18,10 +18,6 @@
     visible: false
   }
 
-  handleMenuClick = () => {
-    this.setState({visible: true})
-  }
-
   pasteSubmit = () => {
     let appType = sessionStorage.getItem('appType')
     let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
diff --git a/src/menu/components/iframe/index.jsx b/src/menu/components/iframe/index.jsx
index 53645e2..d0f2d38 100644
--- a/src/menu/components/iframe/index.jsx
+++ b/src/menu/components/iframe/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Input } from 'antd'
+import { Popover, Input, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, SettingOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -173,7 +173,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/module/account/options.jsx b/src/menu/components/module/account/options.jsx
index 9d027e8..8faa66c 100644
--- a/src/menu/components/module/account/options.jsx
+++ b/src/menu/components/module/account/options.jsx
@@ -35,13 +35,27 @@
     },
     {
       type: 'radio',
+      field: 'readonly',
+      label: '鍙',
+      initval: wrap.readonly || 'false',
+      required: true,
+      options: [
+        {value: 'false', label: '鍚�'},
+        {value: 'true', label: '鏄�'},
+      ],
+      controlFields: [
+        {field: 'addable', values: ['false']},
+      ]
+    },
+    {
+      type: 'radio',
       field: 'addable',
       label: '鍙柊澧�',
       initval: wrap.addable || 'false',
       required: true,
       options: [
-        {value: 'true', label: '鏄�'},
         {value: 'false', label: '鍚�'},
+        {value: 'true', label: '鏄�'},
       ],
       controlFields: [
         {field: 'linkmenu', values: ['true']},
diff --git a/src/menu/components/module/voucher/index.jsx b/src/menu/components/module/voucher/index.jsx
index def62fe..beb0972 100644
--- a/src/menu/components/module/voucher/index.jsx
+++ b/src/menu/components/module/voucher/index.jsx
@@ -39,7 +39,7 @@
         name: '鍑瘉',
         subtype: card.subtype,
         // setting: { interType: 'system' },
-        wrap: { name: '鍑瘉', title: '', width: card.width || 12, type: 'edit' },
+        wrap: { name: '鍑瘉', title: '', width: card.width || 12, type: 'createVoucher', space: 30 },
         style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px', paddingBottom: '20px' },
         headerStyle: {},
         columns: [],
@@ -84,7 +84,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -101,7 +101,6 @@
 
   updateWrap = (res) => {
     let _card = {...this.state.card, wrap: res}
-    _card.switchable = res.type !== 'edit'
 
     this.updateComponent(_card)
   }
@@ -123,31 +122,48 @@
           <ToolOutlined />
         </Popover>
         <div className="voucher-box">
-          <div className="voucher-header">
-            <Button className="add-background header-btn">鏂板</Button>
+          {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="system-background header-btn">瀵煎叆</Button>
-            <Button className="out-background header-btn">瀵煎嚭</Button>
+            <Button className="out-background header-btn">鏇村</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>
+          </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">
+              <div className="voucher-code">
+                <div>璁�<DownOutlined/></div>
+                <div>1</div>
+                鍙�
+              </div>
+              <div className="voucher-date">
+                鏃ユ湡锛�<div>璇烽�夋嫨鏃ユ湡 <CalendarOutlined /></div>
+              </div>
+              <div className="voucher-affix">
+                闄勫崟鎹� <div>2</div> 寮�
+                <Button type="link" className="">闄勪欢</Button>
+                <Button type="link" className="">澶囨敞</Button>
+              </div>
+            </div> : null}
+            {card.wrap.type === 'createTemp' || card.wrap.type === 'checkTemp' ? <div className="pre-wrap">
+              <div className="temp-code">
+                妯℃澘鍚嶇О:
+                <div>&nbsp;</div>
+              </div>
+              <div className="temp-code">
+                妯℃澘绫诲瀷:
+                <div>鏃ュ父鏀嚭<DownOutlined/></div>
+              </div>
+              <Button className="out-background header-btn">鍏抽棴</Button>
+              <Button className="add-background header-btn">淇濆瓨</Button>
+            </div> : null}
+            <VoucherTable config={card}/>
+            {card.wrap.type === 'createVoucher' || card.wrap.type === 'checkVoucher' ? <div className="user">鍒跺崟浜猴細</div> : null}
           </div>
-          <div className="voucher-body">
-          <div className="pre-wrap">
-            <div className="voucher-code">
-              <div>璁�<DownOutlined/></div>
-              <div>1</div>
-              鍙�
-            </div>
-            <div className="voucher-date">
-              鏃ユ湡锛�<div>璇烽�夋嫨鏃ユ湡 <CalendarOutlined /></div>
-            </div>
-            <div className="voucher-affix">
-              闄勫崟鎹� <div>2</div> 寮�
-              <Button type="link" className="">闄勪欢</Button>
-              <Button type="link" className="">澶囨敞</Button>
-            </div>
-          </div>
-          <VoucherTable config={card}/>
-        </div>
         </div>
       </div>
     )
diff --git a/src/menu/components/module/voucher/index.scss b/src/menu/components/module/voucher/index.scss
index c7def70..f7b22db 100644
--- a/src/menu/components/module/voucher/index.scss
+++ b/src/menu/components/module/voucher/index.scss
@@ -7,6 +7,7 @@
   background-size: cover;
   min-height: 150px;
   overflow-y: auto;
+  overflow-x: hidden;
 
   .anticon-tool {
     position: absolute;
@@ -30,7 +31,6 @@
     }
   }
   .voucher-body {
-    padding: 0 15px;
     .voucher-code {
       display: inline-block;
       width: 160px;
@@ -52,6 +52,33 @@
           margin-left: 5px;
         }
       }
+    }
+    .temp-code {
+      display: inline-block;
+      width: 180px;
+      margin-right: 15px;
+      
+      div {
+        display: inline-block;
+        min-width: 100px;
+        margin-right: 10px;
+        margin-left: 10px;
+        border: 1px solid #d9d9d9;
+        padding: 4px 10px;
+        border-radius: 4px;
+
+        .anticon-down {
+          position: relative;
+          left: 3px;
+          color: #c8c8c8;
+          font-size: 12px;
+          margin-left: 5px;
+        }
+      }
+    }
+    .header-btn {
+      float: right;
+      margin-left: 10px;
     }
     .pre-wrap {
       padding: 10px 0px;
@@ -87,6 +114,9 @@
         border-radius: 4px;
       }
     }
+    .user {
+      padding-top: 15px;
+    }
   }
 
   .add-background {
diff --git a/src/menu/components/module/voucher/options.jsx b/src/menu/components/module/voucher/options.jsx
index 343594e..bd1bee2 100644
--- a/src/menu/components/module/voucher/options.jsx
+++ b/src/menu/components/module/voucher/options.jsx
@@ -29,14 +29,24 @@
     //   required: false
     // },
     {
-      type: 'radio',
+      type: 'select',
       field: 'type',
       label: '绫诲瀷',
-      initval: wrap.type || 'edit',
+      initval: wrap.type || 'createVoucher',
       required: true,
       options: [
-        {value: 'edit', label: '缂栬緫'},
-        {value: 'check', label: '鏌ョ湅'},
+        {value: 'createVoucher', label: '鏂板鍑瘉'},
+        {value: 'checkVoucher', label: '鏌ョ湅鍑瘉'},
+        {value: 'createTemp', label: '鏂板妯℃澘'},
+        {value: 'checkTemp', label: '缂栬緫妯℃澘'},
+      ],
+      controlFields: [
+        {field: 'businessType', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherType', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherTypeText', values: ['createVoucher', 'checkVoucher']},
+        {field: 'voucherSign', values: ['createVoucher', 'checkVoucher']},
+        {field: 'supModule', values: ['checkTemp', 'checkVoucher']},
+        {field: 'attachStatus', values: ['createVoucher', 'checkVoucher']},
       ]
     },
     {
@@ -68,6 +78,34 @@
       allowClear: true
     },
     {
+      type: 'text',
+      field: 'businessType',
+      label: '涓氬姟绫诲瀷',
+      initval: wrap.businessType || 'fcc01',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherType',
+      label: '鍑瘉绫诲瀷',
+      initval: wrap.voucherType || 'fcc_keeping',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherTypeText',
+      label: '鍑瘉绫诲瀷鏂囨湰',
+      initval: wrap.voucherTypeText || '璁拌处鍑瘉',
+      required: true
+    },
+    {
+      type: 'text',
+      field: 'voucherSign',
+      label: '鍑瘉绫诲瀷鏍囪瘑',
+      initval: wrap.voucherSign || 'fcc_keeping',
+      required: true
+    },
+    {
       type: 'cascader',
       field: 'supModule',
       label: '涓婄骇缁勪欢',
@@ -76,6 +114,26 @@
       options: modules,
       allowClear: true,
     },
+    {
+      type: 'radio',
+      field: 'attachStatus',
+      label: '闄勪欢鐘舵��',
+      initval: wrap.attachStatus || 0,
+      tooltip: '娣诲姞鎴栦慨鏀瑰嚟璇佹椂锛屼笂浼犻檮浠剁殑鐘舵�併��',
+      required: true,
+      options: [
+        {value: 0, label: '寰呭鏍�'},
+        {value: 10, label: '宸插鏍�'},
+      ]
+    },
+    {
+      type: 'number',
+      field: 'space',
+      label: '鐣欑櫧',
+      initval: wrap.space || 0,
+      tooltip: '琛ㄦ牸涓讳綋閮ㄥ垎涓ょ鐨勭┖鐧借窛绂伙紝琛ㄦ牸鍦ㄧ紪杈戞椂涓ょ浼氭湁娣诲姞鍜屽垹闄ゅ浘鏍囥��',
+      required: false
+    },
   ]
 
   return wrapForm
diff --git a/src/menu/components/search/main-search/dragsearch/index.jsx b/src/menu/components/search/main-search/dragsearch/index.jsx
index 5da648f..c290b29 100644
--- a/src/menu/components/search/main-search/dragsearch/index.jsx
+++ b/src/menu/components/search/main-search/dragsearch/index.jsx
@@ -135,6 +135,10 @@
 
   let labelwidth = setting.searchLwidth !== undefined ? setting.searchLwidth : 33.3
   let advanceType = setting.advanceType || 'modal'
+  let style = {}
+  if (setting.borderRadius) {
+    style.borderRadius = setting.borderRadius
+  }
 
   return (
     <div ref={drop} className="ant-row">
@@ -161,8 +165,8 @@
         <div className="ant-row ant-form-item" style={{lineHeight: '40px', height: '55px', marginBottom: 0}}>
         <div className="ant-col ant-form-item-label" style={{width: labelwidth + '%'}}></div>
           <div className="ant-col ant-form-item-control-wrapper" style={{whiteSpace: 'nowrap'}}>
-            <Button type="primary">鎼滅储</Button>
-            <Button style={{ marginLeft: 8 }}>閲嶇疆</Button>
+            <Button style={style} type="primary">鎼滅储</Button>
+            <Button style={{ marginLeft: 8, ...style }}>閲嶇疆</Button>
             <div style={{position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}}></div>
           </div>
         </div>
diff --git a/src/menu/components/search/main-search/index.jsx b/src/menu/components/search/main-search/index.jsx
index 8407229..fe83c62 100644
--- a/src/menu/components/search/main-search/index.jsx
+++ b/src/menu/components/search/main-search/index.jsx
@@ -1,7 +1,7 @@
 import React, { Component } from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Modal, notification, Popover, Switch } from 'antd'
+import { Modal, notification, Popover, Switch, message } from 'antd'
 import { PlusOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 import moment from 'moment'
 
@@ -413,7 +413,17 @@
         } trigger="hover">
           <ToolOutlined />
         </Popover>
-        <div className="component-name"><div className="center">{card.name}</div></div>
+        <div className="component-name">
+          <div className="center" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
+        </div>
         {/* 缂栬緫鎼滅储鏉′欢 */}
         <Modal
           title="鎼滅储鏉′欢-缂栬緫"
diff --git a/src/menu/components/search/main-search/options.jsx b/src/menu/components/search/main-search/options.jsx
index 880a5a7..f9324cf 100644
--- a/src/menu/components/search/main-search/options.jsx
+++ b/src/menu/components/search/main-search/options.jsx
@@ -117,9 +117,20 @@
       options: [
         {value: 'true', label: '鏄剧ず'},
         {value: 'false', label: '闅愯棌'},
+      ],
+      controlFields: [
+        {field: 'borderRadius', values: ['true']}
       ]
     },
     {
+      type: 'number',
+      field: 'borderRadius',
+      label: '鎸夐挳鍦嗚',
+      initval: wrap.borderRadius || '',
+      tooltip: '鎼滅储鍜岄噸缃寜閽殑鍦嗚銆�',
+      required: false
+    },
+    {
       type: 'radio',
       field: 'permission',
       label: '鏉冮檺楠岃瘉',
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index 5c0a14c..30473b8 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -17,7 +17,7 @@
   prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden'],
   exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hidden'],
   excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
-  excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', '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'],
   innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
@@ -214,6 +214,9 @@
       if (Ot === 'required') {
         shows.push('progress')
       }
+      if (Ot === 'required' && (intertype === 'inner' || intertype === 'system')) {
+        shows.push('execType')
+      }
       if (this.record.openmenu && this.record.openmenu !== 'goback') {
         shows.push('open')
       }
@@ -240,6 +243,8 @@
 
       if (this.record.formType === 'switch') {
         shows.push('field', 'size', 'openVal', 'closeVal', 'openText', 'closeText')
+      } else if (this.record.formType === 'counter') {
+        shows.push('field', 'size', 'min', 'max', 'decimal')
       } else if (this.record.formType === 'radio') {
         shows.push('field', 'checkType', 'openVal', 'closeVal')
       } else {
@@ -328,6 +333,7 @@
       }
     } else if (openType === 'excelOut') {
       reOptions.intertype = this.state.interTypeOptions.filter(op => op.value !== 'custom')
+      reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredOnce'].includes(op.value))
 
       if (this.record.intertype === 'outer') {
         shows.push('innerFunc', 'sysInterface', 'outerFunc')
@@ -352,6 +358,9 @@
       }
       if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
         shows.push('resetPageIndex')
+      }
+      if (this.record.Ot !== 'notRequired' && this.record.Ot !== 'requiredOnce') {
+        this.record.Ot = 'notRequired'
       }
     } else if (openType === 'popview') {
       reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
@@ -430,7 +439,7 @@
       } else if (_funcType === 'closetab') {
         shows.push('refreshTab')
       } else if (_funcType === 'scan') {
-        shows.push('linkmenu')
+        shows.push('linkmenu', 'prefix')
 
         reRequired.linkmenu = false
         reTooltip.linkmenu = '浣跨敤鎵爜鐧诲綍鍔熻兘鎴栬彍鍗曡烦杞姛鑳芥椂锛岄渶閫夋嫨璺宠浆鐨勮彍鍗曘��'
@@ -466,7 +475,7 @@
     }
     
     if (appType === 'mob') {
-      if (Ot !== 'notRequired') {
+      if (Ot !== 'notRequired' && openType !== 'excelOut') {
         shows.push('control')
         reOptions.control = [
           { value: '', text: '鏃�' },
@@ -481,7 +490,7 @@
         }
       }
     } else {
-      if (Ot !== 'notRequired') {
+      if (Ot !== 'notRequired' && openType !== 'excelOut') {
         reOptions.control = [
           { value: '', text: '鏃�' },
           { value: 'disabled', text: '绂佺敤' },
@@ -566,7 +575,8 @@
         _fieldval.label = '瀵煎嚭Excel'
         _fieldval.class = 'dgreen'
         _fieldval.execSuccess = 'never'
-        this.record.Ot = 'notRequired'
+        _fieldval.Ot = 'requiredOnce'
+        this.record.Ot = 'requiredOnce'
         this.record.label = '瀵煎嚭Excel'
         this.record.class = 'dgreen'
         this.record.execSuccess = 'never'
@@ -791,6 +801,7 @@
 
         content = <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />
       } else if (item.type === 'number') {
+        initVal = item.initVal || item.initVal === 0 ? item.initVal : ''
         rules = [
           { required: item.required, message: '璇疯緭鍏�' + item.label + '!' }
         ]
@@ -930,7 +941,7 @@
               values.icon = 'scan'
             }
           } else if (values.OpenType === 'excelOut') {
-            values.Ot = 'notRequired'
+            values.Ot = values.Ot || 'notRequired'
           } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
             if ((values.Ot === 'requiredOnce' || card.Ot === 'requiredOnce') && card.Ot !== values.Ot) {
               values.verify.uniques = []
diff --git a/src/menu/components/share/actioncomponent/dragaction/card.jsx b/src/menu/components/share/actioncomponent/dragaction/card.jsx
index 0059c8d..3163444 100644
--- a/src/menu/components/share/actioncomponent/dragaction/card.jsx
+++ b/src/menu/components/share/actioncomponent/dragaction/card.jsx
@@ -52,7 +52,7 @@
   let _style = resetStyle(card.style)
   let _class = ''
   let show = card.show
-  if (type === 'datacard') {
+  if (type === 'datacard' || type === 'dualdatacard') {
     _style = null
     _class = 'swiper swiper-' + card.color
     show = 'button'
diff --git a/src/menu/components/share/actioncomponent/dragaction/index.jsx b/src/menu/components/share/actioncomponent/dragaction/index.jsx
index 73abf27..e797df7 100644
--- a/src/menu/components/share/actioncomponent/dragaction/index.jsx
+++ b/src/menu/components/share/actioncomponent/dragaction/index.jsx
@@ -122,12 +122,13 @@
 
         if (newcard.OpenType === 'excelIn') {
           newcard.label = item.text
-          newcard.class = item.class || 'dgreen'
+          newcard.class = 'dgreen'
           newcard.Ot = 'notRequired'
         } else if (newcard.OpenType === 'excelOut') {
           newcard.label = item.text
           newcard.execSuccess = 'never'
           newcard.class = 'dgreen'
+          newcard.Ot = 'requiredOnce'
         }
 
         if (item.overIndex) {
diff --git a/src/menu/components/share/actioncomponent/formconfig.jsx b/src/menu/components/share/actioncomponent/formconfig.jsx
index ab5b23b..135daca 100644
--- a/src/menu/components/share/actioncomponent/formconfig.jsx
+++ b/src/menu/components/share/actioncomponent/formconfig.jsx
@@ -22,7 +22,7 @@
 
   if (card.eleType === 'button') {
     type = 'card'
-  } else if (config.subtype === 'datacard' || config.subtype === 'tablecard') {
+  } else if (config.subtype === 'datacard' || config.subtype === 'tablecard' || config.subtype === 'dualdatacard') {
     type = 'datacard'
   } else if (config.type === 'line' || config.type === 'bar' || config.type === 'scatter') {
     type = 'chart'
@@ -137,6 +137,7 @@
       { value: 'mkUnBinding', text: '鐢ㄦ埛瑙g粦' },
       { value: 'mkUnsubscribe', text: '娉ㄩ攢璐︽埛' },
       { value: 'reAuth', text: '鍒囨崲绯荤粺锛堟竻绌虹紦瀛�-灏忕▼搴忥級' },
+      { value: 'clearCache', text: '娓呯┖鏈湴閰嶇疆' },
       { value: 'copyurl', text: '澶嶅埗閾炬帴鍦板潃' },
       { value: 'logout', text: '閫�鍑�' },
       { value: 'goBack', text: '杩斿洖' },
@@ -265,6 +266,9 @@
       }, {
         value: 'radio',
         text: '鍕鹃�夋'
+      }, {
+        value: 'counter',
+        text: '璁℃暟鍣�'
       }, 
       ...formTypes]
     },
@@ -382,6 +386,14 @@
       required: true,
       extendName: 'MenuNo',
       options: isApp ? appMenus : menulist
+    },
+    {
+      type: 'text',
+      key: 'prefix',
+      label: '鍓嶇紑',
+      initVal: card.prefix || '',
+      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid寮�澶淬��',
+      required: false
     },
     {
       type: 'textarea',
@@ -523,7 +535,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆�',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -546,7 +558,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮��',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1017,7 +1029,7 @@
     {
       type: 'radio',
       key: 'size',
-      label: '寮�鍏冲昂瀵�',
+      label: '灏哄',
       initVal: card.size || 'default',
       options: [{
         value: 'large',
@@ -1052,6 +1064,27 @@
       required: false
     },
     {
+      type: 'number',
+      key: 'min',
+      label: '鏈�灏忓��',
+      initVal: card.min,
+      required: false
+    },
+    {
+      type: 'number',
+      key: 'max',
+      label: '鏈�澶у��',
+      initVal: card.max,
+      required: false
+    },
+    {
+      type: 'number',
+      key: 'decimal',
+      label: '灏忔暟浣�',
+      initVal: card.decimal || 0,
+      required: true
+    },
+    {
       type: 'text',
       key: 'closeVal',
       label: '鍏抽棴鍊�',
@@ -1072,6 +1105,21 @@
       label: '鍏抽棴鎻愮ず',
       initVal: card.closeText || '',
       required: false,
+    },
+    {
+      type: 'radio',
+      key: 'execType',
+      label: '璇锋眰鏂瑰紡',
+      initVal: card.execType || 'multi',
+      tooltip: '閫変腑澶氭潯鏁版嵁鏃剁殑璇锋眰鏂瑰紡锛屾敞锛氬綋閫変腑鏁版嵁瓒呰繃20鏉℃椂灏嗛�愭潯璇锋眰銆�',
+      required: false,
+      options: [{
+        value: 'multi',
+        text: '鎵归噺璇锋眰'
+      }, {
+        value: 'single',
+        text: '閫愭潯璇锋眰'
+      }]
     },
     {
       type: 'radio',
@@ -1468,7 +1516,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆�',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傛敞锛氫笂绾х粍浠跺湪鏁版嵁婧愪腑娣诲姞銆傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1490,7 +1538,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮��',
+      tooltip: refresh.length ? '鎵ц鍒锋柊婧愮粍浠舵椂锛岃鍦ㄦ簮鎸夐挳涓缃叧闂悗鍒锋柊閭d竴椤癸紝娉細姝ゆ椂浼氬悓姝ュ埛鏂板綋鍓嶇粍浠跺拰涓婄骇缁勪欢-琛屻�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��' : '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍硷紝娉細涓婄骇缁勪欢鍦ㄦ暟鎹簮涓坊鍔犮�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1804,6 +1852,21 @@
     },
     {
       type: 'radio',
+      key: 'execType',
+      label: '璇锋眰鏂瑰紡',
+      initVal: card.execType || 'multi',
+      tooltip: '閫変腑澶氭潯鏁版嵁鏃剁殑璇锋眰鏂瑰紡锛屾敞锛氬綋閫変腑鏁版嵁瓒呰繃20鏉℃椂灏嗛�愭潯璇锋眰銆�',
+      required: false,
+      options: [{
+        value: 'multi',
+        text: '鎵归噺璇锋眰'
+      }, {
+        value: 'single',
+        text: '閫愭潯璇锋眰'
+      }]
+    },
+    {
+      type: 'radio',
       key: 'progress',
       label: '杩涘害鎻愮ず',
       initVal: card.progress || 'number',
diff --git a/src/menu/components/share/markcomponent/index.jsx b/src/menu/components/share/markcomponent/index.jsx
index ae293fe..53a2a73 100644
--- a/src/menu/components/share/markcomponent/index.jsx
+++ b/src/menu/components/share/markcomponent/index.jsx
@@ -265,6 +265,9 @@
       if (item.signType && item.signType[0] === 'icon') {
         item.signType = [item.signType[0] + item.signType[1], item.signType[2], item.signType[3]]
       }
+      if (!item.uuid) {
+        item.uuid = Utils.getuuid()
+      }
       return item
     })
 
diff --git a/src/menu/components/share/pastebasetable/index.jsx b/src/menu/components/share/pastebasetable/index.jsx
index ac88559..adb2c56 100644
--- a/src/menu/components/share/pastebasetable/index.jsx
+++ b/src/menu/components/share/pastebasetable/index.jsx
@@ -19,10 +19,6 @@
     visible: false
   }
 
-  handleMenuClick = () => {
-    this.setState({visible: true})
-  }
-
   pasteSubmit = () => {
     this.pasteFormRef.handleConfirm().then(res => {
       if (res.copyType !== 'basetable') {
diff --git a/src/menu/components/share/pastecomponent/index.jsx b/src/menu/components/share/pastecomponent/index.jsx
index cb1bb7b..477e3e0 100644
--- a/src/menu/components/share/pastecomponent/index.jsx
+++ b/src/menu/components/share/pastecomponent/index.jsx
@@ -21,10 +21,6 @@
     visible: false
   }
 
-  handleMenuClick = () => {
-    this.setState({visible: true})
-  }
-
   resetconfig = (item, config) => {
     let _uuid = Utils.getuuid()
 
@@ -116,9 +112,14 @@
   pasteSubmit = () => {
     const { options } = this.props
     this.pasteFormRef.handleConfirm().then(res => {
-
       if (!options.includes(res.copyType)) {
         notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
+        return
+      }
+
+      if (!this.props.config) {
+        this.props.updateConfig(res)
+        this.setState({visible: false})
         return
       }
 
@@ -181,7 +182,7 @@
         })
       }
 
-      this.props.updateConfig(config)
+      this.props.updateConfig(config, type)
       this.setState({visible: false})
 
       notification.success({
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 044e8ad..f7b9799 100644
--- a/src/menu/components/table/base-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/base-table/columns/editColumn/index.jsx
@@ -167,7 +167,15 @@
 
       if (item.type === 'text') {
         let rules = []
-        if (item.key !== 'linkurl') {
+        if (item.key === 'field') {
+          rules = [{
+            pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
+            message: '瀛楁鍚嶅彧鍏佽鍖呭惈鏁板瓧銆佸瓧姣嶃�佹眽瀛椾互鍙奯'
+          }, {
+            max: formRule.input.max,
+            message: formRule.input.message
+          }]
+        } else if (item.key !== 'linkurl') {
           rules = [{
             max: formRule.input.max,
             message: formRule.input.message
diff --git a/src/menu/components/table/base-table/columns/index.jsx b/src/menu/components/table/base-table/columns/index.jsx
index b7cd7e3..27b02ee 100644
--- a/src/menu/components/table/base-table/columns/index.jsx
+++ b/src/menu/components/table/base-table/columns/index.jsx
@@ -650,7 +650,7 @@
     }
 
     return (
-      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
+      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''} table-col-${columns.length}`} id={tableId}>
         <div className="col-control">
           <FieldsComponent config={config} type="columns" />
           <CopyOutlined title="澶嶅埗鏄剧ず鍒�" onClick={this.copycolumn} />
diff --git a/src/menu/components/table/base-table/index.jsx b/src/menu/components/table/base-table/index.jsx
index a1d88d9..86ba414 100644
--- a/src/menu/components/table/base-table/index.jsx
+++ b/src/menu/components/table/base-table/index.jsx
@@ -385,6 +385,13 @@
     this.updateComponent(config)
   }
 
+  parseComponent = (config, type) => {
+    if (type === 'cols') {
+      this.updatecolumn(config)
+    }
+    this.updateComponent(config)
+  }
+
   render() {
     const { card } = this.state
     let options = ['action', 'search', 'form', 'cols']
@@ -397,7 +404,7 @@
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
             <CopyComponent type="basetable" card={card}/>
-            <PasteComponent config={card} options={options} updateConfig={this.updateComponent} />
+            <PasteComponent config={card} options={options} updateConfig={this.parseComponent} />
             <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle}/>
             <SettingComponent config={card} updateConfig={this.updateComponent} />
           </div>
diff --git a/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
index bd69d85..6120716 100644
--- a/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
+++ b/src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -14,7 +14,8 @@
     roleList = []
   }
 
-  if (['picture', 'link', 'colspan'].includes(card.type)) {
+  // if (['picture', 'link', 'colspan'].includes(card.type)) {
+  if (['picture', 'link'].includes(card.type)) {
     card.type = 'text'
   }
 
@@ -31,8 +32,11 @@
     value: 'custom',
     text: '鑷畾涔夊垪'
   }, {
-    value: 'action',
-    text: '鎿嶄綔'
+    value: 'colspan',
+    text: '鍚堝苟鍒�'
+  // }, {
+  //   value: 'action',
+  //   text: '鎿嶄綔'
   }, {
     value: 'formula',
     text: '鍏紡'
@@ -40,6 +44,13 @@
     value: 'index',
     text: '搴忓彿'
   }]
+
+  if (!card.isSub) {
+    options.push({
+      value: 'action',
+      text: '鎿嶄綔'
+    })
+  }
 
   let editCols = [
     {
@@ -60,6 +71,15 @@
       editCols.push({
         field: col.uuid,
         label: col.label
+      })
+    } else if (col.type === 'colspan') {
+      col.subcols.forEach(subcol => {
+        if (subcol.editable === 'true' && subcol.uuid !== card.uuid) {
+          editCols.push({
+            field: subcol.uuid,
+            label: col.label + '-' + subcol.label
+          })
+        }
       })
     }
   })
@@ -116,7 +136,7 @@
       type: 'radio',
       key: 'IsSort',
       label: '鎺掑簭',
-      initVal: card.IsSort || 'false',
+      initVal: card.IsSort || (card.isSub ? 'false' : 'true'),
       required: true,
       options: [{
         value: 'true',
diff --git a/src/menu/components/table/edit-table/columns/editColumn/index.jsx b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
index 88c227d..e445b43 100644
--- a/src/menu/components/table/edit-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -17,6 +17,7 @@
   number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'editable', 'initval', 'sum', 'blacklist'],
   textarea: ['label', 'field', 'type', 'Align', 'Hide', 'Width', 'prefix', 'initval', 'postfix', 'blacklist'],
   custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
+  colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
   action: ['label', 'type', 'Align', 'Width'],
   formula: ['label', 'type', 'Align', 'Hide', 'Width', 'prefix', 'postfix', 'eval', 'formula', 'blacklist'],
   index: ['label', 'type', 'Align', 'Width']
@@ -131,7 +132,7 @@
           return item
         })
       }, () => {
-        if (value === 'action') {
+        if (value === 'action' || value === 'colspan') {
           this.props.form.setFieldsValue({Align: 'center'})
         }
       })
@@ -349,21 +350,18 @@
   }
 
   handleSubmit = () => {
-    const { columns, column } = this.props
+    // const { columns } = this.props
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     this.props.form.validateFieldsAndScroll((err, values) => {
       if (!err) {
-        values.uuid = column.uuid
-        values.marks = column.marks || []
-        
-        if (values.field && columns.filter(col => col.field && col.uuid !== values.uuid && col.field === values.field).length > 0) {
-          notification.warning({
-            top: 92,
-            message: '瀛楁宸叉坊鍔狅紒',
-            duration: 5
-          })
-          return
-        }
+        // if (values.field && columns.filter(col => col.field && col.uuid !== values.uuid && col.field === values.field).length > 0) {
+        //   notification.warning({
+        //     top: 92,
+        //     message: '瀛楁宸叉坊鍔狅紒',
+        //     duration: 5
+        //   })
+        //   return
+        // }
         this.setState({visible: false, formlist: null})
         this.props.submitCol(values)
 
diff --git a/src/menu/components/table/edit-table/columns/index.jsx b/src/menu/components/table/edit-table/columns/index.jsx
index 319b9af..afa1eba 100644
--- a/src/menu/components/table/edit-table/columns/index.jsx
+++ b/src/menu/components/table/edit-table/columns/index.jsx
@@ -59,31 +59,57 @@
       </th>
     )
 
-    let style = {cursor: 'move', textAlign: align}
-    if (column.Width) {
-      style.width = column.Width
-      style.minWidth = column.Width
-    }
+    if (index !== undefined) {
+      let style = {cursor: 'move', textAlign: align}
+      if (column.Width) {
+        style.width = column.Width
+        style.minWidth = column.Width
+      }
 
-    return connectDragSource(
-      connectDropTarget(<th {...restProps} index={index} style={style} onDoubleClick={() => this.props.editColumn(column)}>
-        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
-          <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
-            {['custom', 'action'].includes(column.type) ?
-              <PlusOutlined className="plus" title="娣诲姞" onClick={() => this.props.addElement(column)} /> : null
-            }
-            <EditOutlined className="edit" title="缂栬緫" onClick={() => this.props.editColumn(column)} />
-            {column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
-            {column.type === 'action' ? <PasteComponent options={['action']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
-            {column.type === 'custom' || column.type === 'action' ? <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={() => this.props.changeStyle(column)}/> : null}
-            <DeleteOutlined className="close" title="鍒犻櫎" onClick={this.deleteCol} />
-            {['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
-          </div>
-        } trigger="hover">
-          {children}
-        </Popover>
-      </th>),
-    )
+      return connectDragSource(
+        connectDropTarget(<th {...restProps} index={index} style={style} onDoubleClick={() => this.props.editColumn(column)}>
+          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+            <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
+              {['custom', 'colspan', 'action'].includes(column.type) ?
+                <PlusOutlined className="plus" title="娣诲姞" onClick={() => this.props.addElement(column)} /> : null
+              }
+              <EditOutlined className="edit" title="缂栬緫" onClick={() => this.props.editColumn(column)} />
+              {column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
+              {column.type === 'action' ? <PasteComponent options={['action']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
+              {column.type === 'custom' || column.type === 'action' ? <FontColorsOutlined className="style" title="璋冩暣鏍峰紡" onClick={() => this.props.changeStyle(column)}/> : null}
+              <DeleteOutlined className="close" title="鍒犻櫎" onClick={this.deleteCol} />
+              {['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
+            </div>
+          } trigger="hover">
+            {children}
+          </Popover>
+        </th>),
+      )
+    } else if (column) {
+      let style = {textAlign: align}
+      if (column.Width) {
+        style.width = column.Width
+        style.minWidth = column.Width
+      }
+
+      return (
+        <th {...restProps} style={style} key={column.uuid} onDoubleClick={() => this.props.editColumn(column)}>
+          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+            <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
+              {['custom', 'colspan'].includes(column.type) ?
+                <PlusOutlined className="plus" title="娣诲姞" onClick={() => this.props.addElement(column)} /> : null
+              }
+              <EditOutlined className="edit" title="缂栬緫" onClick={() => this.props.editColumn(column)} />
+              {column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
+              <DeleteOutlined className="close" title="鍒犻櫎" onClick={this.deleteCol} />
+              {column && ['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
+            </div>
+          } trigger="hover">
+            {children}
+          </Popover>
+        </th>
+      )
+    }
   }
 }
 
@@ -267,12 +293,14 @@
     let _columns = fromJS(this.state.columns).toJS()
     let type = item.subType
 
-    if (!['text', 'number', 'textarea', 'custom', 'action', 'formula', 'index'].includes(item.subType)) {
+    if (!['text', 'number', 'textarea', 'custom', 'action', 'formula', 'index', 'colspan'].includes(item.subType)) {
       type = 'text'
     }
 
     let col = { focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: type, elements: [] }
-    if (col.type === 'action') {
+    if (col.type === 'colspan') {
+      col.subcols = []
+    } else if (col.type === 'action') {
       col.label = '鎿嶄綔'
     } else if (col.type === 'index') {
       col.label = '搴忓彿'
@@ -287,14 +315,21 @@
     })
   }
 
-  updateCol = (col, btn) => {
-    let _columns = fromJS(this.state.columns).toJS()
-    _columns = _columns.map(column => {
+  loopCol = (columns, col) => {
+    return columns.map(column => {
+      if (column.type === 'colspan') {
+        column.subcols = this.loopCol(column.subcols || [], col)
+      }
       if (column.uuid === col.uuid) {
         return col
       }
       return column
     })
+  }
+
+  updateCol = (col, btn) => {
+    let _columns = fromJS(this.state.columns).toJS()
+    _columns = this.loopCol(_columns, col)
 
     this.setState({
       columns: _columns,
@@ -331,7 +366,16 @@
   addElement = (col) => {
     let column = fromJS(col).toJS()
 
-    if (column.type === 'custom') {
+    if (column.type === 'colspan') {
+      column.subcols = column.subcols || []
+      let subcol = { isSub: true, focus: true, uuid: Utils.getuuid(), label: 'label', field: '', type: 'text' }
+      column.subcols.push(subcol)
+
+      this.setState({
+        card: subcol
+      })
+      this.updateCol(column)
+    } else if (column.type === 'custom') {
       let newcard = {uuid: Utils.getuuid(), focus: true, width: 24, eleType: 'text', datatype: 'dynamic', style: {paddingLeft: '4px'}}
   
       // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
@@ -358,7 +402,13 @@
   submitCol = (col) => {
     const { card } = this.state
     
-    if (col.type === 'custom') {
+    col.uuid = card.uuid
+    col.isSub = card.isSub === true
+    col.marks = card.marks || []
+
+    if (col.type === 'colspan') {
+      col.subcols = card.subcols || []
+    } else if (col.type === 'custom') {
       col.style = card.style || {}
       col.elements = card.type === 'custom' ? (card.elements || []) : []
     } else if (col.type === 'action') {
@@ -410,10 +460,19 @@
     this.setState({card: null})
   }
 
+  loopDelCol = (columns, col) => {
+    return columns.filter(column => {
+      if (column.type === 'colspan') {
+        column.subcols = this.loopDelCol(column.subcols, col)
+      }
+      return column.uuid !== col.uuid
+    })
+  }
+
   deleteCol = (col) => {
     let _columns = fromJS(this.state.columns).toJS()
 
-    _columns = _columns.filter(column => column.uuid !== col.uuid)
+    _columns = this.loopDelCol(_columns, col)
 
     this.setState({
       columns: _columns
@@ -541,6 +600,43 @@
     MKEmitter.removeListener('submitStyle', this.getStyle)
   }
 
+  handlecolumns = (columns, fields, config, isSub) => {
+    return columns.map((col, index) => {
+      let title = col.label
+      if (col.editable === 'true') {
+        title = <span>{col.label}<EditOutlined style={{position: 'absolute', bottom: 0, right: 0, color: '#1890ff', opacity: '0.7'}}/></span>
+      }
+
+      return {
+        title: title,
+        dataIndex: col.uuid,
+        align: col.Align,
+        sorter: col.IsSort === 'true',
+        onCell: () => ({
+          column: col,
+          width: col.Width,
+          config: config,
+          upComponent: this.updateCol
+        }),
+        onHeaderCell: () => ({
+          index: isSub ? undefined : index,
+          column: col,
+          fields: fields,
+          align: col.Align,
+          moveCol: this.moveCol,
+          dropCol: this.dropCol,
+          updateCol: this.updateCol,
+          addElement: this.addElement,
+          editColumn: this.editColumn,
+          pasteCell: this.pasteCell,
+          changeStyle: this.changeStyle,
+          deleteCol: this.deleteCol,
+        }),
+        children: col.subcols && col.subcols.length ? this.handlecolumns(col.subcols, fields, config, true) : null,
+      }
+    })
+  }
+
   render() {
     const { config } = this.props
     const { fields, card, lineMarks, tableId, visible } = this.state
@@ -560,38 +656,7 @@
       }
     }
 
-    const columns = this.state.columns.map((col, index) => {
-      let title = col.label
-      if (col.editable === 'true') {
-        title = <span>{col.label}<EditOutlined style={{position: 'absolute', bottom: 0, right: 0, color: '#1890ff', opacity: '0.7'}}/></span>
-      }
-      return {
-        title: title,
-        dataIndex: col.uuid,
-        align: col.Align,
-        sorter: col.IsSort === 'true',
-        onCell: () => ({
-          column: col,
-          width: col.Width,
-          config: config,
-          upComponent: this.updateCol
-        }),
-        onHeaderCell: () => ({
-          index,
-          column: col,
-          fields: fields,
-          align: col.Align,
-          moveCol: this.moveCol,
-          dropCol: this.dropCol,
-          updateCol: this.updateCol,
-          addElement: this.addElement,
-          editColumn: this.editColumn,
-          pasteCell: this.pasteCell,
-          changeStyle: this.changeStyle,
-          deleteCol: this.deleteCol,
-        }),
-      }
-    })
+    const columns = this.handlecolumns(this.state.columns, fields, config)
 
     return (
       <div className={`edit-table-columns ${config.setting.laypage} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
diff --git a/src/menu/components/table/edit-table/columns/index.scss b/src/menu/components/table/edit-table/columns/index.scss
index b7e3f7b..0accff1 100644
--- a/src/menu/components/table/edit-table/columns/index.scss
+++ b/src/menu/components/table/edit-table/columns/index.scss
@@ -113,6 +113,7 @@
     }
     >.anticon-copy {
       color: #26C281;
+      margin-left: 5px;
     }
     >.anticon-delete {
       color: #ff4d4f;
diff --git a/src/menu/components/table/edit-table/index.jsx b/src/menu/components/table/edit-table/index.jsx
index ecd404c..ac0caff 100644
--- a/src/menu/components/table/edit-table/index.jsx
+++ b/src/menu/components/table/edit-table/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -228,7 +228,7 @@
     style.fontSize = card.wrap.fontSize || 14
     style.fontWeight = card.wrap.fontWeight || 'normal'
 
-    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -350,6 +350,14 @@
         if (col.format === 'abs') {
           config.absFields.push(col.field)
         }
+      } else if (col.type === 'colspan' && col.subcols) {
+        col.subcols.forEach(scol => {
+          if (scol.type === 'number') {
+            if (scol.format === 'abs') {
+              config.absFields.push(scol.field)
+            }
+          }
+        })
       }
     })
 
@@ -405,7 +413,15 @@
         <ColumnComponent config={card} updatecolumn={this.updatecolumn}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/table/edit-table/options.jsx b/src/menu/components/table/edit-table/options.jsx
index d04ef9a..9e47b44 100644
--- a/src/menu/components/table/edit-table/options.jsx
+++ b/src/menu/components/table/edit-table/options.jsx
@@ -62,6 +62,9 @@
       options: [
         {value: 'true', label: '鍙紪杈�'},
         {value: 'false', label: '涓嶅彲缂栬緫'},
+      ],
+      controlFields: [
+        {field: 'switchable', values: ['true']},
       ]
     },
     {
@@ -280,6 +283,18 @@
       forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
     },
     {
+      type: 'radio',
+      field: 'switchable',
+      label: '鐘舵�佸垏鎹�',
+      initval: wrap.switchable || 'true',
+      tooltip: '鏄惁鍙互鍦ㄧ紪杈戝拰榛樿table鐘舵�侀棿鍒囨崲銆�',
+      required: false,
+      options: [
+        {value: 'true', label: '鍚敤'},
+        {value: 'false', label: '绂佺敤'},
+      ]
+    },
+    {
       type: 'multiselect',
       field: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/menu/components/table/normal-table/columns/index.jsx b/src/menu/components/table/normal-table/columns/index.jsx
index 1097ef5..917976c 100644
--- a/src/menu/components/table/normal-table/columns/index.jsx
+++ b/src/menu/components/table/normal-table/columns/index.jsx
@@ -501,7 +501,6 @@
         title: col.label,
         dataIndex: col.uuid,
         align: col.Align,
-        // sorter: !isSub && col.IsSort === 'true',
         sorter: col.IsSort === 'true',
         onCell: () => ({
           column: col,
@@ -607,7 +606,7 @@
     const columns = this.handlecolumns(this.state.columns, fields, config)
 
     return (
-      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
+      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''} table-col-${columns.length}`} id={tableId}>
         <div className="col-control">
           <CopyOutlined title="澶嶅埗鏄剧ず鍒�" onClick={this.copycolumn} />
           <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index cd6df52..873c345 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/src/menu/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 { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { PlusOutlined, PlusCircleOutlined, PlusSquareOutlined, EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -280,7 +280,7 @@
     style.fontSize = card.wrap.fontSize || 14
     style.fontWeight = card.wrap.fontWeight || 'normal'
 
-    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['font1', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -472,7 +472,15 @@
         <ColumnComponent config={card} updatecolumn={this.updateComponent}/>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/tabs/paste/index.jsx b/src/menu/components/tabs/paste/index.jsx
index 53b2285..346f029 100644
--- a/src/menu/components/tabs/paste/index.jsx
+++ b/src/menu/components/tabs/paste/index.jsx
@@ -19,39 +19,32 @@
     visible: false
   }
 
-  handleMenuClick = () => {
-    this.setState({visible: true})
-  }
-
-  resetconfig = (item, uuids = {}) => {
+  resetconfig = (item) => {
     if (item.type === 'tabs') {
-      uuids[item.uuid] = MenuUtils.getuuid()
-      item.uuid = uuids[item.uuid]
+      item.uuid = MenuUtils.getuuid()
       item.setting.name = item.setting.name + MenuUtils.getSignName()
       item.name = item.setting.name
       
       item.subtabs.forEach(tab => {
-        uuids[tab.uuid] = MenuUtils.getuuid()
-        tab.uuid = uuids[tab.uuid]
+        tab.uuid = MenuUtils.getuuid()
 
         tab.components = tab.components.map(cell => {
-          cell = this.resetconfig(cell, uuids)
+          cell = this.resetconfig(cell)
           return cell
         })
       })
     } else if (item.type === 'group') {
-      uuids[item.uuid] = MenuUtils.getuuid()
-      item.uuid = uuids[item.uuid]
+      item.uuid = MenuUtils.getuuid()
       item.setting.name = item.setting.name + MenuUtils.getSignName()
       item.name = item.setting.name
 
       item.components = item.components.map(cell => {
-        cell = MenuUtils.resetComponentConfig(cell, uuids)
+        cell = MenuUtils.resetComponentConfig(cell)
 
         return cell
       })
     } else {
-      item = MenuUtils.resetComponentConfig(item, uuids)
+      item = MenuUtils.resetComponentConfig(item)
     }
 
     return item
@@ -90,7 +83,7 @@
         return
       }
 
-      res = this.resetconfig(res, {})
+      res = this.resetconfig(res)
 
       delete res.copyType
       
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index 7b1e17d..cf77eba 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -28,8 +28,9 @@
 const CustomChart = asyncComponent(() => import('@/menu/components/chart/chart-custom'))
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -91,6 +92,8 @@
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'card' && card.subtype === 'propcard') {
       return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
       return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'propcard') {
@@ -102,7 +105,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx
index a0ed8c1..bda63dd 100644
--- a/src/menu/components/tabs/tabcomponents/index.jsx
+++ b/src/menu/components/tabs/tabcomponents/index.jsx
@@ -34,6 +34,25 @@
     handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...config, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -146,6 +165,7 @@
           card={card}
           moveCard={moveCard}
           delCard={deleteCard}
+          unGroup={unGroup}
           findCard={findCard}
           updateConfig={updateConfig}
         />
diff --git a/src/menu/components/timeline/normal-timeline/index.jsx b/src/menu/components/timeline/normal-timeline/index.jsx
index 237e4fa..79df605 100644
--- a/src/menu/components/timeline/normal-timeline/index.jsx
+++ b/src/menu/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 { Popover } from 'antd'
+import { Popover, message } from 'antd'
 import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
@@ -165,7 +165,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -217,7 +217,15 @@
         {card.subcards.map(subcard => (<CardSimpleComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard}/>))}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/tree/antd-tree/index.jsx b/src/menu/components/tree/antd-tree/index.jsx
index c3c8640..8e91c46 100644
--- a/src/menu/components/tree/antd-tree/index.jsx
+++ b/src/menu/components/tree/antd-tree/index.jsx
@@ -1,13 +1,14 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Popover, Tree } from 'antd'
-import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, FileOutlined, FolderOpenOutlined } from '@ant-design/icons'
+import { Popover, Tree, message } from 'antd'
+import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, FileOutlined, FolderOpenOutlined, PlusSquareOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
 import { resetStyle, getTables } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
+import Utils from '@/utils/utils.js'
 import getWrapForm from './options'
 
 import './index.scss'
@@ -18,6 +19,7 @@
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
 const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
 
 const { TreeNode } = Tree
 
@@ -52,6 +54,7 @@
         headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
         columns: [],
         scripts: [],
+        action: [],
       }
 
       if (card.config) {
@@ -69,8 +72,11 @@
       
       this.updateComponent(_card)
     } else {
+      let _card = fromJS(card).toJS()
+      _card.action = _card.action || [] // 鍏煎
+
       this.setState({
-        card: fromJS(card).toJS()
+        card: _card
       })
     }
   }
@@ -129,13 +135,65 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
     let _card = {...this.state.card, style}
 
     this.updateComponent(_card)
+  }
+
+  addButton = (copy) => {
+    const { card } = this.state
+
+    let newcard = {}
+
+    if (copy) {
+      newcard = copy
+      newcard.focus = true
+    } else {
+      newcard.uuid = Utils.getuuid()
+      newcard.focus = true
+      
+      newcard.label = 'label'
+      newcard.Ot = 'requiredSgl'
+      newcard.OpenType = 'pop'
+      newcard.icon = ''
+      newcard.class = 'green'
+      newcard.intertype = card.setting.interType || 'system'
+      newcard.innerFunc = card.setting.innerFunc || ''
+      newcard.sysInterface = card.setting.sysInterface || ''
+      newcard.outerFunc = card.setting.outerFunc || ''
+      newcard.interface = card.setting.interface || ''
+      newcard.execSuccess = 'grid'
+      newcard.execError = 'never'
+      newcard.verify = null
+      newcard.show = 'button'
+      newcard.style = {marginRight: '15px'}
+    }
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
+    MKEmitter.emit('addButton', card.uuid, newcard)
+  }
+
+  setSubConfig = (item) => {
+    const { card, appType } = this.state
+    let btn = fromJS(item).toJS()
+
+    if (btn.OpenType === 'pop' || btn.execMode === 'pop') {
+      if (!btn.modal) {
+        btn.modal = {
+          setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
+          tables: [],
+          groups: [],
+          fields: []
+        }
+      }
+      MKEmitter.emit('changeModal', card, btn)
+    } else if (btn.OpenType === 'popview' && appType !== 'mob') {
+      MKEmitter.emit('changePopview', card, btn)
+    }
   }
 
   getWrapForms = () => {
@@ -168,8 +226,10 @@
     return (
       <div className="menu-tree-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <NormalHeader config={card} updateComponent={this.updateComponent}/>
+        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
+            <PlusSquareOutlined className="plus" title="娣诲姞鎸夐挳" onClick={() => this.addButton()}/>
             <NormalForm title="鍩烘湰璁剧疆" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
               <EditOutlined style={{color: '#1890ff'}} title="缂栬緫"/>
             </NormalForm>
@@ -197,7 +257,15 @@
         </div>
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+              message.success('澶嶅埗鎴愬姛銆�')
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/menu/components/tree/antd-tree/index.scss b/src/menu/components/tree/antd-tree/index.scss
index a1255ef..20df956 100644
--- a/src/menu/components/tree/antd-tree/index.scss
+++ b/src/menu/components/tree/antd-tree/index.scss
@@ -25,6 +25,9 @@
     line-height: 90px;
     color: #bcbcbc;
   }
+  .model-menu-action-list:not(.length0) {
+    margin: 10px 0px;
+  }
 }
 .menu-tree-box::after {
   display: block;
diff --git a/src/menu/datasource/index.jsx b/src/menu/datasource/index.jsx
index 52a1544..c40ff35 100644
--- a/src/menu/datasource/index.jsx
+++ b/src/menu/datasource/index.jsx
@@ -198,6 +198,10 @@
 
       res.setting.maxScript = maxScript
 
+      if (config.subtype !== 'dualdatacard') {
+        delete res.subColumns
+      }
+
       this.setState({loading: false, visible: false})
       this.props.updateConfig({...config, ...res})
     }, () => {
diff --git a/src/menu/datasource/verifycard/customscript/index.jsx b/src/menu/datasource/verifycard/customscript/index.jsx
index a673fea..85de3e6 100644
--- a/src/menu/datasource/verifycard/customscript/index.jsx
+++ b/src/menu/datasource/verifycard/customscript/index.jsx
@@ -234,7 +234,7 @@
           </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</span></Tooltip>,&nbsp;
+              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鍏叡鍊硷紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�'}><span style={{color: '#1890ff'}}>BID, 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>,&nbsp;
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'鎺掑簭銆佸垎椤典互鍙婃悳绱㈡潯浠跺彉閲忥紝璇锋寜鐓xxx@鏍煎紡浣跨敤銆�'}>orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}</Tooltip>
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'url鍙橀噺锛岃鎸夌収@xxx@鏍煎紡浣跨敤銆�'}>{urlFields ? ', ' : ''}<span style={{color: '#13c2c2'}}>{urlFields}</span></Tooltip>
diff --git a/src/menu/datasource/verifycard/index.jsx b/src/menu/datasource/verifycard/index.jsx
index 4962810..dcb2c3d 100644
--- a/src/menu/datasource/verifycard/index.jsx
+++ b/src/menu/datasource/verifycard/index.jsx
@@ -32,6 +32,7 @@
 
   state = {
     columns: [],
+    subColumns: [],
     activeKey: 'setting',
     loading: false,
     initsql: '',          // sql楠岃瘉鏃跺彉閲忓0鏄庡強璧嬪��
@@ -197,6 +198,7 @@
     this.setState({
       scripts,
       columns: config.columns ? fromJS(config.columns).toJS() : [],
+      subColumns: config.subColumns ? fromJS(config.subColumns).toJS() : [],
       setting: _setting,
       median: _setting,
       searches: search,
@@ -272,6 +274,26 @@
     values.uuid = Utils.getuuid()
 
     this.setState({ columns: [...columns, values] })
+  }
+
+  subColumnChange = (values, resolve) => {
+    const { subColumns } = this.state
+
+    let fields = subColumns.map(item => item.field.toLowerCase())
+    if (fields.includes(values.field.toLowerCase())) {
+      notification.warning({
+        top: 92,
+        message: '瀛楁宸插瓨鍦紒',
+        duration: 5
+      })
+      return
+    }
+
+    resolve()
+
+    values.uuid = Utils.getuuid()
+
+    this.setState({ subColumns: [...subColumns, values] })
   }
 
   deleteScript = (record) => {
@@ -422,6 +444,23 @@
         loading: false
       })
       this.getdefaultSql()
+    } else if (activeKey === 'subcolumns') {
+      if (this.subdatasource && this.subdatasource.state.editingKey) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁鏈繚瀛橈紝璇蜂繚瀛樺悗鍒囨崲锛�',
+          duration: 5
+        })
+        this.setState({
+          loading: false
+        })
+        return
+      }
+
+      this.setState({
+        activeKey: val,
+        loading: false
+      })
     } else if (activeKey === 'scripts') {
       let _loading = false
       if (this.scriptsForm && this.scriptsForm.state.editItem) {
@@ -514,7 +553,26 @@
 
   submitDataSource = () => {
     const { config, mainSearch } = this.props
-    const { activeKey, setting, columns, scripts } = this.state
+    const { activeKey, setting, columns, subColumns, scripts } = this.state
+
+    if (config.subtype === 'dualdatacard') {
+      let arr = columns.map(col => col.field.toLowerCase())
+      let _arr = []
+      subColumns.forEach(col => {
+        if (arr.includes(col.field.toLowerCase())) {
+          _arr.push(col.field)
+        }
+      })
+
+      if (_arr.length > 0) {
+        notification.warning({
+          top: 92,
+          message: '瀛愯〃涓瓧娈�' + _arr.join('銆�') + '涓庝富琛ㄥ瓧娈甸噸澶嶏紒',
+          duration: 5
+        })
+        return Promise.reject()
+      }
+    }
 
     return new Promise((resolve, reject) => {
       if (activeKey === 'setting') {
@@ -536,7 +594,7 @@
             defaultSearch: _search,
             setting: res
           }, () => {
-            this.sqlverify(() => { resolve({setting: res, columns, scripts }) }, reject, false)
+            this.sqlverify(() => { resolve({setting: res, columns, subColumns, scripts }) }, reject, false)
           })
         }, () => {
           reject()
@@ -551,7 +609,18 @@
           reject()
           return
         }
-        this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false)
+        this.sqlverify(() => { resolve({setting, columns, subColumns, scripts }) }, reject, false)
+      } else if (activeKey === 'subcolumns') {
+        if (this.subdatasource && this.subdatasource.state.editingKey) {
+          notification.warning({
+            top: 92,
+            message: '瀛楁鏈繚瀛橈紝璇蜂繚瀛樺悗鎻愪氦锛�',
+            duration: 5
+          })
+          reject()
+          return
+        }
+        this.sqlverify(() => { resolve({setting, columns, subColumns, scripts }) }, reject, false)
       } else if (activeKey === 'scripts') {
         let _loading = false
         if (this.scriptsForm && this.scriptsForm.state.editItem) {
@@ -570,7 +639,7 @@
           return
         }
 
-        this.sqlverify(() => { resolve({setting, columns, scripts }) }, reject, false)
+        this.sqlverify(() => { resolve({setting, columns, subColumns, scripts }) }, reject, false)
       }
     })
   }
@@ -701,18 +770,15 @@
     })
   }
 
+  updateSubfields = (columns) => {
+    this.setState({
+      subColumns: columns
+    })
+  }
+
   copyDatasource = () => {
     const { config } = this.props
-    const { columns, scripts } = this.state
-
-    if (columns.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '璇锋坊鍔犲瓧娈甸泦!',
-        duration: 5
-      })
-      return
-    }
+    const { columns, subColumns, scripts } = this.state
 
     this.settingForm.handleConfirm().then(res => {
       delete res.supModule
@@ -721,7 +787,7 @@
       let source = {
         key: 'interface',
         type: 'line',
-        data: {setting: res, columns, scripts, pageable: false, format: 'array', name: res.name, status: 'false', type: 'interface', uuid: '' }
+        data: {setting: res, columns, subColumns, scripts, pageable: false, format: 'array', name: res.name, status: 'false', type: 'interface', uuid: '' }
       }
 
       try {
@@ -769,6 +835,15 @@
       }
 
       if (config.subtype !== 'basetable') {
+        let subColumns = []
+
+        if (config.subtype === 'dualdatacard' && res.data.subColumns) {
+          subColumns = res.data.subColumns.map(col => {
+            col.uuid = Utils.getuuid()
+            return col
+          })
+        }
+
         this.setState({
           scripts: res.data.scripts.map(col => {
             col.uuid = Utils.getuuid()
@@ -778,6 +853,7 @@
             col.uuid = Utils.getuuid()
             return col
           }),
+          subColumns: subColumns,
           setting: res.data.setting,
           median: res.data.setting,
           reload: true,
@@ -823,6 +899,27 @@
     message.success('澶嶅埗鎴愬姛銆�')
   }
 
+  copySubColumns = () => {
+    const { subColumns } = this.state
+    let m = []
+    let n = []
+
+    subColumns.forEach(col => {
+      m.push(`${col.field}(${col.label})`)
+      n.push(col.field)
+    })
+
+    let oInput = document.createElement('input')
+    oInput.value = `/*${m.join(',')}*/
+      ${n.join(',')}`
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    document.body.removeChild(oInput)
+
+    message.success('澶嶅埗鎴愬姛銆�')
+  }
+
   /**
    * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
    */
@@ -834,7 +931,7 @@
 
   render() {
     const { config } = this.props
-    const { columns, median, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue } = this.state
+    const { columns, subColumns, median, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches, defaultsql, visible, pvisible, reload, script, scriptValue } = this.state
 
     return (
       <div className="model-data-source-wrap">
@@ -844,13 +941,12 @@
           <TabPane tab={
             <span>
               鏁版嵁婧�
-              {config.type !== 'interface' ? <CopyOutlined title="澶嶅埗鏁版嵁婧�" className="mk-copy-datasource" onClick={this.copyDatasource}/> : null}
-              {config.type !== 'interface' ? <SnippetsOutlined title="瀵煎叆鏁版嵁婧�" className="mk-paste-datasource" onClick={() => this.setState({pvisible: true})}/> : null}
             </span>
           } key="setting">
             {!reload ? <SettingForm
               config={config}
               columns={columns}
+              subColumns={subColumns}
               setting={setting}
               scripts={scripts}
               updateStatus={(res) => this.setState({median: {...res}})}
@@ -861,21 +957,38 @@
             <span>
               瀛楁闆�
               {columns.length ? <span className="count-tip">{columns.length}</span> : null}
-              <CopyOutlined title="浠ラ�楀彿鎷兼帴褰㈠紡澶嶅埗瀛楁" className="mk-copy-fields" onClick={this.copyColumns}/>
             </span>
           } key="columns">
             <ColForm columnChange={this.columnChange}/>
             <FieldsComponent
-              config={{...config, columns}}
+              config={{columns}}
               type="fields"
               updatefield={this.updatefields}
             />
             <EditTable actions={['edit', 'move', 'copy', 'del', 'clear']} type="datasourcefield" wrappedComponentRef={(inst) => this.datasource = inst} data={columns} columns={colColumns} onChange={(columns) => this.setState({columns})}/>
           </TabPane> : null}
+          {config.subtype === 'dualdatacard' ? <TabPane tab={
+            <span>
+              瀛愯〃瀛楁闆�
+              {subColumns.length ? <span className="count-tip">{subColumns.length}</span> : null}
+            </span>
+          } key="subcolumns">
+            <ColForm columnChange={this.subColumnChange}/>
+            <FieldsComponent
+              config={{columns: subColumns}}
+              type="fields"
+              updatefield={this.updateSubfields}
+            />
+            <EditTable actions={['edit', 'move', 'copy', 'del', 'clear']} type="datasourcefield" wrappedComponentRef={(inst) => this.subdatasource = inst} data={subColumns} columns={colColumns} onChange={(subColumns) => this.setState({subColumns})}/>
+          </TabPane> : null}
           <TabPane tab={
             <span>
               鑷畾涔夎剼鏈�
               {scripts.length ? <span className="count-tip">{scripts.length}</span> : null}
+              {config.type !== 'interface' && activeKey === 'setting' ? <CopyOutlined title="澶嶅埗鏁版嵁婧�" className="mk-copy-datasource" onClick={(e) => {e.stopPropagation();this.copyDatasource()}}/> : null}
+              {config.type !== 'interface' && activeKey === 'setting' ? <SnippetsOutlined title="瀵煎叆鏁版嵁婧�" className="mk-paste-datasource" onClick={(e) => {e.stopPropagation();this.setState({pvisible: true})}}/> : null}
+              {activeKey === 'columns' ? <CopyOutlined title="浠ラ�楀彿鎷兼帴褰㈠紡澶嶅埗瀛楁" className="mk-copy-fields" onClick={(e) => {e.stopPropagation();this.copyColumns()}}/> : null}
+              {activeKey === 'subcolumns' ? <CopyOutlined title="浠ラ�楀彿鎷兼帴褰㈠紡澶嶅埗瀛楁" className="mk-copy-fields" onClick={(e) => {e.stopPropagation();this.copySubColumns()}}/> : null}
             </span>
           } key="scripts" disabled={median.interType !== 'system'} id="mk-scripts-tabpane">
             {scripts.length ? <BorderOutlined className="full-scripts" onClick={() => {
diff --git a/src/menu/datasource/verifycard/index.scss b/src/menu/datasource/verifycard/index.scss
index 7fcbe7e..b9bc0fe 100644
--- a/src/menu/datasource/verifycard/index.scss
+++ b/src/menu/datasource/verifycard/index.scss
@@ -14,9 +14,9 @@
       cursor: pointer;
       z-index: 1;
       top: 19px;
-      right: -210px;
+      right: -50px;
       color: rgb(24, 144, 255);
-      display: none;
+      display: inline-block;
       opacity: 0.4;
       transition: opacity 0.2s;
     }
@@ -25,9 +25,9 @@
       cursor: pointer;
       z-index: 1;
       top: 19px;
-      right: -319px;
+      right: -50px;
       color: rgb(24, 144, 255);
-      display: none;
+      display: inline-block;
       opacity: 0.4;
       transition: opacity 0.2s;
     }
@@ -36,19 +36,14 @@
       cursor: pointer;
       z-index: 1;
       top: 19px;
-      right: -355px;
+      right: -90px;
       color:purple;
-      display: none;
+      display: inline-block;
       opacity: 0.4;
       transition: opacity 0.2s;
     }
     .mk-copy-fields:hover, .mk-copy-datasource:hover, .mk-paste-datasource:hover {
       opacity: 1;
-    }
-    .ant-tabs-tab-active {
-      .mk-copy-fields, .mk-copy-datasource, .mk-paste-datasource {
-        display: inline-block;
-      }
     }
     .count-tip {
       position: absolute;
diff --git a/src/menu/datasource/verifycard/settingform/index.jsx b/src/menu/datasource/verifycard/settingform/index.jsx
index ad9a2bd..de02f21 100644
--- a/src/menu/datasource/verifycard/settingform/index.jsx
+++ b/src/menu/datasource/verifycard/settingform/index.jsx
@@ -409,7 +409,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            {!['navbar', 'balcony', 'menubar', 'interface'].includes(config.type) && (!config.wrap || config.wrap.supType !== 'multi') ? <Col span={8}>
+            {!['navbar', 'balcony', 'menubar'].includes(config.type) && (!config.wrap || config.wrap.supType !== 'multi') ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'璇ョ粍浠跺鏋滃彈鍏朵粬缁勪欢鎺у埗锛岃閫夐」鐩稿簲鐨勭粍浠讹紝娌℃湁鏃堕�夆�滄棤鈥濄��'}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -460,7 +460,7 @@
               </Form.Item>
             </Col> : null}
             {/* 1銆佷笉鍒嗛〉涓斾笉瀛樺湪涓婄骇妯″潡 */}
-            {!['navbar', 'interface'].includes(config.type) && !['editable', 'basetable'].includes(config.subtype) && (!config.pageable || (config.pageable && setting.laypage === 'false')) && (setting.supModule.length === 0 || setting.supModule[0] === 'empty') && setting.interType === 'system' ? <Col span={8}>
+            {!['navbar', 'interface'].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' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'鍒濆鍖栧姞杞芥椂锛屾槸鍚︿笌鍏朵粬缁勪欢涓�鍚屽姞杞芥暟鎹紝娉細浠呭湪浣跨敤绯荤粺鍑芥暟锛屼笖鍒濆鍖栧姞杞芥暟鎹椂鏈夋晥锛屽垎椤佃姹傛椂鏃犳晥銆�'}>
                   <QuestionCircleOutlined className="mk-form-tip" />
@@ -556,6 +556,54 @@
                 })(<InputNumber min={0} max={500} precision={0} />)}
               </Form.Item>
             </Col> : null}
+            {config.subtype === 'dualdatacard' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="瀛愯〃鍦ㄤ富琛ㄤ腑鐨勬暟鎹泦鍚嶇О銆�">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  瀛愯〃瀛楁
+                </Tooltip>
+              }>
+                {getFieldDecorator('subdata', {
+                  initialValue: setting.subdata || 'sub_data',
+                  rules: [
+                    {
+                      required: true,
+                      message: '璇疯緭鍏ラ粯璁ゆ帓搴�!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {config.subtype === 'dualdatacard' ? <Col span={8}>
+              <Form.Item label="瀛愯〃涓婚敭">
+                {getFieldDecorator('subKey', {
+                  initialValue: setting.subKey || ''
+                })(
+                  <Select>
+                    {this.props.subColumns.map((option, i) =>
+                      <Select.Option key={i} value={option.field}>
+                        {option.label}
+                      </Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {config.subtype === 'dualdatacard' ? <Col span={8}>
+              <Form.Item label="瀛愯〃BID">
+                {getFieldDecorator('subBID', {
+                  initialValue: setting.subBID || ''
+                })(
+                  <Select>
+                    {this.props.subColumns.map((option, i) =>
+                      <Select.Option key={i} value={option.field}>
+                        {option.label}
+                      </Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
           </Row>
         </Form>
       </div>
diff --git a/src/menu/datasource/verifycard/utils.jsx b/src/menu/datasource/verifycard/utils.jsx
index 6296192..93f129b 100644
--- a/src/menu/datasource/verifycard/utils.jsx
+++ b/src/menu/datasource/verifycard/utils.jsx
@@ -14,13 +14,11 @@
     let _customScript = ''
     let arr_field = columns.map(item => item.field).join(',')
 
-    if (scripts.length > 0) {
-      scripts.forEach(item => {
-        _customScript += `
-          ${item.sql}
-        `
-      })
-    }
+    scripts.forEach(item => {
+      _customScript += `
+        ${item.sql}
+      `
+    })
 
     if (!arr_field) {
       arr_field = '*'
@@ -44,8 +42,8 @@
     //   error = '绯荤粺鍑芥暟' + _customScript.match(/\$ex@.{1,50}@ex\$/g)[0].replace(/\$ex@|@ex\$/g, '') + '鏈畾涔�'
     // }
 
-    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|datam|upid)@/ig, `'${timestamp}'`)
-    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|datam|upid)@/ig, `'${timestamp}'`)
+    _dataresource = _dataresource.replace(/@(BID|LoginUID|SessionUid|UserID|Appkey|time_id|datam|upid|typename)@/ig, `'${timestamp}'`)
+    _customScript = _customScript.replace(/@(BID|LoginUID|SessionUid|UserID|Appkey|time_id|datam|upid|typename)@/ig, `'${timestamp}'`)
 
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
@@ -218,12 +216,38 @@
     if (/@[0-9a-zA-Z_]+@/ig.test(sql)) {
       let arr = sql.match(/@[0-9a-zA-Z_]+@/ig)
 
+      let getTrueSql = (sl) => {
+        if (!/\/\*/.test(sl)) return sl
+        let index = 0
+
+        sl = sl.replace(/\s/ig, ' ')
+        sl = sl.replace(/\*\//ig, 'm_k@')
+        sl = sl.replace(/\/\*/ig, () => {
+          index++
+          return '@m_k' + index
+        })
+
+        for (let i = index; i > 0; i--) {
+          let reg = new RegExp(`@m_k${i}.+m_k@`, 'ig')
+          sl = sl.replace(reg, '')
+        }
+
+        return sl
+      }
+
+      let _scripts = []
+      _dataresource = _dataresource.replace('/*system_query*/', '')
+      _dataresource = getTrueSql(_dataresource)
+      scripts.forEach(item => {
+        _scripts.push({...item, sql: getTrueSql(item.sql)})
+      })
+
       arr.forEach(item => {
         let reg = new RegExp(item, 'ig')
         if (reg.test(_dataresource)) {
           errors.push(`鏁版嵁婧愪腑瀛樺湪鏈浛鎹㈠��${item}`)
         }
-        scripts && scripts.forEach(script => {
+        _scripts.forEach(script => {
           if (reg.test(script.sql)) {
             errors.push(`鑷畾涔夎剼鏈�(${script.$index || ''})瀛樺湪鏈浛鎹㈠��${item}`)
           }
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index 0226f8f..467795d 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -11,6 +11,7 @@
 const AntvScatter = asyncComponent(() => import('@/menu/components/chart/antv-scatter'))
 const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs'))
 const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
@@ -32,7 +33,7 @@
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -78,6 +79,8 @@
       return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'search') {
       return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'dashboard') {
@@ -105,7 +108,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index 9024341..9533aa5 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -155,6 +174,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/menu/modalconfig/index.jsx b/src/menu/modalconfig/index.jsx
index e205f50..c0da35b 100644
--- a/src/menu/modalconfig/index.jsx
+++ b/src/menu/modalconfig/index.jsx
@@ -4,8 +4,8 @@
 import { DndProvider } from 'react-dnd'
 import HTML5Backend from 'react-dnd-html5-backend'
 import moment from 'moment'
-import { Button, Card, Modal, Collapse, notification, Switch } from 'antd'
-import { SettingOutlined } from '@ant-design/icons'
+import { Button, Card, Modal, Collapse, notification, Switch, message } from 'antd'
+import { SettingOutlined, CopyOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -106,7 +106,7 @@
    * 3銆佽缃紪杈戝弬鏁伴」-formlist
    */
   handleForm = (_card) => {
-    const { componentConfig } = this.props
+    const { componentConfig, btn } = this.props
     const { config } = this.state
     let card = fromJS(_card).toJS()
     let _inputfields = []
@@ -119,35 +119,28 @@
     let index = null
     uniq.set(card.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     config.fields.forEach((item, i) => {
       if (card.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && card.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
       if (card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
 
@@ -158,13 +151,12 @@
 
         _linkableFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
-        _linkIndex++
       }
     })
     if (index !== null) {
@@ -175,17 +167,19 @@
       }
     }
 
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
+    let columns = componentConfig.columns
+    if (btn.$sub) {
+      columns = componentConfig.subColumns || []
+    }
 
-    componentConfig.columns.forEach(col => {
+    columns.forEach(col => {
       if (col.field && !uniq.has(col.field)) {
         uniq.set(col.field, true)
 
         _linkableFields.push({
           field: col.field,
-          label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+          label: col.label + '-鏄剧ず鍒�'
         })
-        _linkIndex++
       }
     })
 
@@ -206,7 +200,7 @@
       standardform,
       visible: true,
       card: card,
-      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, componentConfig.columns)
+      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, columns)
     })
   }
 
@@ -271,7 +265,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -462,8 +456,44 @@
     })
   }
 
-  plusFields = (items) => {
+  plusFields = (items, type) => {
     let _config = fromJS(this.state.config).toJS()
+
+    if (type === 'forms') {
+      if (_config.fields.length > 0) {
+        let that = this
+        _config.fields = items.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        confirm({
+          title: '纭畾鏇挎崲琛ㄥ崟鍚楋紵',
+          content: '鍘熻〃鍗曞皢鍒犻櫎銆�',
+          onOk() {
+            that.setState({
+              config: _config
+            })
+          },
+          onCancel() {}
+        })
+      } else {
+        _config.fields = items.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        this.setState({
+          config: _config
+        })
+        notification.success({
+          top: 92,
+          message: '绮樿创鎴愬姛锛�',
+          duration: 2
+        })
+      }
+      return
+    }
 
     _config.fields.push(...items)
 
@@ -474,6 +504,39 @@
         this.handleForm(items[0])
       }
     })
+  }
+
+  triggerCopy = () => {
+    const { config } = this.state
+
+    let val = {
+      copyType: 'forms',
+      fields: config.fields || []
+    }
+
+    if (val.fields.length === 0) {
+      message.warning('琛ㄥ崟鍏冪礌涓嶅彲涓虹┖锛�')
+      return
+    }
+
+    try {
+      val = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    } catch (e) {
+      console.warn(e)
+      message.warning('澶嶅埗澶辫触锛岃閲嶈瘯锛�')
+      val = ''
+    }
+
+    if (val) {
+      let oInput = document.createElement('input')
+      oInput.value = val
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+
+      message.success('澶嶅埗鎴愬姛銆�')
+    }
   }
 
   render () {
@@ -499,7 +562,7 @@
             <Card title="琛ㄥ崟閰嶇疆" bordered={false} extra={
               <div>
                 <Button type="danger" onClick={this.clearConfig}>娓呯┖</Button>
-                <EditComponent options={['form']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
+                <EditComponent options={['form', 'forms']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
                 <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>淇濆瓨</Button>
                 <Button onClick={this.cancelConfig}>杩斿洖</Button>
               </div>
@@ -512,6 +575,7 @@
                   <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2鍒�</Button>
                   <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3鍒�</Button>
                   <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4鍒�</Button>
+                  <CopyOutlined title="澶嶅埗" onClick={this.triggerCopy} />
                   <Switch checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
                 </div>
                 <div className="ant-modal-body">
diff --git a/src/menu/modalconfig/index.scss b/src/menu/modalconfig/index.scss
index e0dcc61..4e0d628 100644
--- a/src/menu/modalconfig/index.scss
+++ b/src/menu/modalconfig/index.scss
@@ -117,10 +117,17 @@
           z-index: 10;
           background: transparent;
           min-height: 50px;
-          padding-right: 75px;
+          padding-right: 80px;
           .ant-modal-title {
             display: inline-block;
           }
+          .anticon-copy {
+            position: absolute;
+            top: 18px;
+            color: #26C281;
+            right: 65px;
+            font-size: 16px;
+          }
           .ant-switch {
             position: absolute;
             top: 15px;
diff --git a/src/menu/modulecell/index.jsx b/src/menu/modulecell/index.jsx
index 279ab51..b8841a6 100644
--- a/src/menu/modulecell/index.jsx
+++ b/src/menu/modulecell/index.jsx
@@ -67,7 +67,8 @@
           { subType: 'hint', text: '鎻愮ず', type: 'form' },
           { subType: 'split', text: '鍒嗛殧绾�', type: 'form' },
           { subType: 'linkMain', text: '鍏宠仈涓昏〃', type: 'form' },
-          { subType: 'formula', text: '鍏紡', type: 'form' }
+          { subType: 'formula', text: '鍏紡', type: 'form' },
+          { subType: 'vercode', text: '楠岃瘉鐮�', type: 'form' }
         ]
       },
       {
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index 8273421..696b3a5 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -1,7 +1,7 @@
 import bar from '@/assets/mobimg/bar.png'
 import bar1 from '@/assets/mobimg/bar1.png'
 import line from '@/assets/mobimg/line.png'
-import line1 from '@/assets/mobimg/line1.png'
+// import line1 from '@/assets/mobimg/line1.png'
 import tabs from '@/assets/mobimg/tabs.png'
 import group from '@/assets/mobimg/group.png'
 import card1 from '@/assets/mobimg/card1.png'
@@ -40,6 +40,7 @@
   { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', width: 24 },
   { type: 'menu', url: card2, component: 'balcony', subtype: 'balcony', title: '娴姩鍗�', width: 24},
+  { type: 'menu', url: card1, component: 'card', subtype: 'dualdatacard', title: '鍙岄噸鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: simpleform, component: 'form', subtype: 'simpleform', title: '琛ㄥ崟', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟锛堝垎姝ワ級', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: tabForm, component: 'form', subtype: 'tabform', title: '琛ㄥ崟锛坱ab椤碉級', width: 24, forbid: ['billPrint'] },
@@ -51,7 +52,7 @@
   { type: 'menu', url: timeline, component: 'timeline', subtype: 'timeline', title: '鏃堕棿杞�', width: 12 },
   { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '鏍戝舰鍒楄〃', width: 12, forbid: ['billPrint'] },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
-  { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
+  // { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
   { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '鏌辩姸鍥�', width: 24 },
   { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
   { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 12 },
diff --git a/src/menu/normalCss/index.jsx b/src/menu/normalCss/index.jsx
new file mode 100644
index 0000000..27c393a
--- /dev/null
+++ b/src/menu/normalCss/index.jsx
@@ -0,0 +1,70 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal } from 'antd'
+import { EditOutlined } from '@ant-design/icons'
+
+import CodeMirror from '@/templates/zshare/codemirror'
+import './index.scss'
+
+class NormalCss extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false,
+    normalcss: ''
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  trigger = () => {
+    const { config } = this.props
+
+    this.setState({visible: true, normalcss: config.normalcss || ''})
+  }
+
+  onCssChange = (val) => {
+    this.setState({
+      normalcss: val
+    })
+  }
+
+  submit = () => {
+    const { normalcss } = this.state
+
+    this.setState({
+      visible: false
+    })
+
+    this.props.updateConfig({...this.props.config, normalcss: normalcss})
+  }
+
+  render() {
+    const { visible, normalcss } = this.state
+
+    return (
+      <div className="mk-normal-css">
+        鍏ㄥ眬鏍峰紡锛�<EditOutlined onClick={this.trigger} />
+        <Modal
+          title="鍏ㄥ眬鏍峰紡"
+          wrapClassName="normal-css-modal"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          destroyOnClose
+        >
+          <CodeMirror mode="text/css" theme="cobalt" value={normalcss} onChange={this.onCssChange} />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default NormalCss
\ No newline at end of file
diff --git a/src/menu/normalCss/index.scss b/src/menu/normalCss/index.scss
new file mode 100644
index 0000000..872d481
--- /dev/null
+++ b/src/menu/normalCss/index.scss
@@ -0,0 +1,21 @@
+.mk-normal-css {
+  padding-left: 18px;
+
+  .anticon-edit {
+    color: #1890ff;
+    cursor: pointer;
+  }
+}
+.normal-css-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 250px;
+    padding-top: 10px;
+
+    .code-mirror-wrap .code-mirror-area .CodeMirror {
+      min-height: 400px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/pastecontroller/index.jsx b/src/menu/pastecontroller/index.jsx
index 7a49bf2..d816e9d 100644
--- a/src/menu/pastecontroller/index.jsx
+++ b/src/menu/pastecontroller/index.jsx
@@ -18,40 +18,37 @@
     visible: false
   }
 
-  resetconfig = (item, uuids = {}) => {
+  resetconfig = (item) => {
     let appType = sessionStorage.getItem('appType')
     
     if (item.type === 'tabs') {
-      uuids[item.uuid] = MenuUtils.getuuid()
-      item.uuid = uuids[item.uuid]
+      item.uuid = MenuUtils.getuuid()
       item.setting.name = item.setting.name + MenuUtils.getSignName()
       item.name = item.setting.name
 
       item.subtabs.forEach(tab => {
-        uuids[tab.uuid] = MenuUtils.getuuid()
-        tab.uuid = uuids[tab.uuid]
+        tab.uuid = MenuUtils.getuuid()
 
         if (appType !== 'mob') {
           tab.components = tab.components.filter(cell => cell.type !== 'menubar')
         }
 
         tab.components = tab.components.map(cell => {
-          cell = this.resetconfig(cell, uuids)
+          cell = this.resetconfig(cell)
           return cell
         })
       })
     } else if (item.type === 'group') {
-      uuids[item.uuid] = MenuUtils.getuuid()
-      item.uuid = uuids[item.uuid]
+      item.uuid = MenuUtils.getuuid()
       item.setting.name = item.setting.name + MenuUtils.getSignName()
       item.name = item.setting.name
 
       item.components = item.components.map(cell => {
-        cell = MenuUtils.resetComponentConfig(cell, uuids)
+        cell = MenuUtils.resetComponentConfig(cell)
         return cell
       })
     } else {
-      item = MenuUtils.resetComponentConfig(item, uuids)
+      item = MenuUtils.resetComponentConfig(item)
     }
 
     return item
diff --git a/src/menu/stylecombcontroller/index.jsx b/src/menu/stylecombcontroller/index.jsx
index e47bdd3..5d83165 100644
--- a/src/menu/stylecombcontroller/index.jsx
+++ b/src/menu/stylecombcontroller/index.jsx
@@ -30,6 +30,7 @@
 
 import MKEmitter from '@/utils/events.js'
 import ColorSketch from '@/mob/colorsketch'
+import SysColorSketch from '@/menu/stylecontroller/syscolorsketch'
 import StyleInput from './styleInput'
 import './index.scss'
 
@@ -242,6 +243,7 @@
   }
 
   render () {
+    const { style, borposition } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -251,6 +253,20 @@
         xs: { span: 24 },
         sm: { span: 16 }
       }
+    }
+
+    let borderColor = ''
+
+    if (borposition === 'outer') {
+      borderColor = style.borderColor || ''
+    } else if (borposition === 'left') {
+      borderColor = style.borderLeftColor || ''
+    } else if (borposition === 'right') {
+      borderColor = style.borderRightColor || ''
+    } else if (borposition === 'top') {
+      borderColor = style.borderTopColor || ''
+    } else if (borposition === 'bottom') {
+      borderColor = style.borderBottomColor || ''
     }
 
     return (
@@ -312,7 +328,14 @@
                     label={<FontColorsOutlined title="瀛椾綋棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch onChange={this.changeFontColor} />
+                    <ColorSketch value={style.color || ''} onChange={this.changeFontColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeFontColor} />
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -363,7 +386,14 @@
                     label={<BgColorsOutlined title="鑳屾櫙棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch onChange={this.changeBackgroundColor} />
+                    <ColorSketch value={style.backgroundColor || ''} onChange={this.changeBackgroundColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeBackgroundColor} />
                   </Form.Item>
                 </Col>
               </Panel>
@@ -412,7 +442,14 @@
                     label={<BgColorsOutlined title="杈规棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch onChange={this.changeBorderColor} />
+                    <ColorSketch value={borderColor} onChange={this.changeBorderColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeBorderColor} />
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -432,7 +469,14 @@
                     label={<BgColorsOutlined title="闃村奖棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch onChange={this.changeShadowColor} />
+                    <ColorSketch value={style.shadow || ''} onChange={this.changeShadowColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeShadowColor} />
                   </Form.Item>
                 </Col>
               </Panel>
diff --git a/src/menu/stylecombcontroller/styleInput/index.jsx b/src/menu/stylecombcontroller/styleInput/index.jsx
index 1a2c00c..7426b2d 100644
--- a/src/menu/stylecombcontroller/styleInput/index.jsx
+++ b/src/menu/stylecombcontroller/styleInput/index.jsx
@@ -140,7 +140,7 @@
       <div className="style-input-box">
         <Input value={value} addonAfter={
           options.length > 1 ?
-          <Select value={<span>{unit}</span>} onChange={this.changeUnit}>
+          <Select value={unit} onChange={this.changeUnit}>
             {options.map(item => <Option key={item} value={item}>{item}</Option>)}
           </Select> :
           <div className="single-unit">{unit}</div>
diff --git a/src/menu/stylecombcontroller/styleInput/index.scss b/src/menu/stylecombcontroller/styleInput/index.scss
index 5b4266b..0844abd 100644
--- a/src/menu/stylecombcontroller/styleInput/index.scss
+++ b/src/menu/stylecombcontroller/styleInput/index.scss
@@ -1,7 +1,7 @@
 .style-input-box {
   line-height: 32px;
   .ant-select {
-    width: 60px!important;
+    width: 65px!important;
   }
   .single-unit {
     width: 38px;
diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx
index 053ee15..e06a198 100644
--- a/src/menu/stylecontroller/index.jsx
+++ b/src/menu/stylecontroller/index.jsx
@@ -35,6 +35,7 @@
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import StyleInput from './styleInput'
+import SysColorSketch from './syscolorsketch'
 import MainLogo from '@/assets/img/main-logo.png'
 import './index.scss'
 
@@ -54,7 +55,8 @@
     fonts: null,
     backgroundImage: '',
     options: [],
-    borposition: 'outer'
+    borposition: 'outer',
+    type: ''
   }
 
   callback = null
@@ -77,7 +79,7 @@
     MKEmitter.removeListener('changeStyle', this.initStyle)
   }
 
-  initStyle = (options, style = {}, callback) => {
+  initStyle = (options, style = {}, callback, type) => {
     let backgroundImage = ''
     if (style.backgroundImage && /^url/ig.test(style.backgroundImage)) {
       backgroundImage = style.backgroundImage.replace(/^url\(/ig, '').replace(/\)$/ig, '')
@@ -115,6 +117,7 @@
 
     this.setState({
       visible: true,
+      type: type || '',
       fonts: fonts,
       card: card,
       options: options,
@@ -164,12 +167,16 @@
     this.callback = null
   }
 
-  updateStyle = (style) => {
+  updateStyle = (style, prop) => {
     const { card } = this.state
 
     let _style = {
       ...card,
       ...style
+    }
+
+    if (prop && !_style[prop]) {
+      delete _style[prop]
     }
 
     this.setState({
@@ -275,7 +282,7 @@
    * @description 淇敼鑳屾櫙棰滆壊 锛岄鑹叉帶浠�
    */
   changeBackgroundColor = (val) => {
-    this.updateStyle({backgroundColor: val})
+    this.updateStyle({backgroundColor: val}, 'backgroundColor')
   }
 
   changeBackground = (val) => {
@@ -435,21 +442,11 @@
   }
 
   changeWidth = (val) => {
-    let _val = val
-    if (_val === '0px') {
-      _val = 'auto'
-    }
-
-    this.updateStyle({width: _val})
+    this.updateStyle({width: val === '0px' ? '' : val}, 'width')
   }
 
   changeHeight = (val) => {
-    let _val = val
-    if (_val === '0px') {
-      _val = 'auto'
-    }
-
-    this.updateStyle({height: _val})
+    this.updateStyle({height: val === '0px' ? '' : val}, 'height')
   }
 
   changeNormalStyle = (val, type) => {
@@ -457,7 +454,7 @@
   }
 
   render () {
-    const { card, options, backgroundImage, borposition, fonts } = this.state
+    const { card, options, backgroundImage, borposition, fonts, type } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -485,7 +482,7 @@
         maskStyle={{opacity: 0.1}}
         visible={this.state.visible}
       >
-        <div className="menu-style-controller">
+        <div className={'menu-style-controller ' + (type || '')}>
           <Form {...formItemLayout}>
             {card ? <Collapse expandIconPosition="right" destroyInactivePanel={true} defaultActiveKey={options[0]}>
               {options.includes('width') ? <Panel header="瀹藉害" key="width">
@@ -495,7 +492,7 @@
                     label={<ColumnWidthOutlined title="瀹藉害"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw', '%']} onChange={this.changeWidth}/>
+                    <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw', '%', 'auto']} onChange={this.changeWidth}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -566,6 +563,13 @@
                   >
                     <ColorSketch value={card.color || 'rgba(0, 0, 0, 0.85)'} onChange={this.changeFontColor} />
                   </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeFontColor} />
+                  </Form.Item>
                 </Col> : null}
                 {fonts.includes('fontStyle') ? <Col span={24}>
                   <Form.Item
@@ -609,13 +613,20 @@
                 </Col> : null}
               </Panel> : null}
               {options.includes('background') || options.includes('backgroundColor') ? <Panel header="鑳屾櫙" key="background">
-                <Col span={24}>
+                <Col span={24} className="bg-color-panel">
                   <Form.Item
                     colon={false}
                     label={<BgColorsOutlined title="鑳屾櫙棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <ColorSketch value={card.backgroundColor || '#ffffff'} onChange={this.changeBackgroundColor} />
+                    <ColorSketch allowClear={true} value={card.backgroundColor || ''} onChange={this.changeBackgroundColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeBackgroundColor} />
                   </Form.Item>
                 </Col>
                 {window.develop === true ? <Col span={24}>
@@ -627,7 +638,7 @@
                     <Input value={card.background || ''} onChange={(e) => this.changeBackground(e.target.value)} />
                   </Form.Item>
                 </Col> : null}
-                {!options.includes('backgroundColor') ? <Col span={24}>
+                {!options.includes('backgroundColor') ? <Col span={24} className="bg-image-panel">
                   <Form.Item
                     colon={false}
                     label={<PictureOutlined title="鑳屾櫙鍥剧墖"/>}
@@ -675,8 +686,14 @@
                   >
                     <Select defaultValue={card.backgroundPosition || 'center'} onChange={this.changeBackgroundPositon}>
                       <Option value="center">center</Option>
-                      <Option value="top">top</Option>
-                      <Option value="bottom">bottom</Option>
+                      <Option value="center top">center top</Option>
+                      <Option value="center bottom">center bottom</Option>
+                      <Option value="left top">left top</Option>
+                      <Option value="left center">left center</Option>
+                      <Option value="left bottom">left bottom</Option>
+                      <Option value="right top">right top</Option>
+                      <Option value="right center">right center</Option>
+                      <Option value="right bottom">right bottom</Option>
                     </Select>
                   </Form.Item>
                 </Col> : null}
@@ -754,11 +771,18 @@
                     label={<BgColorsOutlined title="杈规棰滆壊"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    {borposition === 'outer' ? <ColorSketch defaultValue={card.borderColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'left' ? <ColorSketch defaultValue={card.borderLeftColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'right' ? <ColorSketch defaultValue={card.borderRightColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'top' ? <ColorSketch defaultValue={card.borderTopColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
-                    {borposition === 'bottom' ? <ColorSketch defaultValue={card.borderBottomColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'outer' ? <ColorSketch value={card.borderColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'left' ? <ColorSketch value={card.borderLeftColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'right' ? <ColorSketch value={card.borderRightColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'top' ? <ColorSketch value={card.borderTopColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                    {borposition === 'bottom' ? <ColorSketch value={card.borderBottomColor || 'transparent'} onChange={this.changeBorderColor} /> : null}
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeBorderColor} />
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -779,6 +803,13 @@
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
                     <ColorSketch value={card.shadowColor || 'transparent'} onChange={this.changeShadowColor} />
+                  </Form.Item>
+                  <Form.Item
+                    colon={false}
+                    label={<BgColorsOutlined title="绯荤粺鑹�"/>}
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <SysColorSketch onChange={this.changeShadowColor} />
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -907,7 +938,7 @@
                     label={<ColumnHeightOutlined title="鏈�灏忛珮搴�"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.minHeight || '28px'} options={['px']} onChange={(val) => this.changeNormalStyle(val, 'minHeight')}/>
+                    <StyleInput defaultValue={card.minHeight || ''} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'minHeight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
diff --git a/src/menu/stylecontroller/index.scss b/src/menu/stylecontroller/index.scss
index 514e0b1..8940758 100644
--- a/src/menu/stylecontroller/index.scss
+++ b/src/menu/stylecontroller/index.scss
@@ -82,6 +82,14 @@
               .color-sketch-block {
                 position: relative;
                 top: 10px;
+                .color-sketch-value {
+                  .anticon-close-circle {
+                    background: transparent;
+                  }
+                  .anticon-close-circle:hover {
+                    color: #ffffff;
+                  }
+                }
               }
               .color-sketch-block + .ant-input {
                 float: right;
@@ -126,6 +134,11 @@
     }
   }
 }
+.menu-style-controller.mk-picture {
+  .bg-image-panel {
+    display: none;
+  }
+}
 
 .margin-popover {
   padding-top: 0px;
diff --git a/src/menu/stylecontroller/styleInput/index.jsx b/src/menu/stylecontroller/styleInput/index.jsx
index 8eea049..d7661d0 100644
--- a/src/menu/stylecontroller/styleInput/index.jsx
+++ b/src/menu/stylecontroller/styleInput/index.jsx
@@ -48,6 +48,8 @@
         unit = 'vw'
       } else if (val.indexOf('vh') > -1) {
         unit = 'vh'
+      } else if (val === 'auto' && _options.includes('auto')) {
+        unit = 'auto'
       }
     }
 
@@ -135,8 +137,14 @@
     const { value } = this.state
 
     this.setState({unit: val})
-    if (value && this.props.onChange) {
-      this.props.onChange(`${value}${val}`)
+
+    if (val === 'auto') {
+      this.setState({value: ''})
+      this.props.onChange('auto')
+    } else {
+      if (value && this.props.onChange) {
+        this.props.onChange(`${value}${val}`)
+      }
     }
   }
 
@@ -145,7 +153,7 @@
 
     return (
       <div className="style-input-box">
-        <Input value={value} addonAfter={
+        <Input value={value} disabled={unit === 'auto'} addonAfter={
           options.length > 1 ?
           <Select value={unit} onChange={this.changeUnit}>
             {options.map(item => <Option key={item} value={item}>{item}</Option>)}
diff --git a/src/menu/stylecontroller/styleInput/index.scss b/src/menu/stylecontroller/styleInput/index.scss
index 5b4266b..0844abd 100644
--- a/src/menu/stylecontroller/styleInput/index.scss
+++ b/src/menu/stylecontroller/styleInput/index.scss
@@ -1,7 +1,7 @@
 .style-input-box {
   line-height: 32px;
   .ant-select {
-    width: 60px!important;
+    width: 65px!important;
   }
   .single-unit {
     width: 38px;
diff --git a/src/menu/stylecontroller/syscolorsketch/index.jsx b/src/menu/stylecontroller/syscolorsketch/index.jsx
new file mode 100644
index 0000000..e596a77
--- /dev/null
+++ b/src/menu/stylecontroller/syscolorsketch/index.jsx
@@ -0,0 +1,44 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+
+import './index.scss'
+
+class SysColorSketch extends Component {
+  static propTpyes = {
+    onChange: PropTypes.func
+  }
+  state = {
+    colors: ['#1890ff', '#40a9ff', '#69c0ff', '#91d5ff', '#bae7ff', '#e6f7ff']
+  }
+
+  handleChange = (color) => {
+    let _color = 'var(--mk-sys-color)'
+    if (color === '#1890ff') {
+      _color = 'var(--mk-sys-color)'
+    } else if (color === '#40a9ff') {
+      _color = 'var(--mk-sys-color5)'
+    } else if (color === '#69c0ff') {
+      _color = 'var(--mk-sys-color4)'
+    } else if (color === '#91d5ff') {
+      _color = 'var(--mk-sys-color3)'
+    } else if (color === '#bae7ff') {
+      _color = 'var(--mk-sys-color2)'
+    } else if (color === '#e6f7ff') {
+      _color = 'var(--mk-sys-color1)'
+    }
+
+    this.props.onChange(_color)
+  }
+
+  render() {
+    const { colors } = this.state
+
+    return (
+      <div className="sys-color-sketch-block">
+        {colors.map(color => <span key={color} onClick={() => this.handleChange(color)} style={ {background: color} }></span>)}
+      </div>
+    )
+  }
+}
+
+export default SysColorSketch
\ No newline at end of file
diff --git a/src/menu/stylecontroller/syscolorsketch/index.scss b/src/menu/stylecontroller/syscolorsketch/index.scss
new file mode 100644
index 0000000..a948d17
--- /dev/null
+++ b/src/menu/stylecontroller/syscolorsketch/index.scss
@@ -0,0 +1,13 @@
+.sys-color-sketch-block {
+  height: 40px;
+  width: 100%;
+
+  span {
+    display: inline-block;
+    width: 20px;
+    height: 20px;
+    margin-right: 10px;
+    cursor: pointer;
+    vertical-align: middle;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/tablenodes/index.jsx b/src/menu/tablenodes/index.jsx
index 36281b2..e903da7 100644
--- a/src/menu/tablenodes/index.jsx
+++ b/src/menu/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 } from 'antd'
+import { Modal, Button, notification, Spin, Input, message } from 'antd'
 import { ForkOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -158,6 +158,7 @@
               id: 'par' + i,
               direction: 'left',
               color: '#5AD8A6',
+              node: 'table',
               children: []
             }
 
@@ -232,7 +233,12 @@
     if (menu.direction !== 'right') return
 
     if (menu.depth === 1) {
+      sessionStorage.setItem('mk-table-node', menu.label)
       window.open('#/hs')
+
+      setTimeout(() => {
+        sessionStorage.removeItem('mk-table-node')
+      }, 50)
     } else if (menu.param) {
       if (menu.param.type === 'admin') {
         if (menu.param.MenuType === 'custom') {
@@ -354,6 +360,23 @@
           }
         })
 
+        if (model.direction === 'left') {
+          if (model.node === 'table') {
+            model.fontcolor = '#1890ff'
+            this.graph.updateItem(item, model, false)
+
+            let oInput = document.createElement('input')
+            oInput.value = model.label
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+            
+            message.success('琛ㄥ悕澶嶅埗鎴愬姛銆�')
+          }
+          return
+        }
+
         model.fontcolor = '#1890ff'
         this.graph.updateItem(item, model, false)
         
diff --git a/src/mob/components/formdragelement/card.jsx b/src/mob/components/formdragelement/card.jsx
index 020a096..1ca1c3b 100644
--- a/src/mob/components/formdragelement/card.jsx
+++ b/src/mob/components/formdragelement/card.jsx
@@ -212,6 +212,8 @@
         </div>
       </div>
     </div>)
+  } else if (card.type === 'vercode') {
+    formItem = <div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control"><span style={{color: '#bcbcbc'}}>{card.placeholder || ''}</span></div><div className="am-list-extra" style={{width: 'auto', height: 'auto', backgroundColor: '#fafafa', padding: '0 15px'}}>鑾峰彇楠岃瘉鐮�</div></div></div>
   }
 
   let style = {...card.style}
diff --git a/src/mob/components/formdragelement/index.jsx b/src/mob/components/formdragelement/index.jsx
index 4ab72c5..bfeaf84 100644
--- a/src/mob/components/formdragelement/index.jsx
+++ b/src/mob/components/formdragelement/index.jsx
@@ -102,6 +102,10 @@
       newcard.span = 24
       newcard.focus = true
 
+      if (item.subType === 'textarea') {
+        newcard.required = 'false'
+      }
+
       let targetId = ''
 
       if (item.dropTargetId) {
diff --git a/src/mob/components/search/single-search/index.jsx b/src/mob/components/search/single-search/index.jsx
index 43debf2..514a906 100644
--- a/src/mob/components/search/single-search/index.jsx
+++ b/src/mob/components/search/single-search/index.jsx
@@ -139,7 +139,16 @@
         } trigger="hover">
           <ToolOutlined />
         </Popover>
-        <div className="component-name"><div className="center">{card.name}</div></div>
+        <div className="component-name">
+          <div className="center" onDoubleClick={() => {
+            let oInput = document.createElement('input')
+            oInput.value = card.uuid
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+          }}>{card.name}</div>
+        </div>
       </div>
     )
   }
diff --git a/src/mob/components/tabs/tabcomponents/card.jsx b/src/mob/components/tabs/tabcomponents/card.jsx
index 700de18..24dc025 100644
--- a/src/mob/components/tabs/tabcomponents/card.jsx
+++ b/src/mob/components/tabs/tabcomponents/card.jsx
@@ -26,8 +26,9 @@
 const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -89,6 +90,8 @@
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'card' && card.subtype === 'propcard') {
       return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
       return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'propcard') {
@@ -98,7 +101,7 @@
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'menubar') {
diff --git a/src/mob/components/tabs/tabcomponents/index.jsx b/src/mob/components/tabs/tabcomponents/index.jsx
index d202e5e..1d146b5 100644
--- a/src/mob/components/tabs/tabcomponents/index.jsx
+++ b/src/mob/components/tabs/tabcomponents/index.jsx
@@ -34,6 +34,25 @@
     handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)})
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...config, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -139,6 +158,7 @@
           card={card}
           moveCard={moveCard}
           delCard={deleteCard}
+          unGroup={unGroup}
           findCard={findCard}
           updateConfig={updateConfig}
         />
diff --git a/src/mob/components/topbar/normal-navbar/options.jsx b/src/mob/components/topbar/normal-navbar/options.jsx
index 2a395e0..5fbab72 100644
--- a/src/mob/components/topbar/normal-navbar/options.jsx
+++ b/src/mob/components/topbar/normal-navbar/options.jsx
@@ -87,6 +87,7 @@
       controlFields: [
         {field: 'reload', values: ['back']},
         {field: 'linkmenu', values: ['scan']},
+        {field: 'prefix', values: ['scan']},
       ],
       span: 24
     },
@@ -179,6 +180,14 @@
       options: menulist
     },
     {
+      type: 'text',
+      field: 'prefix',
+      label: '鍓嶇紑',
+      initval: wrap.prefix || '',
+      tooltip: '鎵爜淇℃伅灏嗕笌鍓嶇紑鎷兼帴鍚庢墽琛屻�傛敞锛氳烦杞彍鍗曢渶浠kbid寮�澶淬��',
+      required: false
+    },
+    {
       type: 'radio',
       field: 'minishow',
       label: '灏忕▼搴忎腑',
diff --git a/src/mob/mobshell/card.jsx b/src/mob/mobshell/card.jsx
index 517db7f..fdca2fd 100644
--- a/src/mob/mobshell/card.jsx
+++ b/src/mob/mobshell/card.jsx
@@ -32,8 +32,9 @@
 const OfficialAccount = asyncComponent(() => import('@/mob/components/official'))
 const ShareCode = asyncComponent(() => import('@/mob/components/sharecode'))
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -72,21 +73,21 @@
   }
 
   let col = 'ant-col-' + (card.width || 24)
-  if (card.type === 'login') {
-    let height = ''
-    if (card.wrap && card.wrap.height) {
-      // scaleview
-      height = card.wrap.height.replace(/\d+vw/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
-        // return parseFloat(word) * 350 / 100 + 'px'
-      }).replace(/\d+vh/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
-        // return parseFloat(word) * 615 / 100 + 'px'
-      })
-    }
+  // if (card.type === 'login') {
+  //   let height = ''
+  //   if (card.wrap && card.wrap.height) {
+  //     // scaleview
+  //     height = card.wrap.height.replace(/\d+vw/ig, (word) => {
+  //       return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
+  //       // return parseFloat(word) * 350 / 100 + 'px'
+  //     }).replace(/\d+vh/ig, (word) => {
+  //       return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
+  //       // return parseFloat(word) * 615 / 100 + 'px'
+  //     })
+  //   }
     
-    style.minHeight = height
-  }
+  //   style.minHeight = height
+  // }
 
   const getCardComponent = () => {
     if (card.type === 'bar' || card.type === 'line') {
@@ -111,6 +112,8 @@
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'card' && card.subtype === 'propcard') {
       return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
       return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'propcard') {
@@ -120,7 +123,7 @@
     } else if (card.type === 'table' && card.subtype === 'normaltable') {
       return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
diff --git a/src/mob/mobshell/index.jsx b/src/mob/mobshell/index.jsx
index 0063894..c7b5442 100644
--- a/src/mob/mobshell/index.jsx
+++ b/src/mob/mobshell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -220,6 +239,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/mob/modalconfig/index.jsx b/src/mob/modalconfig/index.jsx
index 97d305d..8bcad78 100644
--- a/src/mob/modalconfig/index.jsx
+++ b/src/mob/modalconfig/index.jsx
@@ -4,7 +4,7 @@
 import { DndProvider } from 'react-dnd'
 import HTML5Backend from 'react-dnd-html5-backend'
 import moment from 'moment'
-import { Button, Modal, Collapse, notification, Switch } from 'antd'
+import { Button, Modal, Collapse, notification, Switch, message } from 'antd'
 import { LeftOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
@@ -127,7 +127,7 @@
    * 3銆佽缃紪杈戝弬鏁伴」-formlist
    */
   handleForm = (_card) => {
-    const { componentConfig } = this.props
+    const { componentConfig, btn } = this.props
     const { config } = this.state
     let card = fromJS(_card).toJS()
     let _inputfields = []
@@ -140,35 +140,28 @@
     let index = null
     uniq.set(card.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     config.fields.forEach((item, i) => {
       if (card.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && card.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
       if (card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
 
@@ -179,17 +172,14 @@
 
         _linkableFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
-        _linkIndex++
       }
     })
-
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
 
     if (index !== null) {
       if (index === 0) {
@@ -199,15 +189,19 @@
       }
     }
 
-    componentConfig.columns.forEach(col => {
+    let columns = componentConfig.columns
+    if (btn.$sub) {
+      columns = componentConfig.subColumns || []
+    }
+
+    columns.forEach(col => {
       if (col.field && !uniq.has(col.field)) {
         uniq.set(col.field, true)
 
         _linkableFields.push({
           field: col.field,
-          label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+          label: col.label + '-鏄剧ず鍒�'
         })
-        _linkIndex++
       }
     })
 
@@ -220,7 +214,7 @@
       standardform,
       visible: true,
       card: card,
-      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, componentConfig.columns)
+      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, columns)
     })
   }
 
@@ -267,7 +261,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -415,12 +409,83 @@
     })
   }
 
-  insert = (config) => {
+  insert = (config, type) => {
+    if (type === 'forms') {
+      let _config = fromJS(this.state.config).toJS()
+
+      if (_config.fields.length > 0) {
+        let that = this
+        _config.fields = config.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        confirm({
+          title: '纭畾鏇挎崲琛ㄥ崟鍚楋紵',
+          content: '鍘熻〃鍗曞皢鍒犻櫎銆�',
+          onOk() {
+            that.setState({
+              config: _config
+            })
+          },
+          onCancel() {}
+        })
+      } else {
+        _config.fields = config.fields.map(item => {
+          item.uuid = Utils.getuuid()
+          return item
+        })
+
+        this.setState({
+          config: _config
+        })
+        notification.success({
+          top: 92,
+          message: '绮樿创鎴愬姛锛�',
+          duration: 2
+        })
+      }
+      return
+    }
+
     this.setState({
       config
     }, () => {
       this.handleForm(config.fields[config.fields.length - 1])
     })
+  }
+
+  triggerCopy = () => {
+    const { config } = this.state
+
+    let val = {
+      copyType: 'forms',
+      fields: config.fields || []
+    }
+
+    if (val.fields.length === 0) {
+      message.warning('琛ㄥ崟鍏冪礌涓嶅彲涓虹┖锛�')
+      return
+    }
+
+    try {
+      val = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    } catch (e) {
+      console.warn(e)
+      message.warning('澶嶅埗澶辫触锛岃閲嶈瘯锛�')
+      val = ''
+    }
+
+    if (val) {
+      let oInput = document.createElement('input')
+      oInput.value = val
+      document.body.appendChild(oInput)
+      oInput.select()
+      document.execCommand('Copy')
+      document.body.removeChild(oInput)
+
+      message.success('澶嶅埗鎴愬姛銆�')
+    }
   }
 
   clearConfig = () => {
@@ -459,6 +524,7 @@
             <Button icon="setting" onClick={this.changeSetting}>璁剧疆</Button>
             <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>淇濆瓨</Button>
             <Button onClick={this.cancelConfig}>杩斿洖</Button>
+            <Button type="primary" style={{background: '#26C281', border: 'none'}} onClick={this.triggerCopy}>澶嶅埗</Button>
             <PasteComponent config={config} updateConfig={this.insert} />
             <Button type="danger" onClick={this.clearConfig}>娓呯┖</Button>
             <Switch checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
diff --git a/src/mob/modalconfig/pastecomponent/index.jsx b/src/mob/modalconfig/pastecomponent/index.jsx
index fea6610..26b033d 100644
--- a/src/mob/modalconfig/pastecomponent/index.jsx
+++ b/src/mob/modalconfig/pastecomponent/index.jsx
@@ -20,7 +20,11 @@
   pasteSubmit = () => {
     const { config } = this.props
     this.pasteFormRef.handleConfirm().then(res => {
-      if (res.copyType !== 'form') {
+      if (res.copyType === 'forms') {
+        this.props.updateConfig(res, 'forms')
+        this.setState({visible: false})
+        return
+      } else if (res.copyType !== 'form') {
         notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
         return
       }
diff --git a/src/mob/modalconfig/source.jsx b/src/mob/modalconfig/source.jsx
index 04ed6a4..c7a4046 100644
--- a/src/mob/modalconfig/source.jsx
+++ b/src/mob/modalconfig/source.jsx
@@ -109,6 +109,11 @@
     type: 'form',
     label: '鍏紡',
     subType: 'formula',
+  },
+  {
+    type: 'form',
+    label: '楠岃瘉鐮�',
+    subType: 'vercode',
   }
 ]
 
diff --git a/src/mob/modulesource/option.jsx b/src/mob/modulesource/option.jsx
index 1fc604b..f4b8529 100644
--- a/src/mob/modulesource/option.jsx
+++ b/src/mob/modulesource/option.jsx
@@ -1,7 +1,7 @@
 import bar from '@/assets/mobimg/bar.png'
 import bar1 from '@/assets/mobimg/bar1.png'
 import line from '@/assets/mobimg/line.png'
-import line1 from '@/assets/mobimg/line1.png'
+// import line1 from '@/assets/mobimg/line1.png'
 import tabs from '@/assets/mobimg/tabs.png'
 import group from '@/assets/mobimg/group.png'
 import card1 from '@/assets/mobimg/card1.png'
@@ -41,6 +41,7 @@
   { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', width: 24 },
   { type: 'menu', url: card2, component: 'balcony', subtype: 'balcony', title: '娴姩鍗�', width: 24 },
+  { type: 'menu', url: card1, component: 'card', subtype: 'dualdatacard', title: '鍙岄噸鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: form, component: 'form', subtype: 'simpleform', title: '琛ㄥ崟', width: 24 },
   { type: 'menu', url: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟锛堝垎姝ワ級', width: 24 },
   { type: 'menu', url: tabForm, component: 'form', subtype: 'tabform', title: '琛ㄥ崟锛坱ab椤碉級', width: 24 },
@@ -50,7 +51,7 @@
   { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
   { type: 'menu', url: timeline, component: 'timeline', subtype: 'timeline', title: '鏃堕棿杞�', width: 24 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
-  { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
+  // { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
   { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '鏌辩姸鍥�', width: 24 },
   { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
   { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 24 },
diff --git a/src/pc/bgcontroller/index.jsx b/src/pc/bgcontroller/index.jsx
index 35def8d..35f3fd0 100644
--- a/src/pc/bgcontroller/index.jsx
+++ b/src/pc/bgcontroller/index.jsx
@@ -2,13 +2,14 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { Form, Select, Input } from 'antd'
-import { ArrowUpOutlined, ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons'
+import { ArrowUpOutlined, ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined, BgColorsOutlined, ColumnWidthOutlined } from '@ant-design/icons'
 
 import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
 const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
 const StyleInput = asyncComponent(() => import('@/menu/stylecontroller/styleInput'))
+const SysColorSketch = asyncComponent(() => import('@/menu/stylecontroller/syscolorsketch'))
 const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
 const { Option } = Select
 
@@ -150,8 +151,52 @@
     }
   }
 
+  /**
+   * @description 淇敼闃村奖棰滆壊 锛岄鑹叉帶浠�
+   */
+  changeShadowColor = (val) => {
+    let config = fromJS(this.props.config).toJS()
+    config.style.shadowColor = val
+    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
+
+    this.props.updateConfig(config)
+  }
+
+  /**
+   * @description 淇敼闃村奖棰滆壊 锛岄鑹叉帶浠�
+   */
+  changeShadowBlur = (val) => {
+    let config = fromJS(this.props.config).toJS()
+    config.style.shadowBlur = val
+    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
+
+    this.props.updateConfig(config)
+  }
+
+  /**
+   * @description 淇敼闃村奖棰滆壊 锛岄鑹叉帶浠�
+   */
+  changeHShadow = (val) => {
+    let config = fromJS(this.props.config).toJS()
+    config.style.hShadow = val
+    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
+
+    this.props.updateConfig(config)
+  }
+
+  /**
+   * @description 淇敼闃村奖棰滆壊 锛岄鑹叉帶浠�
+   */
+  changeVShadow = (val) => {
+    let config = fromJS(this.props.config).toJS()
+    config.style.vShadow = val
+    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
+
+    this.props.updateConfig(config)
+  }
+
   render () {
-    const { config } = this.props
+    const { config, type } = this.props
     const { backgroundColor, backgroundImage, backgroundSize, backgroundRepeat, backgroundPosition, background } = this.state
     const formItemLayout = {
       labelCol: {
@@ -174,8 +219,11 @@
           >
             <StyleInput defaultValue={config.style.width || '100%'} options={['px', '%', 'vw']} onChange={(val) => this.changePadding(val, 'width')}/>
           </Form.Item> */}
-          <Form.Item className="color-control" colon={false} label="鑳屾櫙鑹�">
+          <Form.Item className="color-control" style={{marginBottom: '0px'}} colon={false} label="鑳屾櫙鑹�">
             <ColorSketch value={backgroundColor} onChange={this.changeBackgroundColor} />
+          </Form.Item>
+          <Form.Item colon={false} label="绯荤粺鑹�">
+            <SysColorSketch onChange={this.changeBackgroundColor} />
           </Form.Item>
           {window.develop === true ? <Form.Item colon={false} label="棰滆壊">
             <Input value={background} onChange={(e) => this.changeBackground(e.target.value)} />
@@ -209,6 +257,24 @@
               <Option value="bottom">bottom</Option>
             </Select>
           </Form.Item>
+          {type === 'mob_popview' ? <p className="normal-view" style={{borderBottom: '1px solid #eaeaea', color: '#40a9ff'}}>闃村奖</p> : null}
+          {type === 'mob_popview' ? <>
+            <Form.Item colon={false} label={<BgColorsOutlined title="闃村奖棰滆壊"/>}>
+              <ColorSketch value={config.style.shadowColor || 'transparent'} onChange={this.changeShadowColor} />
+            </Form.Item>
+            <Form.Item colon={false} label={<BgColorsOutlined title="绯荤粺鑹�"/>}>
+              <SysColorSketch onChange={this.changeShadowColor} />
+            </Form.Item>
+            <Form.Item colon={false} label={<ColumnWidthOutlined title="妯$硦璺濈"/>}>
+              <StyleInput defaultValue={config.style.shadowBlur || '0px'} options={['px']} onChange={this.changeShadowBlur}/>
+            </Form.Item>
+            <Form.Item colon={false} label={<ArrowRightOutlined title="姘村钩浣嶇疆"/>}>
+              <StyleInput defaultValue={config.style.hShadow || '0px'} options={['px']} onChange={this.changeHShadow}/>
+            </Form.Item>
+            <Form.Item colon={false} label={<ArrowDownOutlined title="鍨傜洿浣嶇疆"/>}>
+              <StyleInput defaultValue={config.style.vShadow || '0px'} options={['px']} onChange={this.changeVShadow}/>
+            </Form.Item>
+          </> : null}
           <p className="normal-view" style={{borderBottom: '1px solid #eaeaea', color: '#40a9ff'}}>鍐呰竟璺�</p>
           <Form.Item
             colon={false}
diff --git a/src/pc/components/login/normal-login/index.jsx b/src/pc/components/login/normal-login/index.jsx
index 286b250..60a3e17 100644
--- a/src/pc/components/login/normal-login/index.jsx
+++ b/src/pc/components/login/normal-login/index.jsx
@@ -71,6 +71,11 @@
       if (_card.wrap.classify === 'signin') {
         active = 'signin'
       }
+      if (!_card.style.minHeight && _card.wrap.height) {
+        _card.style.minHeight = _card.wrap.height
+        delete _card.wrap.height
+      }
+
       this.setState({
         active,
         card: _card
@@ -114,7 +119,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', ['width', 'background', 'border', 'padding', 'margin', 'clear'], card.style, this.getStyle)
+    MKEmitter.emit('changeStyle', ['width', 'background', 'border', 'padding', 'margin', 'clear', 'minHeight'], card.style, this.getStyle)
   }
 
   getStyle = (style) => {
@@ -190,7 +195,14 @@
         {card.wrap.signWays && active === 'signin' ? <SignForm wrap={card.wrap} changeway={() => this.setState({active: 'login'})}/> : null}
         <div className="component-name">
           <div className="center">
-            <div className="title">{card.name}</div>
+            <div className="title" onDoubleClick={() => {
+              let oInput = document.createElement('input')
+              oInput.value = card.uuid
+              document.body.appendChild(oInput)
+              oInput.select()
+              document.execCommand('Copy')
+              document.body.removeChild(oInput)
+            }}>{card.name}</div>
             <div className="content">
               {card.errors && card.errors.map((err, index) => {
                 if (err.level === 0) {
diff --git a/src/pc/components/login/normal-login/options.jsx b/src/pc/components/login/normal-login/options.jsx
index 0c49d34..634d7bf 100644
--- a/src/pc/components/login/normal-login/options.jsx
+++ b/src/pc/components/login/normal-login/options.jsx
@@ -70,15 +70,15 @@
     //   precision: 0,
     //   required: false
     // },
-    {
-      type: 'styleInput',
-      field: 'height',
-      label: '鏈�灏忛珮搴�',
-      initval: wrap.height || '',
-      tooltip: '缁勪欢鍗犵敤鐨勬渶灏忛珮搴︼紝鐢ㄤ簬椤甸潰甯冨眬銆�',
-      required: false,
-      options: ['px', 'vh', 'vw', '%']
-    },
+    // {
+    //   type: 'styleInput',
+    //   field: 'height',
+    //   label: '鏈�灏忛珮搴�',
+    //   initval: wrap.height || '',
+    //   tooltip: '缁勪欢鍗犵敤鐨勬渶灏忛珮搴︼紝鐢ㄤ簬椤甸潰甯冨眬銆�',
+    //   required: false,
+    //   options: ['px', 'vh', 'vw', '%']
+    // },
     // {
     //   type: 'styleInput',
     //   field: 'maxWidth',
diff --git a/src/pc/createview/index.jsx b/src/pc/createview/index.jsx
index 580b8cc..be5bdec 100644
--- a/src/pc/createview/index.jsx
+++ b/src/pc/createview/index.jsx
@@ -3,6 +3,7 @@
 import { is, fromJS } from 'immutable'
 import { Button, Modal, notification } from 'antd'
 import moment from 'moment'
+import md5 from 'md5'
 
 import Utils from '@/utils/utils.js'
 import MenuUtils, { getTables } from '@/utils/utils-custom.js'
@@ -158,15 +159,14 @@
           }
 
           if (_config.components) {
-            let uuids = {} // 閲嶇疆鍏叡鏁版嵁婧�
+            let commonId = Utils.getuuid()
             if (_config.interfaces && _config.interfaces.length > 0) {
               config.interfaces = _config.interfaces.map(inter => {
-                uuids[inter.uuid] = this.getuuid()
-                inter.uuid = uuids[inter.uuid]
+                inter.uuid = md5(commonId + inter.uuid)
                 return inter
               })
             }
-            config.components = MenuUtils.resetConfig(_config.components, uuids, res.clearMenu === 'true')
+            config.components = MenuUtils.resetConfig(_config.components, commonId, res.clearMenu === 'true')
             config.tables = _config.tables || []
             config.style = _config.style || {}
             config.statusBarbgColor = _config.statusBarbgColor || ''
diff --git a/src/pc/menushell/card.jsx b/src/pc/menushell/card.jsx
index 085daf7..7cdc671 100644
--- a/src/pc/menushell/card.jsx
+++ b/src/pc/menushell/card.jsx
@@ -31,8 +31,9 @@
 const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
 const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
 const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
+const DoubleDataCard = asyncComponent(() => import('@/menu/components/card/double-data-card'))
 
-const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
+const Card = ({ id, card, moveCard, findCard, delCard, unGroup, updateConfig }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'menu', id, originalIndex },
@@ -71,21 +72,6 @@
   }
   
   let col = ' ant-col ant-col-' + (card.width || 24)
-  if (card.type === 'login') {
-    let height = ''
-    if (card.wrap && card.wrap.height) {
-      // scaleview
-      height = card.wrap.height.replace(/\d+vw/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winWidth || 420) / 100 + 'px'
-        // return parseFloat(word) * 350 / 100 + 'px'
-      }).replace(/\d+vh/ig, (word) => {
-        return parseFloat(word) * (window.GLOB.winHeight || 738) / 100 + 'px'
-        // return parseFloat(word) * 615 / 100 + 'px'
-      })
-    }
-    
-    style.minHeight = height
-  }
 
   const getCardComponent = () => {
     if (card.type === 'bar' || card.type === 'line') {
@@ -114,6 +100,8 @@
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'card' && card.subtype === 'propcard') {
       return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'card' && card.subtype === 'dualdatacard') {
+      return (<DoubleDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'datacard') {
       return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'carousel' && card.subtype === 'propcard') {
@@ -125,7 +113,7 @@
     } else if (card.type === 'table' && card.subtype === 'editable') {
       return (<EditTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'group' && card.subtype === 'normalgroup') {
-      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+      return (<NormalGroup group={card} updateConfig={updateConfig} unGroup={unGroup} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
diff --git a/src/pc/menushell/index.jsx b/src/pc/menushell/index.jsx
index 3bd54a3..32b17b4 100644
--- a/src/pc/menushell/index.jsx
+++ b/src/pc/menushell/index.jsx
@@ -36,6 +36,25 @@
     setCards(_cards)
   }
 
+  const unGroup = (id) => {
+    let { card, index } = findCard(`${id}`)
+    let components = [...card.components].map(item => {
+      if (item.wrap) {
+        item.wrap.width = card.width
+        item.width = card.width
+      } else if (item.plot) {
+        item.plot.width = card.width
+        item.width = card.width
+      }
+      return item
+    })
+    card.components = []
+
+    const _cards = update(cards, { $splice: [[index, 1, card, ...components]] })
+
+    handleList({...menu, components: _cards})
+  }
+
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
@@ -173,6 +192,7 @@
             card={card}
             moveCard={moveCard}
             delCard={deleteCard}
+            unGroup={unGroup}
             findCard={findCard}
             updateConfig={updateConfig}
           />
diff --git a/src/pc/modulesource/option.jsx b/src/pc/modulesource/option.jsx
index db77df6..e5dbf8a 100644
--- a/src/pc/modulesource/option.jsx
+++ b/src/pc/modulesource/option.jsx
@@ -1,7 +1,7 @@
 import bar from '@/assets/mobimg/bar.png'
 import bar1 from '@/assets/mobimg/bar1.png'
 import line from '@/assets/mobimg/line.png'
-import line1 from '@/assets/mobimg/line1.png'
+// import line1 from '@/assets/mobimg/line1.png'
 import tabs from '@/assets/mobimg/tabs.png'
 import group from '@/assets/mobimg/group.png'
 import card1 from '@/assets/mobimg/card1.png'
@@ -37,6 +37,7 @@
   { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', width: 24 },
   { type: 'menu', url: card2, component: 'balcony', subtype: 'balcony', title: '娴姩鍗�', width: 24 },
+  { type: 'menu', url: card1, component: 'card', subtype: 'dualdatacard', title: '鍙岄噸鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟锛堝垎姝ワ級', width: 24 },
   { type: 'menu', url: tabForm, component: 'form', subtype: 'tabform', title: '琛ㄥ崟锛坱ab椤碉級', width: 24 },
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24 },
@@ -47,7 +48,7 @@
   { type: 'menu', url: timeline, component: 'timeline', subtype: 'timeline', title: '鏃堕棿杞�', width: 12 },
   { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '鏍戝舰鍒楄〃', width: 12 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
-  { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
+  // { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '闃舵鎶樼嚎鍥�', width: 24 },
   { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '鏌辩姸鍥�', width: 24 },
   { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
   { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 12 },
diff --git a/src/tabviews/basetable/index.jsx b/src/tabviews/basetable/index.jsx
index 7965a78..e6a783a 100644
--- a/src/tabviews/basetable/index.jsx
+++ b/src/tabviews/basetable/index.jsx
@@ -379,10 +379,21 @@
 
           if (cell.syncComponentId === item.setting.supModule) {
             cell.syncComponentId = ''
+            if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+              cell.execSuccess = 'mainline'
+            }
           }
 
           if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
             cell = this.getPrinter(cell, item.uuid)
+          }
+
+          if (cell.controlField) {
+            if (/,/ig.test(cell.controlVal)) {
+              cell.controlVals = cell.controlVal.split(',')
+            } else {
+              cell.controlVals = [(cell.controlVal || '')]
+            }
           }
 
           return skip || permAction[cell.uuid]
@@ -404,12 +415,23 @@
 
           if (cell.syncComponentId === item.setting.supModule) {
             cell.syncComponentId = ''
+            if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+              cell.execSuccess = 'mainline'
+            }
           }
 
           if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
             cell = this.getPrinter(cell, item.uuid)
           }
 
+          if (cell.controlField) {
+            if (/,/ig.test(cell.controlVal)) {
+              cell.controlVals = cell.controlVal.split(',')
+            } else {
+              cell.controlVals = [(cell.controlVal || '')]
+            }
+          }
+
           return skip || permAction[cell.uuid]
         })
         return col.elements.length !== 0
diff --git a/src/tabviews/basetable/index.scss b/src/tabviews/basetable/index.scss
index 4a12545..ca8acd1 100644
--- a/src/tabviews/basetable/index.scss
+++ b/src/tabviews/basetable/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index f224e98..a1c9987 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -177,7 +177,8 @@
             }
             tab.ContainerId = this.state.ContainerId
 
-            return window.GLOB.mkActions[tab.linkTab]
+            // return window.GLOB.mkActions[tab.linkTab]
+            return tab
           })
         })
       } else {
@@ -319,6 +320,7 @@
       config.action.forEach(item => {
         item.logLabel = MenuName + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
         item.$menuId = this.props.MenuID
+        item.$old = true
         item.ContainerId = this.state.ContainerId
 
         if (item.OpenType === 'funcbutton' && item.funcType === 'print' && item.verify) { // 鎵撳嵃鏈鸿缃�
@@ -336,6 +338,14 @@
             }
           }
         }
+
+        if (item.controlField) {
+          if (/,/ig.test(item.controlVal)) {
+            item.controlVals = item.controlVal.split(',')
+          } else {
+            item.controlVals = [(item.controlVal || '')]
+          }
+        }
         
         if (item.position === 'toolbar') {
           item.$toolbtn = true
diff --git a/src/tabviews/custom/components/card/balcony/index.jsx b/src/tabviews/custom/components/card/balcony/index.jsx
index bf037dd..724f839 100644
--- a/src/tabviews/custom/components/card/balcony/index.jsx
+++ b/src/tabviews/custom/components/card/balcony/index.jsx
@@ -345,7 +345,7 @@
       let _data = {}
 
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -395,20 +395,33 @@
     MKEmitter.emit('mkCheckAll', syncConfig.uuid, e.target.checked)
   }
 
+  triggerButton = () => {
+    const { config, data } = this.state
+
+    if (config.wrap.linkbtn) {
+      MKEmitter.emit('triggerBtnId', config.wrap.linkbtn, data.$$empty ? [] : [data])
+    }
+  }
+
   render() {
     const { config, loading, data, show, syncConfig, syncData, checked } = this.state
 
     if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+
+    let style = {...config.style}
+    if (config.wrap.bgField) {
+      style.backgroundImage = `url('${data[config.wrap.bgField] || ''}')`
+    }
     
     return (
-      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} style={config.style}>
+      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} id={'anchor' + config.uuid} style={style} onClick={this.triggerButton}>
         {loading ?
-          <div className="loading-mask">
+          <div className="loading-mask" onClick={(e) => e.stopPropagation()}>
             <div className="ant-spin-blur"></div>
             <Spin />
           </div> : null
         }
-        {config.wrap.checkAll === 'show' ? <div className="check-all"><Checkbox checked={checked} onChange={this.checkAll}>鍏ㄩ��</Checkbox></div> : null}
+        {config.wrap.checkAll === 'show' ? <div className="check-all" onClick={(e) => e.stopPropagation()}><Checkbox checked={checked} onChange={this.checkAll}>鍏ㄩ��</Checkbox></div> : null}
         <CardCellComponent data={data} syncData={syncData || []} cards={syncConfig || config} cardCell={config} elements={config.elements}/>
       </div>
     )
diff --git a/src/tabviews/custom/components/card/cardItem/index.jsx b/src/tabviews/custom/components/card/cardItem/index.jsx
index 224438e..92777c5 100644
--- a/src/tabviews/custom/components/card/cardItem/index.jsx
+++ b/src/tabviews/custom/components/card/cardItem/index.jsx
@@ -41,15 +41,17 @@
   }
 
   openView = () => {
-    const { card, data, cards } = this.props
+    const { card, data, cards, onClick } = this.props
 
+    onClick && onClick()
+    
     if (!card.setting.click || data.$disabled) return
 
     if (card.setting.click === 'menus' && cards.subtype === 'datacard' && card.$cardType !== 'extendCard') {
       let menu = null
       
       if (card.menus && card.menus.length > 0) {
-        let s = data[card.setting.menuType] || ''
+        let s = data[card.setting.menuType] + ''
         card.menus.forEach(m => {
           if (s !== m.sign) return
           menu = m
@@ -145,8 +147,10 @@
   }
 
   doubleClick = () => {
-    const { card, data, cards } = this.props
+    const { card, data, cards, onDoubleClick } = this.props
 
+    onDoubleClick && onDoubleClick()
+    
     if (card.setting.click !== 'button' || card.setting.clickType !== 'multi' || data.$disabled) return
 
     if (card.setting.linkbtn) {
@@ -161,15 +165,24 @@
   }
 
   render() {
-    const { card, data, cards } = this.props
+    const { card, data, cards, children } = this.props
     let style = {...card.style}
+
+    let bg = null
 
     if (card.setting.bgField) {
       style.backgroundImage = `url('${data[card.setting.bgField] || ''}')`
     }
 
+    if (style.backgroundImage) {
+      bg = <div className="card-background" style={{backgroundImage: style.backgroundImage}}></div>
+      style.backgroundImage = ''
+    }
+
     return (
-      <div className={'card-item-box ' + (card.setting.btnControl || '')} style={style} onClick={this.openView} onDoubleClick={this.doubleClick}>
+      <div className={'card-item-box ' + (card.setting.btnControl || '') + (card.setting.click ? ' mk-pointer' : '')} style={style} onClick={this.openView} onDoubleClick={this.doubleClick}>
+        {bg}
+        {children}
         <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.elements}/>
         {card.setting.type === 'multi' ? <div className={'back-side ' + card.setting.transform} style={card.backStyle}>
           <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.backElements}/>
diff --git a/src/tabviews/custom/components/card/cardItem/index.scss b/src/tabviews/custom/components/card/cardItem/index.scss
index fdf37b0..c6f2f31 100644
--- a/src/tabviews/custom/components/card/cardItem/index.scss
+++ b/src/tabviews/custom/components/card/cardItem/index.scss
@@ -38,6 +38,22 @@
   .back-side.scale {
     transform: scale(0, 0);
   }
+  .card-background {
+    position: absolute;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background-size: inherit;
+    background-position: inherit;
+    background-repeat: inherit;
+  }
+}
+.card-item-box.mk-pointer {
+  cursor: pointer;
+}
+.mk-disabled .card-item-box.mk-pointer {
+  cursor: not-allowed;
 }
 .card-item-box:hover {
   .back-side.up, .back-side.down, .back-side.left, .back-side.right {
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 8f74c29..8d010da 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -475,6 +475,10 @@
           icon = card.icon
         }
 
+        if (!icon && card.noValue === 'hide') { // 绌哄�奸殣钘�
+          return null
+        }
+
         if (!height) { // 鍏煎
           let fontSize = 14
           let lineHeight = 1.5
@@ -558,10 +562,6 @@
         if (url === '' && card.noValue === 'hide') { // 绌哄�奸殣钘�
           return null
         }
-
-        if (_style.borderRadius) {
-          _imagestyle.borderRadius = _style.borderRadius
-        }
   
         if (PicRadio[card.lenWidRadio]) {
           _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
@@ -569,7 +569,10 @@
           _imagestyle.paddingTop = '100%'
         }
 
-        _imagestyle.backgroundSize = card.backgroundSize || 'cover'
+        _imagestyle.borderRadius = _style.borderRadius || 0
+        _imagestyle.backgroundSize = _style.backgroundSize || 'cover'
+        _imagestyle.backgroundPosition = _style.backgroundPosition || 'center'
+        _imagestyle.backgroundRepeat = _style.backgroundRepeat || 'no-repeat'
   
         if (card.link) {
           _style.cursor = 'pointer'
@@ -823,24 +826,12 @@
         )
       } else if (card.eleType === 'button') {
         let _disabled = data.$disabled
-        if (card.control === 'hidden') {
-          let s = data[card.controlField] !== undefined ? data[card.controlField] + '' : ''
-          if (s === card.controlVal || (card.controlVal && card.controlVal.split(',').includes(s))) {
-            return null
-          }
-        } else if (card.control === 'disabled') {
-          let s = data[card.controlField] !== undefined ? data[card.controlField] + '' : ''
-          if (s === card.controlVal || (card.controlVal && card.controlVal.split(',').includes(s))) {
-            _disabled = true
-          }
-        }
-        
         let _data = [data]
   
         if (data.$$type === 'extendCard') {
           _data = data.$$selectedData || []
         } else if (card.$sync) {
-          _data = this.props.syncData
+          _data = this.props.syncData || []
         } else if (data.$$empty) {
           _data = []
         }
diff --git a/src/tabviews/custom/components/card/cardcellList/index.scss b/src/tabviews/custom/components/card/cardcellList/index.scss
index 1eb878d..2ce260c 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.scss
+++ b/src/tabviews/custom/components/card/cardcellList/index.scss
@@ -83,6 +83,7 @@
     background-size: cover;
   }
   .mk-cell-btn {
+    min-height: 0px;
     > div {width: 100%;max-width: 100%;}
     button:not(.ant-switch) {
       width: 100%;
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index 7a4dd46..95fde61 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -99,8 +99,6 @@
 
     _config.subcards = null
     
-    let _cols = new Map()
-
     let _data = null
     let _sync = _config.setting.sync === 'true'
 
@@ -144,24 +142,6 @@
         }
       }
     }
-
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
-    _card.elements = _card.elements.map(item => {
-      if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-        item.decimal = _cols.get(item.field).decimal || 0
-      }
-      return item
-    })
-    _card.backElements = _card.backElements.map(item => {
-      if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-        item.decimal = _cols.get(item.field).decimal || 0
-      }
-      return item
-    })
 
     let supComs = null
     if (_config.wrap.supType === 'multi') {
@@ -452,15 +432,29 @@
     if (config.uuid !== menuId) return
 
     if (checked) {
+      let index = ''
+      let keys = []
+      let items = []
+      let last = ''
+
+      data.forEach((item, i) => {
+        if (item.$disabled) return
+
+        items.push(item)
+        keys.push(i)
+        index = i
+        last = item
+      })
+
       this.setState({
-        activeKey: '',
-        selectKeys: data.map((item, index) => index),
-        selectedData: data
+        activeKey: index,
+        selectKeys: keys,
+        selectedData: items
       })
   
-      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
-      MKEmitter.emit('syncBalconyData', config.uuid, data, data.length > 0)
-      if (data.length === 0) {
+      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
+      MKEmitter.emit('syncBalconyData', config.uuid, items, data.length > 0 && data.length === keys.length)
+      if (items.length === 0) {
         message.warning('鏈幏鍙栧埌鏁版嵁锛�')
       }
     } else {
@@ -472,6 +466,50 @@
   
       MKEmitter.emit('resetSelectLine', config.uuid, '', '')
       MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+    }
+  }
+
+  checkAll = () => {
+    const { config, data, selectedData } = this.state
+
+    if (!data || data.length === 0) return
+    
+    if (selectedData.length === 0 || selectedData.length < data.length) {
+      let index = ''
+      let keys = []
+      let items = []
+      let last = ''
+
+      data.forEach((item, i) => {
+        if (item.$disabled) return
+
+        items.push(item)
+        keys.push(i)
+        index = i
+        last = item
+      })
+
+      this.setState({
+        activeKey: index,
+        selectKeys: keys,
+        selectedData: items
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
+      if (config.setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, items, data.length === keys.length)
+      }
+    } else {
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: []
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      if (config.setting.$hasSyncModule) {
+        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
+      }
     }
   }
 
@@ -613,7 +651,7 @@
       }
 
       this.loaded = true
-      if (config.$cache && pageIndex === 1) {
+      if (config.$cache && pageIndex === 1 && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -878,6 +916,13 @@
       extendData = {...extendData, ...data[0]}
     }
 
+    let checkAll = ''
+    if (config.wrap.selStyle && config.wrap.selStyle.indexOf('check') > -1) {
+      if (selectedData.length > 0) {
+        checkAll = selectedData.length < data.length ? ' half' : ' whole'
+      }
+    }
+
     return (
       <div className="custom-data-card-box" id={'anchor' + config.uuid} style={config.style}>
         {loading ?
@@ -902,11 +947,18 @@
           <Row className={'card-row-list ' + config.wrap.layout}>
             {precards.map((item, index) => (
               <Col key={'pre' + index} className="extend-card" span={item.setting.width || 6}>
-                <CardItem card={item} cards={config} data={extendData}/>
+                <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>
               </Col>
             ))}
             {data && data.map((item, index) => {
-              let className = card.setting.click ? 'mk-card pointer ' : 'mk-card '
+              let className = 'mk-card '
+              if (config.wrap.parity === 'true') {
+                if (index % 2 === 1) {
+                  className += 'mk-parity-bg '
+                }
+              }
               if (item.$disabled) {
                 className = 'mk-disabled'
               } else if (activeKey === index) {
@@ -916,14 +968,18 @@
               }
 
               return (
-                <Col className={className} key={index} span={card.setting.width} onClick={() => {this.changeCard(index, item)}}>
-                  <CardItem card={card} cards={config} data={item}/>
+                <Col className={className} key={index} span={card.setting.width}>
+                  <CardItem card={card} cards={config} data={item} onClick={() => {this.changeCard(index, item)}}>
+                    <span className="circle-select"></span>
+                  </CardItem>
                 </Col>
               )
             })}
             {nextcards.map((item, index) => (
               <Col key={'next' + index} className="extend-card" span={item.setting.width || 6}>
-                <CardItem card={item} cards={config} data={extendData}/>
+                <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>
               </Col>
             ))}
           </Row>
@@ -936,7 +992,5 @@
     )
   }
 }
-
-
 
 export default DataCard
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss
index 77c2788..820b993 100644
--- a/src/tabviews/custom/components/card/data-card/index.scss
+++ b/src/tabviews/custom/components/card/data-card/index.scss
@@ -32,6 +32,11 @@
         }
       }
     }
+    .mk-parity-bg {
+      .card-item-box {
+        background-color: var(--mk-sys-color1);
+      }
+    }
   }
   .data-zoom.scale {
     .card-row-list {
@@ -45,9 +50,6 @@
   }
   .card-row-list {
     flex: 10;
-    .mk-card.pointer {
-      cursor: pointer;
-    }
   }
   .card-row-list.flex-layout {
     display: flex;
@@ -157,6 +159,90 @@
     cursor: not-allowed;
     color: #bcbcbc;
   }
+  .mk-disabled {
+    .circle-select {
+      border-color: #e8e8e8!important;
+      cursor: not-allowed;
+    }
+  }
+  .circle-select {
+    position: relative;
+    display: none;
+    width: 16px;
+    height: 16px;
+    border: 1px solid #cccccc;
+    border-radius: 50%;
+    box-sizing: content-box;
+    margin: auto;
+    margin-right: 5px;
+    background-color: #ffffff;
+    transition: border-color 0.2s;
+    cursor: pointer;
+  }
+  .circle-select::before {
+    position: relative;
+    top: 1px;
+    left: 6px;
+    content: ' ';
+    display: block;
+    width: 5px;
+    height: 11px;
+    border-style: solid;
+    border-width: 0 2px 2px 0;
+    border-color: #ffffff;
+    transform: rotate(45deg);
+  }
+
+  .data-zoom.check.square {
+    .circle-select {
+      border-radius: 0!important;
+    }
+    .circle-select.half::after {
+      border-radius: 0px;
+    }
+  }
+  .data-zoom.check {
+    .mk-card.active, .mk-card.selected {
+      .circle-select {
+        border-color: var(--mk-sys-color);
+        background: var(--mk-sys-color);
+      }
+    }
+    .circle-select.whole {
+      border-color: var(--mk-sys-color);
+      background: var(--mk-sys-color);
+    }
+    .circle-select.half {
+      border-color: var(--mk-sys-color);
+    }
+    .circle-select.half::before {
+      display: none;
+    }
+    .circle-select.half::after {
+      position: absolute;
+      top: 4px;
+      left: 4px;
+      content: ' ';
+      display: block;
+      border-radius: 8px;
+      width: 8px;
+      height: 8px;
+      background: var(--mk-sys-color);
+    }
+    .card-item-box {
+      // width: 100%;
+      display: flex;
+    }
+    .card-cell-list {
+      flex: 1;
+    }
+    .circle-select {
+      display: block;
+    }
+    .circle-select:hover {
+      border-color: var(--mk-sys-color);
+    }
+  }
 }
 .custom-data-card-box::-webkit-scrollbar {
   width: 7px;
diff --git a/src/tabviews/custom/components/card/double-data-card/index.jsx b/src/tabviews/custom/components/card/double-data-card/index.jsx
new file mode 100644
index 0000000..3599a92
--- /dev/null
+++ b/src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -0,0 +1,973 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Spin, Empty, notification, Row, Col, Pagination, Modal } from 'antd'
+import { DownOutlined, UpOutlined, PlusSquareOutlined, MinusSquareOutlined } from '@ant-design/icons'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import preImg from '@/assets/img/prev.png'
+import nextImg from '@/assets/img/next.png'
+import MKEmitter from '@/utils/events.js'
+import TimerTask from '@/utils/timer-task.js'
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const CardItem = asyncComponent(() => import('../cardItem'))
+const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
+const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+
+class DoubleDataCard extends Component {
+  static propTpyes = {
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+  }
+
+  state = {
+    BID: '',                   // 涓婄骇ID
+    BData: '',                 // 涓婄骇琛屾暟鎹�
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    search: null,              // 鎼滅储鏉′欢
+    pageIndex: 1,              // 椤电爜
+    activeKey: '',             // 閫変腑鍗�
+    selectKeys: [],            // 澶氶�夋椂閫変腑鍗$墖
+    selectedData: [],          // 閫変腑鏁版嵁锛岀敤浜庡伐鍏锋爮鎸夐挳
+    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
+    card: null,                // 鍗$墖璁剧疆
+    data: null,                // 鏁版嵁
+    total: null,
+    precards: [],
+    nextcards: [],
+    selected: 'false',
+    opens: [],
+    wrapStyle: null,
+    subcard: null,
+    subconfig: null
+  }
+
+  loaded = false
+
+  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 || ''
+    }
+
+    let _card = null
+    let precards = []
+    let nextcards = []
+
+    if (_config.wrap.controlField) {
+      if (_config.wrap.controlVal) {
+        _config.wrap.controlVal = _config.wrap.controlVal.split(',')
+      } else {
+        _config.wrap.controlVal = ['']
+      }
+    }
+
+    _config.subcards.forEach(item => {
+      if (item.setting.click === 'button' && !item.setting.linkbtn) {
+        item.elements.forEach(ele => {
+          if (ele.eleType === 'button') {
+            item.setting.linkbtn = ele.uuid
+          }
+        })
+        if (!item.setting.linkbtn) {
+          item.setting.click = ''
+        }
+      }
+
+      if (item.$cardType !== 'extendCard') {
+        _card = item
+      } else if (!_card) {
+        precards.push(item)
+      } else {
+        nextcards.push(item)
+      }
+    })
+
+    _config.subcards = null
+    
+    let _data = null
+
+    let selected = 'false'
+    if (_config.wrap.selected === 'always' || _config.wrap.selected === 'init' || _config.wrap.selected === 'sign') {
+      selected = _config.wrap.selected
+    } else {
+      _config.wrap.selected = 'false'
+    }
+
+    _config.wrap.selStyle = _config.wrap.selStyle || 'active'
+    _config.wrap.pagestyle = _config.wrap.pagestyle || 'page'
+
+    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''}`
+
+    this.loaded = _data !== null
+
+    let wrapStyle = null
+    let subcard = fromJS(_card).toJS()
+    let subconfig = fromJS(_config).toJS()
+
+    subconfig.columns = subconfig.subColumns || []
+    subconfig.setting.primaryKey = subconfig.setting.subKey
+
+    subcard.style = subcard.backStyle
+    subcard.elements = subcard.backElements
+    subcard.setting = subcard.backSetting
+
+    if (_card.setting.position === 'inner') {
+      wrapStyle = {}
+      Object.keys(_card.style).forEach(key => {
+        if (!/^(margin|border|box)/.test(key)) return
+        wrapStyle[key] = _card.style[key]
+        delete _card.style[key]
+      })
+    }
+
+    _config.setting.sub_field = subconfig.columns.map(col => col.field).join(',')
+
+    this.setState({
+      selected,
+      precards,
+      nextcards,
+      data: _data,
+      BID: BID || '',
+      BData: BData || '',
+      config: _config,
+      subcard: subcard,
+      subconfig: subconfig,
+      wrapStyle: wrapStyle,
+      card: _card,
+      search: Utils.initMainSearch(_config.search),
+      arr_field: _config.columns.map(col => col.field).join(','),
+    }, () => {
+      if (_config.setting.onload === 'true') {
+        setTimeout(() => {
+          this.loadData()
+        }, _config.setting.delay || 0)
+      }
+    })
+  }
+
+  componentDidMount () {
+    const { config } = this.state
+
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
+    
+    if (config.timer) {
+      this.timer = new TimerTask()
+      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
+        this.setState({
+          pageIndex: 1
+        }, () => {
+          this.loadData('', 'timer')
+        })
+      })
+    }
+
+    if (config.$cache && !this.loaded) {
+      Api.getLCacheConfig(config.uuid).then(res => {
+        if (!res || this.loaded) return
+        let _data = res.map((item, index) => {
+          if (item[config.setting.subdata]) {
+            let _children = item[config.setting.subdata]
+
+            delete item[config.setting.subdata]
+
+            item.children = _children.map((cell, i) => {
+              cell.key = i
+              cell.$$uuid = cell[config.setting.subKey] || ''
+              cell.$$BID = item[config.setting.primaryKey] || ''
+              cell.$$BData = {...item}
+              cell.$Index = i + 1 + ''
+
+              return cell
+            })
+          } else {
+            item.children = []
+          }
+
+          item.key = index
+          item.$$uuid = item[config.setting.primaryKey] || ''
+          item.$Index = index + 1 + ''
+
+          if (config.wrap.controlField) {
+            if (config.wrap.controlVal.includes(item[config.wrap.controlField])) {
+              item.$disabled = true
+            }
+          }
+
+          return item
+        })
+
+        this.setState({data: _data})
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { config } = this.state
+
+    if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({pageIndex: 1}, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+
+    this.timer && this.timer.stop()
+  }
+
+  /**
+   * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂�
+   * @param {*} menuId     // 鑿滃崟Id
+   * @param {*} position   // 鍒锋柊浣嶇疆
+   * @param {*} btn        // 鎵ц鐨勬寜閽�
+   */
+  refreshByButtonResult = (menuId, position, btn, id = '', lines) => {
+    const { config, BID } = this.state
+
+    if (config.uuid !== menuId) return
+
+    let supModule = config.setting.supModule
+
+    if (position === 'line') {
+      if (lines && lines.length === 1) {
+        this.loadLinedata(lines[0].$$uuid)
+      } else {
+        this.loadData(id)
+      }
+    } else if ((position === 'mainline' || position === 'popclose') && supModule && BID) { // 鍒锋柊婧愮粍浠舵椂锛岄檮甯﹀埛鏂颁笂绾ц涓庡綋鍓嶇粍浠�
+      MKEmitter.emit('reloadData', supModule, BID)
+    } else if (!btn || btn.resetPageIndex !== 'false') {
+      this.setState({
+        pageIndex: 1
+      }, () => {
+        this.loadData(id)
+      })
+    } else {
+      this.loadData(id)
+    }
+
+    if (position === 'popclose') { // 鎵ц鍚姩寮圭獥鐨勬寜閽墍閫夋嫨鐨勫埛鏂伴」
+      btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
+    }
+  }
+
+  checkTopLine = (id) => {
+    const { config, data, selected, card } = this.state
+    let _opens = [...this.state.opens]
+
+    if (!data || data.length === 0) {
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: []
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      return
+    }
+
+    if (selected === 'sign') {
+      let index = ''
+      let keys = []
+      let items = []
+      let last = ''
+
+      if (card.setting.display === 'collapse') {
+        _opens = []
+      }
+
+      data.forEach((item, i) => {
+        if (!item.$disabled && item.selected === 'true') {
+          items.push(item)
+          keys.push(i)
+          index = i
+          last = item
+
+          if (card.setting.display === 'collapse') {
+            _opens.push(i)
+          }
+        }
+      })
+
+      this.setState({
+        opens: _opens,
+        activeKey: index,
+        selectKeys: keys,
+        selectedData: items
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
+      return
+    }
+
+    let index = 0
+    if (id) {
+      index = data.findIndex(item => item.$$uuid === id)
+      if (index === -1) {
+        index = 0
+      }
+    }
+
+    if (data[index].$disabled) {
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: []
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      return
+    }
+
+    if (card.setting.display === 'collapse') {
+      _opens = [index]
+    }
+
+    this.setState({
+      opens: _opens,
+      activeKey: index,
+      selectKeys: [index],
+      selectedData: [data[index]]
+    })
+
+    MKEmitter.emit('resetSelectLine', config.uuid, data[index].$$uuid, data[index])
+  }
+
+  checkAll = () => {
+    const { config, data, selectedData } = this.state
+
+    if (!data || data.length === 0) return
+    
+    if (selectedData.length === 0 || selectedData.length < data.length) {
+      let index = ''
+      let keys = []
+      let items = []
+      let last = ''
+
+      data.forEach((item, i) => {
+        if (item.$disabled) return
+
+        items.push(item)
+        keys.push(i)
+        index = i
+        last = item
+      })
+
+      this.setState({
+        activeKey: index,
+        selectKeys: keys,
+        selectedData: items
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
+    } else {
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: []
+      })
+  
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+    }
+  }
+
+  reloadData = (menuId, id) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    if (!id) {
+      this.loadData()
+    } else {
+      this.loadLinedata(id)
+    }
+  }
+
+  resetParentParam = (MenuID, id, data) => {
+    const { config } = this.state
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID || id !== '') {
+      this.setState({ BID: id, BData: data, pageIndex: 1 }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  queryModuleParam = (menuId, callback) => {
+    const { mainSearch } = this.props
+    const { arr_field, config, search } = this.state
+
+    if (config.uuid !== menuId) return
+
+    let searches = search ? fromJS(search).toJS() : []
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    callback({
+      arr_field: arr_field,
+      orderBy: config.setting.order || '',
+      search: searches,
+      menuName: config.name
+    })
+  }
+
+  async loadData (id, type) {
+    const { mainSearch } = this.props
+    const { config, arr_field, pageIndex, search, BID, BData, selected, card } = this.state
+
+    if (config.setting.supModule && !BID && config.wrap.supKey !== 'false') { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.loaded = true
+
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        selectedData: [],
+        pageIndex: 1,
+        data: [],
+        opens: [],
+        total: 0,
+        loading: false
+      })
+      
+      if (selected !== 'false' || (id && config.wrap.selected !== 'false')) {
+        setTimeout(() => {
+          this.checkTopLine(id)
+        }, 200)
+        if (selected === 'init') {
+          this.setState({selected: 'false'})
+        }
+      } else {
+        MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      }
+      return
+    }
+
+    let searches = fromJS(search).toJS()
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    if (type !== 'timer') {
+      this.setState({
+        loading: true
+      })
+    }
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, config.setting.pageSize, BID)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      let start = 1
+      if (config.setting.laypage) {
+        start = config.setting.pageSize * (pageIndex - 1) + 1
+      }
+
+      this.loaded = true
+      if (config.$cache && pageIndex === 1 && config.setting.onload !== 'false') {
+        Api.writeCacheConfig(config.uuid, result.data || '')
+      }
+
+      if (selected !== 'false' || (id && config.wrap.selected !== 'false')) {
+        setTimeout(() => {
+          this.checkTopLine(id)
+        }, 200)
+        if (selected === 'init') {
+          this.setState({selected: 'false'})
+        }
+      } else {
+        MKEmitter.emit('resetSelectLine', config.uuid, '', '')
+      }
+
+      let data = []
+      let opens = []
+
+      if (type === 'plus') {
+        let _data = (this.state.data || []).concat(result.data || [])
+        data = _data.map((item, index) => {
+          if (item[config.setting.subdata]) {
+            let _children = item[config.setting.subdata]
+
+            delete item[config.setting.subdata]
+
+            item.children = _children.map((cell, i) => {
+              cell.key = i
+              cell.$$uuid = cell[config.setting.subKey] || ''
+              cell.$$BID = item[config.setting.primaryKey] || ''
+              cell.$$BData = {...item}
+              cell.$Index = i + 1 + ''
+
+              return cell
+            })
+          } else {
+            item.children = []
+          }
+
+          item.key = index
+          item.$$uuid = item[config.setting.primaryKey] || ''
+          item.$$BID = BID || ''
+          item.$$BData = BData || ''
+          item.$Index = index + 1 + ''
+
+          if (config.wrap.controlField) {
+            if (config.wrap.controlVal.includes(item[config.wrap.controlField])) {
+              item.$disabled = true
+            }
+          }
+          
+          return item
+        })
+      } else {
+        data = result.data.map((item, index) => {
+          if (item[config.setting.subdata]) {
+            let _children = item[config.setting.subdata]
+
+            delete item[config.setting.subdata]
+
+            item.children = _children.map((cell, i) => {
+              cell.key = i
+              cell.$$uuid = cell[config.setting.subKey] || ''
+              cell.$$BID = item[config.setting.primaryKey] || ''
+              cell.$$BData = {...item}
+              cell.$Index = i + 1 + ''
+
+              return cell
+            })
+          } else {
+            item.children = []
+          }
+
+          item.key = index
+          item.$$uuid = item[config.setting.primaryKey] || ''
+          item.$$BID = BID || ''
+          item.$$BData = BData || ''
+          item.$Index = index + start + ''
+
+          if (config.wrap.controlField) {
+            if (config.wrap.controlVal.includes(item[config.wrap.controlField])) {
+              item.$disabled = true
+            }
+          }
+          return item
+        })
+      }
+
+      if (card.setting.display === 'unfold') {
+        opens = data.map(item => item.key)
+      } else {
+        opens = []
+      }
+
+      this.setState({
+        activeKey: '',
+        selectKeys: [],
+        opens: opens,
+        selectedData: [],
+        data: data,
+        total: result.total,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      this.timer && this.timer.stop()
+      if (result.ErrCode === 'N') {
+        Modal.error({
+          title: result.message,
+        })
+      } else {
+        notification.error({
+          top: 92,
+          message: result.message,
+          duration: 10
+        })
+      }
+    }
+  }
+
+  /**
+   * @description 鑾峰彇鍗曡鏁版嵁
+   */ 
+  async loadLinedata (id) {
+    const { mainSearch } = this.props
+    const { config, arr_field, pageIndex, search, BID, BData } = this.state
+
+    let searches = fromJS(search).toJS()
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    this.setState({
+      loading: true
+    })
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, pageIndex, config.setting.pageSize, BID, id)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      let data = fromJS(this.state.data).toJS()
+      if (result.data && result.data[0]) {
+        let _data = result.data[0]
+
+        try {
+          data = data.map(item => {
+            if (item[config.setting.primaryKey] === _data[config.setting.primaryKey]) {
+              if (_data[config.setting.subdata]) {
+                let _children = _data[config.setting.subdata]
+
+                delete _data[config.setting.subdata]
+
+                _data.children = _children.map((cell, i) => {
+                  cell.key = i
+                  cell.$$uuid = cell[config.setting.subKey] || ''
+                  cell.$$BID = _data[config.setting.primaryKey] || ''
+                  cell.$$BData = {..._data}
+                  cell.$Index = i + 1 + ''
+
+                  return cell
+                })
+              } else {
+                _data.children = []
+              }
+
+              _data.key = item.key
+              _data.$$uuid = _data[config.setting.primaryKey] || ''
+              _data.$$BID = BID || ''
+              _data.$$BData = BData || ''
+              _data.$Index = item.$Index
+              return _data
+            } else {
+              return item
+            }
+          })
+        } catch (e) {
+          console.warn('鏁版嵁鏌ヨ閿欒')
+        }
+
+        MKEmitter.emit('resetSelectLine', config.uuid, _data.$$uuid || '', _data)
+      }
+
+      this.setState({
+        data: data,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  loadMore = () => {
+    const { total, pageIndex, loading, config } = this.state
+
+    if (loading || config.setting.pageSize * pageIndex >= total) {
+      return
+    }
+
+    this.setState({
+      pageIndex: pageIndex + 1
+    }, () => {
+      this.loadData('', 'plus')
+    })
+  }
+
+  prevPage = () => {
+    const { pageIndex } = this.state
+
+    if (pageIndex === 1) return
+
+    this.setState({
+      pageIndex: pageIndex - 1
+    }, () => {
+      this.loadData()
+    })
+  }
+
+  nextPage = () => {
+    const { config, pageIndex, total } = this.state
+    let _total = config.setting.pageSize * pageIndex
+
+    if (_total >= total) return
+
+    this.setState({
+      pageIndex: pageIndex + 1
+    }, () => {
+      this.loadData()
+    })
+  }
+
+  changePageIndex = (page) => {
+    this.setState({
+      pageIndex: page
+    }, () => {
+      this.loadData()
+    })
+  }
+
+  refreshSearch = (list) => {
+    this.setState({
+      search: list,
+      pageIndex: 1
+    }, () => {
+      this.loadData()
+    })
+  }
+  
+  changeCard = (index, item, subClass) => {
+    const { config, selectKeys, selectedData, activeKey, opens, card } = this.state
+
+    if (card.setting.click === 'unfold' && card.setting.clickType !== 'multi') {
+      if (subClass === 'mk-unfold') {
+        this.setState({opens: opens.filter(item => item !== index)})
+      } else {
+        this.setState({opens: [...opens, index]})
+      }
+    }
+
+    if (!config.wrap.cardType) return
+    if (item.$disabled) return
+    
+    let _selectKeys = []
+    let _selectedData = []
+    let _activeKey = ''
+    let _item = item
+    if (config.wrap.cardType === 'checkbox') {
+      if (activeKey === index) {
+        _selectKeys = selectKeys.filter(key => key !== index)
+        _selectedData = selectedData.filter(cell => cell.key !== index)
+        _activeKey = _selectKeys.slice(-1)[0]
+        _item = _selectedData.slice(-1)[0] || ''
+      } else if (selectKeys.indexOf(index) > -1) {
+        _selectKeys = selectKeys.filter(key => key !== index)
+        _selectedData = selectedData.filter(cell => cell.key !== index)
+        _activeKey = activeKey
+        _item = _selectedData.filter(cell => cell.key === activeKey)[0] || ''
+      } else {
+        _selectKeys = [...selectKeys, index]
+        _selectedData = [...selectedData, item]
+        _activeKey = index
+      }
+    } else {
+      if (activeKey === index) return
+
+      _selectedData = [item]
+      _activeKey = index
+    }
+
+    this.setState({
+      activeKey: _activeKey,
+      selectKeys: _selectKeys,
+      selectedData: _selectedData
+    })
+
+    MKEmitter.emit('resetSelectLine', config.uuid, (_item ? _item.$$uuid : ''), _item)
+  }
+
+  changeUnfold = (e, i, subClass) => {
+    const { opens } = this.state
+
+    e.stopPropagation()
+
+    if (subClass === 'mk-disabled') return
+
+    if (subClass === 'mk-unfold') {
+      this.setState({opens: opens.filter(item => item !== i)})
+    } else {
+      this.setState({opens: [...opens, i]})
+    }
+  }
+
+  onDoubleClick = (i, subClass) => {
+    const { opens, card } = this.state
+
+    if (card.setting.click !== 'unfold' || card.setting.clickType !== 'multi') return
+
+    if (subClass === 'mk-unfold') {
+      this.setState({opens: opens.filter(item => item !== i)})
+    } else {
+      this.setState({opens: [...opens, i]})
+    }
+  }
+
+  render() {
+    const { config, precards, nextcards, loading, data, pageIndex, total, card, activeKey, BID, BData, selectedData, selectKeys, subcard, subconfig, wrapStyle, opens } = this.state
+
+    if (config.wrap.empty === 'hidden' && (!data || data.length === 0)) return null
+
+    let _total = 0
+    let switchable = false
+    if (config.wrap.pagestyle === 'switch' && config.pageable && config.setting.laypage && total > config.setting.pageSize && data) {
+      _total = config.setting.pageSize * pageIndex
+      switchable = true
+    }
+
+    let extendData = {$$BID: BID, $$BData: BData, $$selectedData: selectedData, $$type: 'extendCard'}
+
+    if (data && data[0]) {
+      extendData = {...extendData, ...data[0]}
+    }
+
+    let checkAll = ''
+    let mainBox = ''
+    if (config.wrap.selStyle && config.wrap.selStyle.indexOf('check') > -1) {
+      if (selectedData.length > 0) {
+        checkAll = selectedData.length < data.length ? ' half' : ' whole'
+      }
+      if (card.setting.controlIcon === 'left') {
+        checkAll += ' mk-extend-icon'
+      }
+    } else if (card.setting.display !== 'default' && card.setting.controlIcon === 'left') {
+      mainBox = 'flex-card '
+    }
+
+    return (
+      <div className="double-data-card-box" id={'anchor' + config.uuid} style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            {data ? <div className="ant-spin-blur"></div> : null}
+            <Spin />
+          </div> : null
+        }
+        <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
+        {config.action && config.action.length > 0 ?
+          <MainAction
+            BID={BID}
+            BData={BData}
+            setting={config.setting}
+            actions={config.action}
+            columns={config.columns}
+            selectedData={selectedData}
+          /> : null
+        }
+        <div className={`data-zoom ${config.wrap.wrapClass}`}>
+          {switchable ? <div className={'prev-page ' + (pageIndex === 1 ? 'disabled' : '')} onClick={this.prevPage}><div><div><img src={preImg} alt=""/></div></div></div> : null}
+          <Row className={'card-row-list '}>
+            {precards.map((item, index) => (
+              <Col key={'pre' + index} className="extend-card" span={item.setting.width || 6}>
+                <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>
+              </Col>
+            ))}
+            {data && data.map((item, index) => {
+              let className = 'card-item-wrap mk-card ' + mainBox
+              let subClass = 'mk-unfold'
+              let unfold = true
+
+              if (item.$disabled) {
+                className = 'mk-disabled ' + mainBox
+              } else if (activeKey === index) {
+                className += 'active'
+              } else if (selectKeys.indexOf(index) > -1) {
+                className += 'selected'
+              }
+
+              if (card.setting.display !== 'default') {
+                if (item.children.length === 0) {
+                  subClass = 'mk-disabled'
+                  unfold = false
+                } else {
+                  subClass = opens.indexOf(index) > -1 ? 'mk-unfold' : 'mk-collapse'
+                  unfold = opens.indexOf(index) > -1
+                }
+              }
+
+              return (
+                <Col key={index} span={card.setting.width}>
+                  <div className={className} style={wrapStyle}>
+                    <CardItem card={card} cards={config} data={item} onDoubleClick={() => this.onDoubleClick(index, subClass)} onClick={() => {this.changeCard(index, item, subClass)}}>
+                      <span className="circle-select"></span>
+                      {card.setting.controlIcon === 'left' ? (!unfold ? <PlusSquareOutlined className={subClass} onClick={(e) => this.changeUnfold(e, index, subClass)}/> : <MinusSquareOutlined className={subClass} onClick={(e) => this.changeUnfold(e, index, subClass)}/>) : null}
+                      {card.setting.controlIcon === 'right' ? <UpOutlined className={subClass} onClick={(e) => this.changeUnfold(e, index, subClass)}/> : null}
+                    </CardItem>
+                    <div className={'sub-card-wrap ' + subClass + (config.wrap.parity === 'true' ? ' mk-parity-bg' : '')}>
+                      {item.children.map((cell, index) => <Col key={'sub' + index} span={subcard.setting.width || 24}>
+                        <CardItem card={subcard} cards={subconfig} data={cell} />
+                      </Col>)}
+                    </div>
+                  </div>
+                </Col>
+              )
+            })}
+            {nextcards.map((item, index) => (
+              <Col key={'next' + index} className="extend-card" span={item.setting.width || 6}>
+                <CardItem card={item} cards={config} data={extendData}>
+                  {item.setting.checkAll === 'show' ? <span onClick={this.checkAll} className={'circle-select' + checkAll}></span> : null}
+                </CardItem>
+              </Col>
+            ))}
+          </Row>
+          {switchable ? <div className={'prev-page ' + (total <= _total ? 'disabled' : '')} onClick={this.nextPage}><div><div><img src={nextImg} alt=""/></div></div></div> : null}
+          {precards.length === 0 && nextcards.length === 0 && (!data || data.length === 0) ? <Empty description={false}/> : null}
+        </div>
+        {config.wrap.pagestyle === 'page' && config.setting.laypage && data ? <Pagination size="small" total={total} showTotal={t => `鍏� ${t} 鏉} pageSize={config.setting.pageSize} onChange={this.changePageIndex} current={pageIndex}/> : null}
+        {config.wrap.pagestyle === 'more' && config.setting.laypage && data && data.length > 0 ? <div className={'mk-more' + (config.setting.pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>鏌ョ湅鏇村<DownOutlined/></div> : null}
+      </div>
+    )
+  }
+}
+
+export default DoubleDataCard
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/double-data-card/index.scss b/src/tabviews/custom/components/card/double-data-card/index.scss
new file mode 100644
index 0000000..f483742
--- /dev/null
+++ b/src/tabviews/custom/components/card/double-data-card/index.scss
@@ -0,0 +1,338 @@
+.double-data-card-box {
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 20px;
+  overflow-y: auto;
+
+  >.button-list.toolbar-button {
+    padding: 0;
+    line-height: 45px;
+    button {
+      margin-right: 0px;
+      margin-bottom: 0px;
+      min-height: 28px;
+      height: auto;
+    }
+  }
+
+  .data-zoom {
+    display: flex;
+    position: relative;
+    .mk-disabled {
+      >.card-item-box {
+        cursor: not-allowed;
+        color: #bcbcbc;
+        .ant-mk-text, .anticon {
+          color: #bcbcbc!important;
+          span {
+            color: #bcbcbc!important;
+          }
+        }
+      }
+    }
+  }
+  .data-zoom.scale {
+    .card-row-list {
+      .mk-card:hover {
+        >.card-item-box {
+          z-index: 1;
+          transform: scale(1.05);
+        }
+      }
+    }
+  }
+  .card-row-list {
+    flex: 10;
+  }
+  .card-row-list.flex-layout {
+    display: flex;
+    width: 100%;
+    >.ant-col {
+      width: 5%;
+      flex: 1;
+    }
+  }
+  .card-row-list.float-center {
+    text-align: center;
+    >.ant-col {
+      display: inline-block;
+      float: none;
+      text-align: left;
+      vertical-align: top;
+    }
+  }
+  .card-row-list.float-right {
+    text-align: right;
+    >.ant-col {
+      display: inline-block;
+      float: none;
+      text-align: left;
+      vertical-align: top;
+    }
+  }
+  .card-item-box {
+    position: relative;
+    background-color: #ffffff;
+    transition: all 0.3s;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+  }
+  .prev-page {
+    width: 20px;
+    div {
+      height: 100%;
+      display: table;
+      div {
+        display: table-cell;
+        vertical-align: middle;
+      }
+    }
+    img {
+      width: 15px;
+      padding: 0 2px;
+      height: 70px;
+      cursor: pointer;
+    }
+  }
+  .prev-page.disabled {
+    img {
+      cursor: not-allowed;
+      opacity: 0.4;
+    }
+  }
+  .card-row-list::after {
+    content: ' ';
+    display: block;
+    clear: both;
+  }
+
+  .ant-empty {
+    width: 100%;
+    min-height: 100px;
+    padding-top: 15px;
+
+    .ant-empty-image {
+      height: 60px;
+    }
+  }
+  .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;
+    }
+  }
+  .ant-pagination {
+    padding: 10px;
+    text-align: right;
+  }
+  .mk-more {
+    text-align: center;
+    line-height: 40px;
+    cursor: pointer;
+    .anticon-down {
+      margin-left: 2px;
+    }
+  }
+  .mk-more.disabled {
+    cursor: not-allowed;
+    color: #bcbcbc;
+  }
+  .mk-disabled {
+    .circle-select {
+      border-color: #e8e8e8!important;
+      cursor: not-allowed;
+    }
+  }
+  .circle-select {
+    position: relative;
+    display: none;
+    width: 16px;
+    height: 16px;
+    border: 1px solid #cccccc;
+    border-radius: 50%;
+    box-sizing: content-box;
+    margin: auto;
+    margin-right: 5px;
+    background-color: #ffffff;
+    transition: border-color 0.2s;
+    cursor: pointer;
+  }
+  .circle-select::before {
+    position: relative;
+    top: 1px;
+    left: 6px;
+    content: ' ';
+    display: block;
+    width: 5px;
+    height: 11px;
+    border-style: solid;
+    border-width: 0 2px 2px 0;
+    border-color: #ffffff;
+    transform: rotate(45deg);
+  }
+
+  .data-zoom.check.square {
+    .circle-select {
+      border-radius: 0!important;
+    }
+    .circle-select.half::after {
+      border-radius: 0px;
+    }
+  }
+  .data-zoom.check {
+    .mk-card.active, .mk-card.selected {
+      .circle-select {
+        border-color: var(--mk-sys-color);
+        background: var(--mk-sys-color);
+      }
+    }
+    .circle-select.whole {
+      border-color: var(--mk-sys-color);
+      background: var(--mk-sys-color);
+    }
+    .circle-select.half {
+      border-color: var(--mk-sys-color);
+    }
+    .circle-select.half::before {
+      display: none;
+    }
+    .circle-select.half::after {
+      position: absolute;
+      top: 4px;
+      left: 4px;
+      content: ' ';
+      display: block;
+      border-radius: 8px;
+      width: 8px;
+      height: 8px;
+      background: var(--mk-sys-color);
+    }
+    .card-item-box {
+      display: flex;
+    }
+    .card-cell-list {
+      flex: 1;
+    }
+    .circle-select {
+      display: block;
+    }
+    .circle-select:hover {
+      border-color: var(--mk-sys-color);
+    }
+    >.card-row-list {
+      >.ant-col:not(.extend-card) {
+        .card-item-box:hover {
+          background-color: var(--mk-sys-color2);
+        }
+      }
+    }
+    .sub-card-wrap.mk-parity-bg {
+      .ant-col:nth-child(even){
+        .card-item-box:not(:hover) {
+          background-color: var(--mk-sys-color1);
+        }
+      }
+    }
+  }
+  .card-item-wrap {
+    .card-item-box {
+      >.anticon-up {
+        position: absolute;
+        right: 0px;
+        bottom: 0px;
+        padding: 10px;
+        transition: all 0.3s;
+        cursor: pointer;
+        z-index: 1;
+      }
+      >.anticon-up:not(.mk-disabled):hover, >.anticon-plus-square:not(.mk-disabled):hover, >.anticon-minus-square:not(.mk-disabled):hover {
+        color: var(--mk-sys-color);
+      }
+      >.anticon-up.mk-disabled {
+        color: #e8e8e8;
+        cursor: not-allowed;
+        transform: rotate(180deg);
+      }
+      >.anticon-up.mk-collapse {
+        transform: rotate(180deg);
+      }
+      >.anticon-plus-square {
+        margin: auto;
+        width: 30px;
+        font-size: 18px;
+      }
+      >.anticon-plus-square.mk-disabled {
+        color: #e8e8e8;
+        cursor: not-allowed;
+      }
+      >.anticon-minus-square {
+        margin: auto;
+        width: 30px;
+        font-size: 18px;
+      }
+    }
+    .sub-card-wrap::after {
+      content: ' ';
+      display: block;
+      clear: both;
+    }
+    .sub-card-wrap.mk-collapse {
+      height: 0;
+      overflow: hidden;
+      transition: height 0.3s;
+    }
+  }
+  .card-item-wrap.flex-card {
+    >.card-item-box:first-child {
+      display: flex;
+      .card-cell-list {
+        flex: 1;
+      }
+    }
+  }
+  .circle-select.mk-extend-icon {
+    margin-right: 35px;
+  }
+
+  .data-zoom:not(.check) {
+    .sub-card-wrap.mk-parity-bg {
+      .ant-col:nth-child(even){
+        .card-item-box {
+          background-color: var(--mk-sys-color1);
+        }
+      }
+    }
+  }
+}
+.double-data-card-box::-webkit-scrollbar {
+  width: 7px;
+  height: 7px;
+}
+.double-data-card-box::-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);
+}
+.double-data-card-box::-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);
+}
diff --git a/src/tabviews/custom/components/card/prop-card/index.jsx b/src/tabviews/custom/components/card/prop-card/index.jsx
index 2ad4a02..aac9321 100644
--- a/src/tabviews/custom/components/card/prop-card/index.jsx
+++ b/src/tabviews/custom/components/card/prop-card/index.jsx
@@ -36,7 +36,6 @@
   UNSAFE_componentWillMount () {
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
 
     let _data = { $$empty: true }
     let _sync = false
@@ -85,11 +84,6 @@
       _data.$$uuid = _data[_config.setting.primaryKey] || ''
     }
 
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
     _config.subcards.forEach(card => {
       if (card.setting.click === 'button' && !card.setting.linkbtn) {
         card.elements.forEach(ele => {
@@ -101,18 +95,6 @@
           card.setting.click = ''
         }
       }
-      card.elements = card.elements.map(item => {
-        if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-          item.decimal = _cols.get(item.field).decimal || 0
-        }
-        return item
-      })
-      card.backElements = card.backElements.map(item => {
-        if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-          item.decimal = _cols.get(item.field).decimal || 0
-        }
-        return item
-      })
     })
 
     let selected = _config.wrap.selected || 'false'
@@ -152,7 +134,7 @@
         }, 200)
       }
 
-      if (_config.wrap.datatype === 'dynamic') {
+      if (_config.wrap.datatype === 'dynamic' && this.loaded) {
         this.autoExec()
       }
       if (!_config.wrap.cardType && _data.$$uuid) {
@@ -270,10 +252,10 @@
   autoExec = () => {
     const { config, data } = this.state
 
-    if (!config.wrap.autoExec || data.$$empty) return
+    if (!config.wrap.autoExec) return
 
     setTimeout(() => {
-      MKEmitter.emit('triggerBtnId', config.wrap.autoExec, [data])
+      MKEmitter.emit('triggerBtnId', config.wrap.autoExec, data.$$empty ? [] : [data])
     }, 200)
   }
 
@@ -407,7 +389,7 @@
       let _data = {}
 
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -499,14 +481,14 @@
         <NormalHeader config={config}/>
         <Row className={`card-row-list data-zoom ${config.wrap.wrapClass}`}>
           {config.subcards.map((item, index) => {
-            let className = item.setting.click ? 'mk-card pointer ' : 'mk-card '
+            let className = 'mk-card '
             if (activeKey === index) {
               className += 'active'
             }
 
             return (
-              <Col className={className} key={index} span={item.setting.width || 6} offset={item.offset || 0} onClick={() => {this.changeCard(index, item)}}>
-                <CardItem card={item} cards={config} data={data}/>
+              <Col className={className} key={index} span={item.setting.width || 6} offset={item.offset || 0}>
+                <CardItem card={item} cards={config} data={data} onClick={() => {this.changeCard(index, item)}}/>
               </Col>
             )
           })}
diff --git a/src/tabviews/custom/components/card/prop-card/index.scss b/src/tabviews/custom/components/card/prop-card/index.scss
index f930a0b..87840aa 100644
--- a/src/tabviews/custom/components/card/prop-card/index.scss
+++ b/src/tabviews/custom/components/card/prop-card/index.scss
@@ -12,11 +12,6 @@
     clear: both;
   }
 
-  .card-row-list {
-    .mk-card.pointer {
-      cursor: pointer;
-    }
-  }
   .card-row-list.flex-layout {
     display: flex;
     width: 100%;
diff --git a/src/tabviews/custom/components/card/table-card/index.jsx b/src/tabviews/custom/components/card/table-card/index.jsx
index 5629e18..ed5623f 100644
--- a/src/tabviews/custom/components/card/table-card/index.jsx
+++ b/src/tabviews/custom/components/card/table-card/index.jsx
@@ -43,7 +43,6 @@
   UNSAFE_componentWillMount () {
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
 
     let _data = null
     let _sync = _config.setting.sync === 'true'
@@ -89,20 +88,6 @@
     } else {
       _config.wrap.contentHeight = showHeader ? 'calc(100% - 45px)' : '100%'
     }
-
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
-    _config.subcards.forEach(card => {
-      card.elements = card.elements.map(item => {
-        if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-          item.decimal = _cols.get(item.field).decimal || 0
-        }
-        return item
-      })
-    })
 
     _config.wrap.pagestyle = _config.wrap.pagestyle || 'page'
 
@@ -321,7 +306,7 @@
       }
 
       this.loaded = true
-      if (config.$cache && pageIndex === 1) {
+      if (config.$cache && pageIndex === 1 && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -515,7 +500,7 @@
           </div> : null
         }
         <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
-        {data && data.length > 0 ? <Row className="card-row-list" style={{height: config.wrap.contentHeight}}>
+        {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}}>
diff --git a/src/tabviews/custom/components/card/table-card/index.scss b/src/tabviews/custom/components/card/table-card/index.scss
index c44fdec..c7b6fc8 100644
--- a/src/tabviews/custom/components/card/table-card/index.scss
+++ b/src/tabviews/custom/components/card/table-card/index.scss
@@ -33,6 +33,13 @@
     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 {
diff --git a/src/tabviews/custom/components/carousel/data-card/index.jsx b/src/tabviews/custom/components/carousel/data-card/index.jsx
index 90e9116..4dbe6e2 100644
--- a/src/tabviews/custom/components/carousel/data-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/data-card/index.jsx
@@ -38,7 +38,6 @@
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
     let _card = _config.subcards[0]
-    let _cols = new Map()
 
     let _data = null
     let _sync = _config.setting.sync === 'true'
@@ -75,21 +74,9 @@
       })
     }
 
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
     if (_card.setting.click) {
       _card.style.cursor = 'pointer'
     }
-
-    _card.elements = _card.elements.map(item => {
-      if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-        item.decimal = _cols.get(item.field).decimal || 0
-      }
-      return item
-    })
 
     if (!_config.wrap.height) { // 鍏煎
       _config.wrap.height = _config.style.height || '300px'
@@ -194,7 +181,7 @@
     this.timer && this.timer.stop()
   }
 
-  openModal = () => {
+  openModal = (ErrCode) => {
     const { config, data } = this.state
     
     if (config.wrap.display !== 'modal' || !data || data.length === 0) return
@@ -208,6 +195,10 @@
       localStorage.setItem(code, data[0].$$uuid + data.length)
 
       Api.getAppVersion(true)
+
+      if (ErrCode === '-1') {
+        return
+      }
     }
 
     setTimeout(() => {
@@ -299,7 +290,7 @@
     let result = await Api.genericInterface(param)
     if (result.status) {
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -314,7 +305,7 @@
         }),
         loading: false
       }, () => {
-        this.openModal()
+        this.openModal(result.ErrCode)
       })
     } else {
       this.setState({
diff --git a/src/tabviews/custom/components/carousel/prop-card/index.jsx b/src/tabviews/custom/components/carousel/prop-card/index.jsx
index 0b5782b..6698d56 100644
--- a/src/tabviews/custom/components/carousel/prop-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/prop-card/index.jsx
@@ -36,7 +36,6 @@
   UNSAFE_componentWillMount () {
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
 
     let _data = {$$empty: true}
     let _sync = false
@@ -79,11 +78,6 @@
     _data.$$BID = BID || ''
     _data.$$BData = BData || ''
 
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
     if (!_config.wrap.height) { // 鍏煎
       _config.wrap.height = _config.style.height || '300px'
       delete _config.style.height
@@ -94,12 +88,6 @@
       if (card.setting.click) {
         card.style.cursor = 'pointer'
       }
-      card.elements = card.elements.map(item => {
-        if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-          item.decimal = _cols.get(item.field).decimal || 0
-        }
-        return item
-      })
     })
 
     _config.wrap.speed = (_config.wrap.speed || 3) * 1000
@@ -198,7 +186,7 @@
     }
   }
 
-  openModal = () => {
+  openModal = (ErrCode) => {
     const { config, data } = this.state
     
     let code = config.wrap.code || ('modal' + config.uuid)
@@ -210,6 +198,10 @@
       localStorage.setItem(code, data.$$uuid || 'true')
 
       Api.getAppVersion(true)
+
+      if (ErrCode === '-1') {
+        return
+      }
     }
 
     setTimeout(() => {
@@ -316,7 +308,7 @@
       let _data = {}
 
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -335,7 +327,7 @@
         loading: false
       }, () => {
         if (config.wrap.display === 'modal') {
-          this.openModal()
+          this.openModal(result.ErrCode)
         }
       })
     } else {
diff --git a/src/tabviews/custom/components/chart/antv-G6/index.jsx b/src/tabviews/custom/components/chart/antv-G6/index.jsx
index e856a3d..ac96d6b 100644
--- a/src/tabviews/custom/components/chart/antv-G6/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-G6/index.jsx
@@ -1100,7 +1100,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -1494,7 +1494,7 @@
       let menu = null
       
       if (plot.menus && plot.menus.length > 0) {
-        let s = data[plot.menuType] || ''
+        let s = data[plot.menuType] + ''
         plot.menus.forEach(m => {
           if (s !== m.sign) return
           menu = m
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 5bc343a..7e4180a 100644
--- a/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -536,7 +536,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -1478,6 +1478,7 @@
     let _valfield = 'value'
     let _typefield = 'key'
     let colorIndex = 0
+    let barcolors = {}
 
     if (plot.datatype === 'statistics') {
       _valfield = plot.InfoValue
@@ -1490,6 +1491,16 @@
       if (plot.enabled === 'true') {
         this.customrender(data)
         return
+      }
+
+      if (plot.barcolors && plot.barcolors.length > 0 && plot.Yaxis.length === 1) {
+        data.forEach((item, i) => {
+          if (plot.barcolors[i]) {
+            barcolors[item[plot.Xaxis]] = plot.barcolors[i].color
+          }
+        })
+      } else {
+        barcolors = null
       }
 
       const ds = new DataSet()
@@ -1624,14 +1635,28 @@
 
       if (plot.$colors) {
         let limit = chartColors.length
-        _chart.color(_typefield, (key) => {
-          if (plot.$colors.has(key)) {
-            return plot.$colors.get(key)
-          } else {
-            colorIndex++
-            return chartColors[(colorIndex - 1) % limit]
-          }
-        })
+
+        if (barcolors) {
+          _chart.color(`${_typefield}*${plot.Xaxis}`, (key, label) => {
+            if (barcolors[label]) {
+              return barcolors[label]
+            } else if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color(`${_typefield}`, (key) => {
+            if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        }
       } else {
         _chart.color(_typefield)
       }
@@ -1686,14 +1711,27 @@
 
       if (plot.$colors) {
         let limit = chartColors.length
-        _chart.color(_typefield, (key) => {
-          if (plot.$colors.has(key)) {
-            return plot.$colors.get(key)
-          } else {
-            colorIndex++
-            return chartColors[(colorIndex - 1) % limit]
-          }
-        })
+        if (barcolors) {
+          _chart.color(`${_typefield}*${plot.Xaxis}`, (key, label) => {
+            if (barcolors[label]) {
+              return barcolors[label]
+            } else if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color(`${_typefield}`, (key) => {
+            if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        }
       } else {
         _chart.color(_typefield)
       }
@@ -1742,7 +1780,7 @@
         let menu = null
         
         if (plot.menus && plot.menus.length > 0) {
-          let s = data[plot.menuType] || ''
+          let s = data[plot.menuType] + ''
           plot.menus.forEach(m => {
             if (s !== m.sign) return
             menu = m
diff --git a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
index c505abf..1544237 100644
--- a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
@@ -279,7 +279,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
diff --git a/src/tabviews/custom/components/chart/antv-pie/index.jsx b/src/tabviews/custom/components/chart/antv-pie/index.jsx
index 216be2f..17e24f5 100644
--- a/src/tabviews/custom/components/chart/antv-pie/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -247,7 +247,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
diff --git a/src/tabviews/custom/components/chart/antv-scatter/index.jsx b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
index a36ef44..b418e31 100644
--- a/src/tabviews/custom/components/chart/antv-scatter/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
@@ -277,7 +277,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
       
diff --git a/src/tabviews/custom/components/chart/custom-chart/index.jsx b/src/tabviews/custom/components/chart/custom-chart/index.jsx
index 19713cf..fb81260 100644
--- a/src/tabviews/custom/components/chart/custom-chart/index.jsx
+++ b/src/tabviews/custom/components/chart/custom-chart/index.jsx
@@ -267,7 +267,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
diff --git a/src/tabviews/custom/components/code/sand-box/index.jsx b/src/tabviews/custom/components/code/sand-box/index.jsx
index a9edce6..8ccc32b 100644
--- a/src/tabviews/custom/components/code/sand-box/index.jsx
+++ b/src/tabviews/custom/components/code/sand-box/index.jsx
@@ -97,7 +97,7 @@
       Api.getLCacheConfig(config.uuid).then(res => {
         if (!res || this.loaded) return
 
-        this.setState({data: res[0]}, () => {
+        this.setState({data: res}, () => {
           this.renderView()
         })
       })
@@ -129,13 +129,13 @@
 
       this.loaded = true
 
-      this.setState({sync: false, data: _data})
-
       if (!is(fromJS(this.state.data), fromJS(_data))) {
         setTimeout(() => {
           this.renderView()
         }, 10)
       }
+
+      this.setState({sync: false, data: _data})
     } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
       this.setState({}, () => {
         this.loadData()
@@ -189,20 +189,20 @@
       let _data = result.data || {}
 
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
+      }
+
+      if (!is(fromJS(this.state.data), fromJS(_data))) {
+        setTimeout(() => {
+          this.renderView()
+        }, 10)
       }
 
       this.setState({
         data: _data,
         loading: false
       })
-      
-      if (!is(fromJS(this.state.data), fromJS(_data))) {
-        setTimeout(() => {
-          this.renderView()
-        }, 10)
-      }
     } else {
       this.setState({
         loading: false
diff --git a/src/tabviews/custom/components/editor/braft-editor/index.jsx b/src/tabviews/custom/components/editor/braft-editor/index.jsx
index 3a2a484..434ed5d 100644
--- a/src/tabviews/custom/components/editor/braft-editor/index.jsx
+++ b/src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -31,7 +31,7 @@
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
 
-    let _data = {}
+    let _data = { $$empty: true }
     let _sync = false
 
     let BID = ''
@@ -46,24 +46,22 @@
       BID = BData.$BID || ''
     }
     
-    if (_config.setting && _config.wrap.datatype !== 'static') {
+    if (_config.setting && _config.wrap.datatype === 'dynamic') {
       _sync = _config.setting.sync === 'true'
 
       if (_sync && data) {
-        _data = data[_config.dataName] || {}
+        _data = data[_config.dataName] || {$$empty: true}
         if (_data && Array.isArray(_data)) {
-          _data = _data[0] || {}
+          _data = _data[0] || {$$empty: true}
         }
         _sync = false
       } else if (_sync && initdata) {
-        _data = initdata || {}
+        _data = initdata
         if (_data && Array.isArray(_data)) {
-          _data = _data[0] || {}
+          _data = _data[0] || {$$empty: true}
         }
         _sync = false
       }
-    } else {
-      _data = {}
     }
 
     if (_config.wrap.minHeight) {
@@ -77,7 +75,7 @@
       config: _config,
       arr_field: _config.columns.map(col => col.field).join(','),
     }, () => {
-      if (_config.wrap.datatype !== 'static' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') {
+      if (_config.wrap.datatype === 'dynamic' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') {
         setTimeout(() => {
           this.loadData()
         }, _config.setting.delay || 0)
@@ -86,7 +84,14 @@
   }
 
   componentDidMount () {
+    const { config } = this.state
+
     MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+
+    if (config.wrap.datatype === 'public') {
+      MKEmitter.addListener('mkPublicData', this.mkPublicData)
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -98,6 +103,8 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('mkPublicData', this.mkPublicData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
   }
 
   /**
@@ -107,17 +114,38 @@
     const { sync, config } = this.state
 
     if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
-      let _data = {}
+      let _data = {$$empty: true}
       if (nextProps.data && nextProps.data[config.dataName]) {
         _data = nextProps.data[config.dataName]
         if (_data && Array.isArray(_data)) {
-          _data = _data[0]
+          _data = _data[0] || {$$empty: true}
         }
       }
 
       this.setState({sync: false, data: _data})
     } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
       this.setState({}, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  mkPublicData = (publicId, data) => {
+    const { config } = this.state
+
+    if (config.wrap.datatype === 'public' && config.wrap.publicId === publicId) {
+      let _data = fromJS(data).toJS()
+
+      this.setState({data: _data})
+    }
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.state
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID || id !== '') {
+      this.setState({ BID: id }, () => {
         this.loadData()
       })
     }
@@ -135,15 +163,20 @@
     const { mainSearch } = this.props
     const { config, arr_field, BID } = this.state
 
+    if (config.wrap.datatype === 'public') {
+      MKEmitter.emit('reloadData', config.wrap.publicId)
+      return
+    }
+    
     if (config.wrap.datatype === 'static') {
       this.setState({
-        data: {},
+        data: {$$empty: true},
         loading: false
       })
       return
     } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
-        data: {},
+        data: {$$empty: true},
         loading: false
       })
       return
@@ -165,7 +198,7 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      let _data = result.data && result.data[0] ? result.data[0] : {}
+      let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
 
       this.setState({
         data: _data,
@@ -186,6 +219,8 @@
   render() {
     const { config, loading, data } = this.state
 
+    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+
     return (
       <div className="custom-braft-editor-box" id={'anchor' + config.uuid} style={config.style}>
         {loading ?
diff --git a/src/tabviews/custom/components/form/simple-form/index.jsx b/src/tabviews/custom/components/form/simple-form/index.jsx
index b29ce9c..96156c2 100644
--- a/src/tabviews/custom/components/form/simple-form/index.jsx
+++ b/src/tabviews/custom/components/form/simple-form/index.jsx
@@ -63,6 +63,7 @@
           _data = _data[0] || {$$empty: true}
         }
         _sync = false
+        _data.$$uuid = _data[config.setting.primaryKey] || ''
       }
     } else {
       _data = {$$empty: true}
@@ -127,6 +128,8 @@
           _data = _data[0] || {$$empty: true}
         }
       }
+
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
 
       this.setState({sync: false, data: _data})
     } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -244,6 +247,8 @@
     if (result.status) {
       let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
 
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
+
       this.setState({
         data: null,
         loading: false
@@ -288,6 +293,9 @@
   render() {
     const { config, loading, BID, BData, data, group, dict } = this.state
 
+    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+    if (config.idCtrl && (!data || data.$$empty)) return null
+    
     return (
       <div className="custom-simple-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
         {loading ?
diff --git a/src/tabviews/custom/components/form/step-form/index.jsx b/src/tabviews/custom/components/form/step-form/index.jsx
index c5c8315..83349ad 100644
--- a/src/tabviews/custom/components/form/step-form/index.jsx
+++ b/src/tabviews/custom/components/form/step-form/index.jsx
@@ -62,6 +62,7 @@
           _data = _data[0] || {$$empty: true}
         }
         _sync = false
+        _data.$$uuid = _data[config.setting.primaryKey] || ''
       }
     } else {
       _data = {$$empty: true}
@@ -102,6 +103,16 @@
 
       let _groups = config.subcards.filter(item => item.setting.status === _status)[0]
       _group = _groups || _group
+    }
+
+    config.titleStyle = {}
+    config.sortStyle = {}
+
+    if (config.style.fontSize) {
+      let size = parseInt(config.style.fontSize)
+      config.titleStyle = {fontSize: size}
+      let s = size * 1.5 + 'px'
+      config.sortStyle = {width: s, height: s, lineHeight: s, borderRadius: s}
     }
 
     this.setState({
@@ -158,6 +169,8 @@
           _data = _data[0] || {$$empty: true}
         }
       }
+
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
 
       if (config.wrap.statusControl && _data[config.wrap.statusControl]) {
         let _status = _data[config.wrap.statusControl]
@@ -294,6 +307,8 @@
       let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
       let _group = this.state.group
 
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
+
       if (type === 'refresh') {
         _group = config.subcards[0]
       }
@@ -380,6 +395,9 @@
   render() {
     const { config, loading, BID, BData, data, group, dict, step } = this.state
 
+    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+    if (config.idCtrl && (!data || data.$$empty)) return null
+    
     return (
       <div className="custom-normal-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
         {loading ?
@@ -390,8 +408,8 @@
         }
         {config.wrap.groupLabel !== 'hidden' ? <div className="mk-normal-form-title">
           {config.subcards.map(card => (
-            <div key={card.uuid} className={'form-title' + (card.sort <= step ? ' active' : '')}>
-              <span className="form-sort" style={{background: config.wrap.color}}>{card.sort}</span>
+            <div key={card.uuid} style={config.titleStyle} className={'form-title' + (card.sort <= step ? ' active' : '')}>
+              <span className="form-sort" style={{background: config.wrap.color, ...config.sortStyle}}>{card.sort}</span>
               <span className="before-line" style={{background: config.wrap.color}}></span>
               <span className="after-line" style={{background: config.wrap.color}}></span>
               {card.setting.title}
diff --git a/src/tabviews/custom/components/form/step-form/index.scss b/src/tabviews/custom/components/form/step-form/index.scss
index 06b56f4..12ca54d 100644
--- a/src/tabviews/custom/components/form/step-form/index.scss
+++ b/src/tabviews/custom/components/form/step-form/index.scss
@@ -11,10 +11,12 @@
     line-height: 30px;
     min-height: 50px;
     margin-bottom: 20px;
+    font-weight: inherit;
     .form-title {
       position: relative;
       flex: 1;
       text-align: center;
+      font-weight: inherit;
       .form-sort {
         background: #d8d8d8;
         display: block;
diff --git a/src/tabviews/custom/components/form/tab-form/index.jsx b/src/tabviews/custom/components/form/tab-form/index.jsx
index 66e5dd2..0538eed 100644
--- a/src/tabviews/custom/components/form/tab-form/index.jsx
+++ b/src/tabviews/custom/components/form/tab-form/index.jsx
@@ -61,6 +61,7 @@
           _data = _data[0] || {$$empty: true}
         }
         _sync = false
+        _data.$$uuid = _data[config.setting.primaryKey] || ''
       }
     } else {
       _data = {$$empty: true}
@@ -82,6 +83,12 @@
 
       return group
     })
+
+    config.titleStyle = {}
+
+    if (config.style.fontSize) {
+      config.titleStyle = {fontSize: parseInt(config.style.fontSize)}
+    }
 
     this.setState({
       sync: _sync,
@@ -136,6 +143,8 @@
           _data = _data[0] || {$$empty: true}
         }
       }
+
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
 
       this.setState({sync: false, data: _data, group: null}, () => {
         this.setState({group: _group})
@@ -254,6 +263,8 @@
     if (result.status) {
       let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
 
+      _data.$$uuid = _data[config.setting.primaryKey] || ''
+
       this.setState({
         data: null,
         loading: false
@@ -300,6 +311,9 @@
   render() {
     const { config, loading, BID, BData, data, group, dict } = this.state
 
+    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
+    if (config.idCtrl && (!data || data.$$empty)) return null
+    
     return (
       <div className="custom-tab-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
         {loading ?
@@ -310,7 +324,7 @@
         }
         {config.wrap.groupLabel !== 'hidden' ? <div className={'mk-normal-form-title ' + config.wrap.tabtype}>
           {config.subcards.map(card => (
-            <div key={card.uuid} onClick={() => this.changeGroup(card)} className={'form-title' + (group && group.uuid === card.uuid ? ' active' : '')}>
+            <div key={card.uuid} onClick={() => this.changeGroup(card)} style={config.titleStyle} className={'form-title' + (group && group.uuid === card.uuid ? ' active' : '')}>
               {card.setting.title}
             </div>))
           }
diff --git a/src/tabviews/custom/components/form/tab-form/index.scss b/src/tabviews/custom/components/form/tab-form/index.scss
index 370f64a..a079e22 100644
--- a/src/tabviews/custom/components/form/tab-form/index.scss
+++ b/src/tabviews/custom/components/form/tab-form/index.scss
@@ -12,11 +12,13 @@
     min-height: 36px;
     margin-bottom: 20px;
     font-size: 16px;
+    font-weight: inherit;
     .form-title {
       position: relative;
       flex: 1;
       text-align: center;
       cursor: pointer;
+      font-weight: inherit;
     }
   }
   .mk-normal-form-title.mkbtn {
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index 44124b6..631caf0 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -20,6 +20,7 @@
 const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
+const DoubleDataCard = asyncComponent(() => import('@/tabviews/custom/components/card/double-data-card'))
 const EditTable = asyncComponent(() => import('@/tabviews/custom/components/table/edit-table'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
@@ -173,6 +174,12 @@
         return (
           <Col span={item.width} style={style} key={item.uuid}>
             <NormalTable config={item} data={data} mainSearch={mainSearch}/>
+          </Col>
+        )
+      } else if (item.type === 'card' && item.subtype === 'dualdatacard') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <DoubleDataCard config={item} mainSearch={mainSearch}/>
           </Col>
         )
       } else if (item.type === 'bar' || item.type === 'line') {
@@ -388,7 +395,7 @@
     if (!config.components || config.components.length === 0) return (<div style={config.style}></div>)
     
     return (
-      <div className={'normal-group-wrap ' + (config.setting.layout || '')} id={config.uuid} style={config.style}>
+      <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}
diff --git a/src/tabviews/custom/components/interfaces/interItem/index.jsx b/src/tabviews/custom/components/interfaces/interItem/index.jsx
index cffd75b..ab62d9b 100644
--- a/src/tabviews/custom/components/interfaces/interItem/index.jsx
+++ b/src/tabviews/custom/components/interfaces/interItem/index.jsx
@@ -17,20 +17,34 @@
 
   loading = false
   
-  state = {}
+  state = {
+    BID: ''
+  }
 
   componentDidMount () {
-    const { config } = this.props
+    const { config, BID } = this.props
 
     if (config.setting.timer) {
       this.timer = new TimerTask()
       this.timer.init(config.uuid, config.setting.timer, config.setting.timerRepeats, () => {this.loadData()})
     }
+
+    if (!config.setting.supModule) {
+      this.setState({ BID: BID || '' })
+    } else {
+      let BData = window.GLOB.CacheData.get(config.setting.supModule)
+
+      if (BData) {
+        this.setState({ BID: BData.$BID || '' })
+      }
+    }
+
     setTimeout(() => {
       this.loadData()
     }, config.setting.delay)
 
     MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
   }
 
   shouldComponentUpdate (nextProps, nextState) { return false }
@@ -44,6 +58,18 @@
     }
     this.timer && this.timer.stop()
     MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.props
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID || id !== '') {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
   }
 
   reloadData = (publicId) => {
@@ -53,7 +79,15 @@
   }
 
   async loadData () {
-    const { config, BID } = this.props
+    const { config } = this.props
+    const { BID } = this.state
+
+    if (config.setting.supModule && !BID) {
+      MKEmitter.emit('mkPublicData', config.uuid, { $$empty: true, $$uuid: '' })
+      MKEmitter.emit('resetSelectLine', config.uuid, '', { $$empty: true, $$uuid: '' })
+      this.loading = false
+      return
+    }
 
     if (this.loading) return
 
diff --git a/src/tabviews/custom/components/module/account/index.jsx b/src/tabviews/custom/components/module/account/index.jsx
index 1a9a7b6..4996d2c 100644
--- a/src/tabviews/custom/components/module/account/index.jsx
+++ b/src/tabviews/custom/components/module/account/index.jsx
@@ -1,14 +1,17 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { notification, Select, Divider } from 'antd'
+import { notification, Select, Divider, Modal } from 'antd'
 import { PlusOutlined } from '@ant-design/icons'
+import moment from 'moment'
 
 import Api from '@/api'
+import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 const { Option } = Select
+const { confirm } = Modal
 
 class AccountModule extends Component {
   static propTpyes = {
@@ -39,7 +42,9 @@
 
   loadData = () => {
     let param = {
-      func: 's_get_fcc_book_data'
+      func: 's_get_fcc_book_data',
+      dataM: sessionStorage.getItem('dataM') === 'true' ? 'Y' : '',
+      mk_organization: sessionStorage.getItem('organization') || ''
     }
 
     Api.genericInterface(param).then(res => {
@@ -69,10 +74,6 @@
         return true
       })
 
-      if (!activeItem && books.length > 0) {
-        activeItem = books[0]
-      }
-
       this.setState({books, activeItem})
 
       if (activeItem) {
@@ -82,15 +83,63 @@
   }
 
   changeBook = (value) => {
-    const { books } = this.state
+    const { books, activeItem } = this.state
 
-    let activeItem = books.filter(item => item.id === value)[0]
+    let Item = books.filter(item => item.id === value)[0]
 
-    this.setState({activeItem})
-
-    if (activeItem) {
-      MKEmitter.emit('resetSelectLine', this.props.config.uuid, activeItem.id, activeItem)
+    if (!activeItem && Item) {
+      this.setBook(Item)
+    } else if (Item) {
+      const that = this
+      confirm({
+        title: '纭畾鍒囨崲璐﹀鍚楋紵',
+        content: '鍒囨崲璐﹀鏃剁郴缁熼渶瑕佸埛鏂般��',
+        onOk() {
+          return new Promise(resolve => {
+            that.setBook(Item, resolve)
+          })
+        },
+        onCancel() {}
+      })
     }
+  }
+
+  setBook = (item, resolve) => {
+    if (!resolve) {
+      this.setState({activeItem: item})
+  
+      MKEmitter.emit('resetSelectLine', this.props.config.uuid, item.id, item)
+    }
+    
+    let userid = sessionStorage.getItem('UserID') || ''
+    let sid = localStorage.getItem('SessionUid') || ''
+    let param = {
+      func: 'sPC_TableData_InUpDe',
+      LText: `delete  tmp_session_show_key where createuserid='${userid}' and key_type='fcc_years'
+        insert into tmp_session_show_key ( key_id,key_type,createuserid,CreateUser,CreateStaff) 
+        select '${item.id}','fcc_years','${userid}','${sid}','${sessionStorage.getItem('Full_Name') || ''}'`,
+      exec_type: 'y'
+    }
+
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    param.secretkey = Utils.encrypt('', param.timestamp)
+    param.LText = Utils.formatOptions(param.LText)
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        resolve && resolve()
+        return
+      }
+
+      if (resolve) {
+        window.location.reload()
+      }
+    })
   }
 
   addBook = () => {
@@ -132,11 +181,11 @@
           </div>
         )}>
           {books.map(item => (
-            <Option key={item.id}>{item.account_name}</Option>
+            <Option disabled={!item.months} key={item.id}>{item.account_name}</Option>
           ))}
-        </Select> : <Select value={activeItem ? activeItem.id : ''} placeholder="璇烽�夋嫨璐﹀" onChange={this.changeBook}>
+        </Select> : <Select value={activeItem ? activeItem.id : ''} disabled={config.wrap.readonly === 'true'} placeholder="璇烽�夋嫨璐﹀" onChange={this.changeBook}>
           {books.map(item => (
-            <Option key={item.id}>{item.account_name}</Option>
+            <Option disabled={!item.months} key={item.id}>{item.account_name}</Option>
           ))}
         </Select>}
         {activeItem ? <span className="date">{activeItem.date}</span> : null}
diff --git a/src/tabviews/custom/components/module/account/index.scss b/src/tabviews/custom/components/module/account/index.scss
index 4b04107..1821b31 100644
--- a/src/tabviews/custom/components/module/account/index.scss
+++ b/src/tabviews/custom/components/module/account/index.scss
@@ -16,6 +16,15 @@
   .date {
     margin-left: 15px;
   }
+  .ant-select.ant-select-disabled {
+    .ant-select-selection:hover {
+      border-color: #d9d9d9;
+    }
+    .ant-select-selection, .ant-select-selection:focus, .ant-select-selection:active {
+      border-color: #d9d9d9;
+      box-shadow: none;
+    }
+  }
 }
 
 .mk-add-book {
diff --git a/src/tabviews/custom/components/module/voucher/assistTable/index.jsx b/src/tabviews/custom/components/module/voucher/assistTable/index.jsx
deleted file mode 100644
index 4a5edb7..0000000
--- a/src/tabviews/custom/components/module/voucher/assistTable/index.jsx
+++ /dev/null
@@ -1,734 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Table, Modal, Input, InputNumber, notification, message } from 'antd'
-// import { EditOutlined } from '@ant-design/icons'
-
-import Api from '@/api'
-import Utils from '@/utils/utils.js'
-import MKEmitter from '@/utils/events.js'
-import './index.scss'
-
-class BodyRow extends React.Component {
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.data), fromJS(nextProps.data))
-  }
-
-  render() {
-    let { data, ...resProps } = this.props
-    let style = {}
-    let className = ''
-
-    return <tr {...resProps} className={className} style={style}/>
-  }
-}
-
-class BodyCell extends React.Component {
-  state = {
-    editing: false,
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.record), fromJS(nextProps.record)) ||
-      nextState.editing !== this.state.editing
-  }
-
-  componentDidMount () {
-    MKEmitter.addListener('tdFocus', this.tdFocus)
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-    MKEmitter.removeListener('tdFocus', this.tdFocus)
-  }
-
-  tdFocus = (id) => {
-    const { col, record } = this.props
-
-    if (id !== col.uuid + record.uuid) return
-
-    this.focus()
-  }
-
-  enterPress = () => {
-    const { col, record } = this.props
-    const { value } = this.state
-
-    this.setState({editing: false})
-
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
-
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
-        line.debtor = ''
-      }
-
-      MKEmitter.emit('changeRecord', col.tableId, line)
-    }
-
-    setTimeout(() => {
-      if (col.field === 'creditor') {
-        MKEmitter.emit('nextLine', col, record)
-      } else {
-        let cl = {remark: 'subject', subject: 'debtor', debtor: 'creditor'}
-        MKEmitter.emit('tdFocus', cl[col.uuid] + record.uuid)
-      }
-    }, 50)
-  }
-
-  focus = () => {
-    const { col, record } = this.props
-
-    if (record.type === 'total') return
-
-    this.setState({editing: true, value: record[col.field]}, () => {
-      let node = document.getElementById(col.uuid + record.uuid)
-      node && node.select()
-    })
-  }
-
-  onBlur = () => {
-    const { col, record } = this.props
-    const { value } = this.state
-
-    this.setState({editing: false})
-
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
-
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
-        line.debtor = ''
-      }
-
-      MKEmitter.emit('changeRecord', col.tableId, line)
-    }
-  }
-  
-  onChange = (val) => {
-    this.setState({value: val})
-  }
-
-  render() {
-    let { col, record, className } = this.props
-    const { editing } = this.state
-
-    let children = null
-    let colSpan = 1
-
-    if (col.field === 'remark') {
-      let val = record.remark || ''
-
-      if (record.type === 'total') {
-        children = <div className="content-wrap" style={{lineHeight: '60px'}}>鍚堣: {val}</div>
-        colSpan = 2
-      } else {
-        if (editing) {
-          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-        } else {
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
-        }
-      }
-    } else if (col.field === 'subject') {
-      if (record.type === 'total') {
-        colSpan = 0
-      } else {
-        let val = record.subject || ''
-  
-        if (editing) {
-          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-        } else {
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
-        }
-      }
-    } else if (col.field === 'debtor') {
-      let val = record.debtor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
-
-      if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-      } 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 === 'creditor') {
-      let val = record.creditor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
-
-      if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
-      } 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>
-      }
-    }
-
-    if (!colSpan) return null
-
-    return (<td colSpan={colSpan} className={className}>{children}</td>)
-  }
-}
-
-class AssistTable extends Component {
-  static propTpyes = {
-    config: PropTypes.object,        // 鑿滃崟Id
-    BID: PropTypes.any,              // 涓昏〃ID
-    data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
-    total: PropTypes.any,            // 鎬绘暟
-    loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
-    refreshdata: PropTypes.func,     // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
-  }
-
-  state = {
-    data: [],
-    edData: [],
-    edColumns: [],
-    tableId: '',          // 琛ㄦ牸ID
-    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
-    columns: null,        // 鏄剧ず鍒�
-    loading: false,
-  }
-
-  UNSAFE_componentWillMount () {
-    const { config } = this.props
-
-    let data = [
-      {remark: '鎻愮幇', subject: '1001 搴撳瓨鐜伴噾', debtor: 124, creditor: ''},
-      {remark: '璐叆鍥哄畾璧勪骇', subject: '1001 搴撳瓨鐜伴噾', debtor: '', creditor: 124},
-      {remark: '杞粨閿�鍞垚鏈�', subject: '1001 搴撳瓨鐜伴噾', debtor: -524, creditor: ''},
-      {remark: '鎻愮幇', subject: '1001 搴撳瓨鐜伴噾', debtor: 34, creditor: ''},
-    ]
-
-    data = this.initData(data)
-    data.push(this.getTotalLine(data))
-
-    let columns = [
-      {
-        title: '鎽樿',
-        dataIndex: 'remark',
-        key: 'remark',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'remark', field: 'remark', tableId: config.uuid},
-        })
-      },
-      {
-        title: '浼氳绉戠洰',
-        dataIndex: 'subject',
-        key: 'subject',
-        width: '34%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'subject', field: 'subject', tableId: config.uuid},
-        })
-      },
-      {
-        title: () => (<>
-          <div className="money-title">鍊熸柟閲戦</div>
-          <div className="money-uint">
-            <span>浜�</span> <span>鍗�</span> <span>鐧�</span> <span>鍗�</span> <span>涓�</span> <span>鍗�</span>
-            <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
-          </div>
-        </>),
-        dataIndex: 'debtor',
-        key: 'debtor',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'debtor', field: 'debtor', tableId: config.uuid},
-        })
-      },
-      {
-        title: () => (<>
-          <div className="money-title">璐锋柟閲戦</div>
-          <div className="money-uint">
-            <span>浜�</span> <span>鍗�</span> <span>鐧�</span> <span>鍗�</span> <span>涓�</span> <span>鍗�</span>
-            <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
-          </div>
-        </>),
-        dataIndex: 'creditor',
-        key: 'creditor',
-        width: '22%',
-        onCell: record => ({
-          record,
-          col: {uuid: 'creditor', field: 'creditor', tableId: config.uuid},
-        })
-      }
-    ]
-
-    this.setState({
-      data: data,
-      edData: fromJS(data).toJS(),
-      columns,
-      tableId: config.uuid
-    })
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  componentDidMount () {
-    MKEmitter.addListener('nextLine', this.nextLine)
-    MKEmitter.addListener('delRecord', this.delRecord)
-    MKEmitter.addListener('changeRecord', this.changeRecord)
-  }
-
-  /**
-   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
-   */
-  componentWillUnmount () {
-    this.setState = () => {
-      return
-    }
-    MKEmitter.removeListener('nextLine', this.nextLine)
-    MKEmitter.removeListener('delRecord', this.delRecord)
-    MKEmitter.removeListener('changeRecord', this.changeRecord)
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps) {
-    if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
-      this.setState({data: nextProps.data || []})
-    }
-  }
-
-  initData = (data) => {
-    let _data = data.map((item, i) => {
-      item.uuid = Utils.getuuid()
-      item.index = i
-      
-      return item
-    })
-
-    if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
-      }
-    }
-    return _data
-  }
-
-  getTotalLine = (data) => {
-    let totalLine = {uuid: Utils.getuuid(), type: 'total'}
-    let debtor = ''
-    let creditor = ''
-
-    data.forEach(item => {
-      if (typeof(item.debtor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
-        }
-
-        debtor += item.debtor
-      } else if (typeof(item.creditor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
-        }
-        if (creditor === '') {
-          creditor = 0
-        }
-        creditor += item.creditor
-      }
-    })
-
-    totalLine.debtor = debtor
-    totalLine.creditor = creditor
-
-    totalLine.remark = this.changeMoneyToChinese(debtor)
-    
-    return totalLine
-  }
-  
-  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 === '') return ''
-
-    if (money >= maxNum) return '瓒呭嚭鏈�澶у鐞嗘暟瀛�'
-
-    if (money === 0) {
-      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
-      return ChineseStr
-    }
-    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
-  }
-
-  nextLine = (col, record) => {
-    const { edData, tableId } = this.state
-
-    if (col.tableId !== tableId) return
-
-    if (record.index < edData.length - 2) {
-      MKEmitter.emit('tdFocus', 'remark' + edData[record.index + 1].uuid)
-    } else {
-      let _data = fromJS(edData).toJS()
-      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subject: '', debtor: '', creditor: ''}
-
-      _data.splice(_data.length - 1, 0, line)
-
-      this.setState({edData: _data}, () => {
-        MKEmitter.emit('tdFocus', 'remark' + line.uuid)
-      })
-    }
-  }
-
-  plusLine = (initEditLine) => {
-    const { edData } = this.state
-
-    let item = {...edData[edData.length - 1]}
-
-    item.key = item.key + 1
-    item.$$uuid = '$new'
-
-    this.setState({edData: [...edData, item]}, () => {
-      MKEmitter.emit('tdFocus', initEditLine.uuid + item.uuid)
-    })
-  }
-
-  delRecord = (id, record) => {
-    const { tableId, edData } = this.state
-
-    if (id !== tableId) return
-
-    let _data = edData.filter(item => item.uuid !== record.uuid)
-
-    _data.pop()
-
-    if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
-      }
-    }
-
-    _data.push(this.getTotalLine(_data))
-
-    this.setState({edData: _data})
-  }
-
-  changeRecord = (tableId, record) => {
-    if (tableId !== this.state.tableId) return
-
-    let _data = this.state.edData.map(item => {
-      if (item.uuid === record.uuid) {
-        return record
-      } else {
-        return item
-      }
-    })
-
-    _data.pop()
-
-    if (record.index === _data.length - 1) {
-      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subject: '', debtor: '', creditor: ''})
-    }
-
-    _data.push(this.getTotalLine(_data))
-
-    this.setState({edData: _data})
-  }
-
-  addLine = () => {
-    const { BID } = this.props
-    const { edData } = this.state
-
-    let item = {}
-    if (edData.length > 0) {
-      item = {...edData[edData.length - 1]}
-      item.key = item.key + 1
-      item.$$uuid = '$new'
-    } else {
-      item.key = 0
-      item.$$uuid = '$new'
-      item.$$BID = BID || ''
-    }
-
-    this.setState({edData: [...edData, item]})
-  }
-
-  checkData = () => {
-    const { edData } = this.state
-
-    if (edData.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '鎻愪氦鏁版嵁涓嶅彲涓虹┖锛�',
-        duration: 5
-      })
-      return
-    }
-    let err = ''
-    let data = fromJS(edData).toJS().map(item => {
-      // let line = []
-      // fields.forEach(col => {
-      //   if (col.editable !== 'true' || item.$deleted) {
-      //     if (col.type === 'number') {
-      //       item[col.field] = +item[col.field]
-      //       if (isNaN(item[col.field])) {
-      //         item[col.field] = 0
-      //       }
-      //     } else {
-      //       item[col.field] = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     }
-      //     return
-      //   }
-      //   if (col.type === 'text') {
-      //     let val = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     if (col.required === 'true' && !val) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //     }
-      //     item[col.field] = val
-      //   } else if (col.type === 'number') {
-      //     let val = item[col.field]
-      //     if (!val && val !== 0) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //       return
-      //     }
-      //     val = +val
-      //     if (isNaN(val)) {
-      //       line.push(`${col.label}鏁版嵁鏍煎紡閿欒`)
-      //       return
-      //     }
-
-      //     val = +val.toFixed(col.decimal || 0)
-          
-      //     if (typeof(col.max) === 'number' && val > col.max) {
-      //       line.push(`${col.label}涓嶅彲澶т簬${col.max}`)
-      //     } else if (typeof(col.min) === 'number' && val < col.min) {
-      //       line.push(`${col.label}涓嶅彲灏忎簬${col.min}`)
-      //     }
-
-      //     item[col.field] = val
-      //   }
-      // })
-
-      return item
-    })
-
-    if (err) {
-      notification.warning({
-        top: 92,
-        message: err,
-        duration: 5
-      })
-    } else {
-      this.submit(data)
-    }
-  }
-
-  submit = (data) => {
-    const { BID } = this.props
-
-    let param = {
-      // excel_in: result.lines,
-      BID: BID || ''
-    }
-
-    this.setState({
-      loading: true
-    })
-
-    param.func = 'submit.innerFunc'
-
-    Api.genericInterface(param).then((res) => {
-      if (res.status) {
-        this.execSuccess(res)
-      } else {
-        this.execError(res)
-      }
-    }, () => {
-      this.execError({})
-    })
-  }
-
-  execSuccess = (res) => {
-    const { submit } = this.props
-
-    if (res && res.ErrCode === 'S') { // 鎵ц鎴愬姛
-      notification.success({
-        top: 92,
-        message: res.ErrMesg || '鎵ц鎴愬姛',
-        duration: submit.stime ? submit.stime : 2
-      })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
-      Modal.success({
-        title: res.ErrMesg || '鎵ц鎴愬姛'
-      })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
-
-    }
-
-    this.setState({
-      loading: false
-    })
-
-    if (submit.closetab === 'true') {
-      MKEmitter.emit('popclose')
-    }
-    if (submit.execSuccess !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit)
-    }
-  }
-
-  execError = (res) => {
-    const { submit } = this.props
-
-    if (res.ErrCode === 'E') {
-      Modal.error({
-        title: res.message || res.ErrMesg,
-      })
-    } else if (res.ErrCode === 'N') {
-      notification.error({
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ntime ? submit.ntime : 10
-      })
-    } else if (res.ErrCode === 'F') {
-      notification.error({
-        className: 'notification-custom-error',
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ftime ? submit.ftime : 10
-      })
-    } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
-    }
-    
-    this.setState({
-      loading: false
-    })
-
-    if (submit.execError !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit)
-    }
-  }
-
-  render() {
-    const { edData, columns} = this.state
-
-    const components = {
-      body: {
-        row: BodyRow,
-        cell: BodyCell
-      }
-    }
-
-    return (
-      <div className="voucher-table-wrap">
-        <Table
-          rowKey="uuid"
-          components={components}
-          columns={columns}
-          dataSource={edData}
-          bordered={true}
-          // loading={this.props.loading}
-          onRow={(record, index) => {
-            return {
-              data: record
-            }
-          }}
-          pagination={false}
-        />
-      </div>
-    )
-  }
-}
-
-export default AssistTable
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/assistTable/index.scss b/src/tabviews/custom/components/module/voucher/assistTable/index.scss
deleted file mode 100644
index e8175c8..0000000
--- a/src/tabviews/custom/components/module/voucher/assistTable/index.scss
+++ /dev/null
@@ -1,259 +0,0 @@
-.voucher-table-wrap {
-  position: relative;
-  padding: 0px;
-
-  .normal-table-footer {
-    padding: 10px 0px;
-    color: rgba(0, 0, 0, 0.65);
-  }
-  .normal-table-footer.pagination {
-    position: absolute;
-    bottom: 10px;
-  }
-  >.ant-table-wrapper {
-    position: relative;
-    z-index: 1;
-  }
-  .ant-table {
-    color: inherit;
-    font-size: inherit;
-  }
-
-  .money-uint {
-    display: flex;
-    span {
-      display: inline-block;
-      flex: 1;
-      text-align: center;
-      font-size: 12px;
-    }
-    span:not(.last) {
-      border-right: 1px solid #e9e9e9;
-    }
-    span:nth-child(3), span:nth-child(6) {
-      border-color: #91d5ff;
-    }
-    span:nth-child(9) {
-      border-color: #ffa39e;
-    }
-  }
-
-  table {
-    max-width: 100%;
-    width: 100%;
-    .ant-table-thead {
-      tr {
-        th {
-          position: relative;
-          background-color: transparent;
-          padding: 0;
-          height: 60px;
-          line-height: 60px;
-          text-align: center;
-
-          .ant-table-header-column {
-            display: block;
-            width: 100%;
-            height: 100%;
-
-            .ant-table-column-title {
-              display: block;
-              width: 100%;
-              height: 100%;
-              font-weight: bold;
-              font-size: 13px;
-            }
-          }
-          .money-title {
-            line-height: 30px;
-            font-weight: bold;
-            font-size: 13px;
-          }
-          .money-uint {
-            line-height: 30px;
-            border-top: 1px solid #dadada;
-          }
-        }
-      }
-    }
-    .ant-table-selection-column {
-      width: 60px;
-      min-width: 60px;
-      max-width: 60px;
-    }
-    .ant-table-tbody {
-      tr td {
-        position: relative;
-        background-color: transparent;
-        padding: 0;
-        height: 60px;
-        vertical-align: top;
-
-        .content-wrap {
-          padding: 5px;
-          height: 100%;
-          font-size: 13px;
-          font-weight: bold;
-        }
-        .money-uint {
-          height: 100%;
-          line-height: 60px;
-
-          span {
-            font-size: 14px;
-            font-weight: bold;
-          }
-        }
-        .money-uint.down {
-          span {
-            color: #ff4d4f;
-          }
-        }
-      }
-    }
-  }
-  .ant-input {
-    height: 60px;
-    border-radius: 0;
-    resize: none;
-  }
-  .ant-input-number {
-    height: 60px;
-    border-radius: 0;
-    
-    .ant-input-number-handler-wrap {
-      display: none;
-    }
-    .ant-input-number-input {
-      border-radius: 0;
-      height: 60px;
-    }
-  }
-  .editing_table_cell {
-    .ant-input {
-      padding: 0px;
-      position: absolute;
-      top: 0px;
-      left: 0px;
-      right: 0px;
-      bottom: 0px;
-      border: 1px solid #1890ff;
-    }
-    .ant-input-number-input {
-      position: absolute;
-      top: 0px;
-      left: 0px;
-      right: 0px;
-      bottom: 0px;
-      border: 1px solid #1890ff;
-    }
-    .anticon {
-      color: #ff4d4f;
-      position: absolute;
-      right: 3px;
-      top: calc(50% - 8px);
-    }
-  }
-  td.pointer {
-    position: relative;
-  }
-  td.pointer {
-    .mk-mask {
-      display: none;
-      cursor: pointer;
-      position: absolute;
-      top: 0;
-      left: 0;
-      bottom: 0;
-      right: 0;
-    }
-  }
-}
-.edit-custom-table.editable {
-  td {
-    background-color: #ffffff!important;
-  }
-  td.pointer .mk-mask {
-    display: block;
-  }
-  .mk-operation {
-    display: none;
-  }
-  .ant-table-placeholder {
-    display: none;
-  }
-}
-.edit-custom-table:not(.fixed-height) {
-  .ant-table-body::-webkit-scrollbar {
-    width: 8px;
-    height: 10px;
-  }
-  ::-webkit-scrollbar-thumb {
-    border-radius: 5px;
-    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-    background: rgba(0, 0, 0, 0.13);
-  }
-  ::-webkit-scrollbar-track {/*婊氬姩鏉¢噷闈㈣建閬�*/
-    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
-    border-radius: 3px;
-    border: 1px solid rgba(0, 0, 0, 0.07);
-    background: rgba(0, 0, 0, 0);
-  }
-}
-.edit-custom-table.fixed-height {
-  .ant-table-body {
-    border-bottom: 1px solid rgba(0, 0, 0, .05);
-    .ant-table-fixed {
-      border-bottom: 0;
-    }
-  }
-}
-.edit-custom-table.hidden {
-  thead {
-    display: none;
-  }
-}
-.edit-custom-table.ghost {
-  .ant-table-thead > tr {
-    > th {
-      color: inherit;
-      background: transparent;
-      .ant-table-column-sorter .ant-table-column-sorter-inner {
-        color: inherit;
-      }
-    }
-    > th:hover {
-      background: transparent;
-    }
-  }
-  .ant-table-body {
-    overflow-x: auto;
-    tr {
-      td {
-        background: transparent!important;
-      }
-    }
-    tr:hover td {
-      background: transparent!important;
-    }
-  }
-}
-.image-scale-modal {
-  width: 70vw;
-  min-height: 80vh;
-  top: 10vh;
-  .ant-modal-body {
-    min-height: calc(80vh - 110px);
-    line-height: calc(80vh - 160px);
-    text-align: center;
-  }
-  .ant-modal-footer {
-    text-align: center;
-    span {
-      display: inline-block;
-      color: #1890ff;
-      padding: 5px 15px;
-      cursor: pointer;
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/index.jsx b/src/tabviews/custom/components/module/voucher/index.jsx
index 1b18806..c230975 100644
--- a/src/tabviews/custom/components/module/voucher/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/index.jsx
@@ -1,15 +1,22 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Button, Select, Input, DatePicker, notification } from 'antd'
+import { Button, Select, Input, Modal, DatePicker, notification, InputNumber, Dropdown } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
-import asyncComponent from '@/utils/asyncComponent'
+import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
+import VoucherTable from './voucherTable'
+import SaveAsTemp from './saveAsTemp'
+import ResetRemark from './resetRemark'
+import ResetAttach from './resetAttach'
+import LoadFromTemp from './loadFromTemp'
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
-const VoucherTable = asyncComponent(() => import('./voucherTable'))
+const PrintVoucher = asyncComponent(() => import('./printVoucher'))
+const { confirm } = Modal
 
 class VoucherModule extends Component {
   static propTpyes = {
@@ -18,17 +25,31 @@
 
   state = {
     BID: '',
+    type: 'createVoucher',
     config: null,
     loading: false,
     data: [],
-    disableAdd: false,
-    disableSave: false,
+    tbdata: [],
     typeOptions: [],
-    subjects: [],
     charType: '',
+    charName: '',
     charInt: '',
     vouDate: null,
-    book: null
+    book: null,
+    username: sessionStorage.getItem('User_Name'),
+    remark: '',
+    attachments: 0,
+    attachlist: [],
+    oriAttachs: [],
+    tempTypes: [],
+    tempTypeClass: '',
+    tempTypeName: '',
+    title: '',
+    orgcode: '',
+    orgname: '',
+    status: '', // 鏂板缓鏃讹紝empty銆乧hange銆乻aved
+    saved: false,
+    voucherCode: ''
   }
 
   UNSAFE_componentWillMount () {
@@ -46,12 +67,44 @@
       BID = BData.$BID || ''
     }
 
+    let book = null
+    let vouDate = null
+    if (config.wrap.supBook) {
+      book = window.GLOB.CacheData.get(config.wrap.supBook) || null
+
+      if (book) {
+        let month = book.months
+        vouDate = moment()
+  
+        if (month && month < moment().format('YYYY-MM')) {
+          vouDate = moment(month, 'YYYY-MM').endOf('month')
+        }
+      }
+    }
+
+    // config.wrap.type = 'checkVoucher'
+    // BID = '20230228173542370E2F4FC1773704C29A6A4'
+
+    // config.wrap.type = 'checkTemp'
+    // BID = '20230214174458780MFR8IA576ON4VKNOLVH'
+
+    window.GLOB.CacheVoucher.delete(config.uuid)
+    let type = config.wrap.type || 'createVoucher'
+
+    if (type === 'createVoucher' || type === 'createTemp') {
+      BID = Utils.getguid()
+    }
+
     this.setState({
+      book: book,
+      vouDate: vouDate,
       config: fromJS(config).toJS(),
+      type: type,
       BID: BID || '',
-      book: window.GLOB.CacheData.get(config.wrap.supBook) || null
+      status: 'empty'
     }, () => {
       this.loadData()
+      this.getVoucher()
     })
   }
 
@@ -75,7 +128,7 @@
   }
 
   resetParentParam = (MenuID, id, data) => {
-    const { config } = this.state
+    const { config, type } = this.state
 
     if (config.wrap.supBook === MenuID) {
       let month = data.months
@@ -87,27 +140,815 @@
 
       this.setState({ book: data, vouDate }, () => {
         this.loadData()
+        this.getVoucher()
       })
       return
     }
 
-    if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
+    if (!config.wrap.supModule || config.wrap.supModule !== MenuID || type === 'createVoucher' || type === 'createTemp') return
     if (id !== this.state.BID || id !== '') {
-      this.setState({ BID: id, BData: data }, () => {
-        this.loadData()
+      this.setState({ BID: id }, () => {
+        this.getVoucher()
       })
     }
   }
 
   loadData = () => {
-    const { book } = this.state
+    const { book, config, type } = this.state
 
     if (!book) return
 
     let param = {
       func: 's_get_fcc_account_data',
+      // account_code: book.account_code || '',
+      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD'),
+      account_year_code: book.account_year_code || '',
+      months: book.months ? book.months : moment().format('YYYY-MM'),
+      BID: book.id
+    }
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      let typeOptions = res.char || []
+      if (type === 'createVoucher') {
+        let charInt = typeOptions[0] ? typeOptions[0].voucher_char_int + 1 : 1
+
+        this.setState({
+          typeOptions: typeOptions,
+          charType: typeOptions[0] ? typeOptions[0].voucher_class : '',
+          charName: typeOptions[0] ? typeOptions[0].voucher_char : '',
+          charInt: charInt,
+          orgcode: res.orgcode,
+          orgname: res.orgname,
+          tempTypes: res.temp_type || []
+        })
+      } else {
+        this.setState({
+          typeOptions: typeOptions,
+          orgcode: res.orgcode,
+          orgname: res.orgname,
+          tempTypes: res.temp_type || []
+        })
+      }
+
+      let names = {}
+      let supplier = []
+      let customer = []
+      let department = []
+      let project = []
+      let inventory = []
+      let employee = []
+      let cash_flow = []
+      let others = []
+
+      res.sup && res.sup.forEach(item => {
+        names[item.sup_type_code] = item.sup_type_name
+      })
+
+      res.supplier && res.supplier.forEach(item => {
+        supplier.push({value: item.suppliercode, label: item.suppliername})
+      })
+
+      res.customer && res.customer.forEach(item => {
+        customer.push({value: item.customercode, label: item.customername})
+      })
+      
+      res.co_pro && res.co_pro.forEach(item => {
+        department.push({value: item.co_pro_code, label: item.co_pro_name})
+      })
+        
+      res.pm && res.pm.forEach(item => {
+        project.push({value: item.projectcode, label: item.projectname})
+      })
+        
+      res.materiel && res.materiel.forEach(item => {
+        inventory.push({value: item.productcode, label: item.productname})
+      })
+        
+      res.workers && res.workers.forEach(item => {
+        employee.push({value: item.workercode, label: item.workername})
+      })
+        
+      res.cash_flow && res.cash_flow.forEach(item => {
+        cash_flow.push({value: item.cash_flow_code, label: item.cash_flow_name})
+      })
+
+      res.others && res.others.forEach(item => {
+        others.push({value: item.sup_acc_code, label: item.sup_acc_name, parentId: item.sup_acc_type})
+      })
+
+      let message = {
+        subjects: res.subjects || [],
+        names: names,
+        supplier: supplier,
+        customer: customer,
+        department: department,
+        project: project,
+        inventory: inventory,
+        currency: res.currency || [],
+        employee: employee,
+        cash_flow: cash_flow,
+        others: others,
+        account_code: res.account_code,
+        account_year_code: res.account_year_code
+      }
+
+      window.GLOB.CacheVoucher.set(config.uuid, message)
+    })
+  }
+
+  getVoucher = () => {
+    const { book, BID, type } = this.state
+
+    if (!book || !BID || type === 'createVoucher' || type === 'createTemp') return
+
+    let param = {
+      func: 's_get_fcc_voucher',
+      BID: book.id,
+      ID: BID
+    }
+
+    if (type === 'checkTemp') {
+      param.func = 's_get_fcc_voucher_temp'
+    }
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      let data = []
+      if (res.voucher) {
+        data = res.voucher.map(line => {
+          line.uuid = line.subject_id || ''
+
+          if (line.direction_type === 'credit') {
+            line.credit = line.net_amount || 0
+            line.debit = ''
+          } else {
+            line.debit = line.net_amount || 0
+            line.credit = ''
+          }
+
+          line.unitratio = line.foreign_unitratio || 0
+          line.exratecode = line.foreign_exratecode || ''
+          line.exratename = line.foreign_exratename || ''
+          line.local_currency = line.local_exratecode || ''
+          line.foreign_currency_type = line.foreign_type || ''
+
+          if (line.sup) {
+            line.supAccounts = line.sup.map(cell => {
+              cell.uuid = cell.sup_id
+              return cell
+            })
+            delete line.sup
+          }
+
+          return line
+        })
+      }
+
+      if (type !== 'checkTemp') {
+        let files = []
+
+        res.fcc_files && res.fcc_files.forEach(file => {
+          file.attachments.forEach(item => {
+            item.id = item.attach_id
+            item.data_code = file.data_code
+            item.data_name = file.data_name
+            item.BID = file.id
+
+            files.push(item)
+          })
+        })
+
+        this.setState({
+          data: data,
+          attachlist: files,
+          vouDate: res.fibvoucherdate ? moment(res.fibvoucherdate, 'YYYY-MM-DD') : null,
+          charType: res.voucher_class,
+          charName: res.voucher_char,
+          charInt: res.voucher_char_int,
+          // orgcode: res.orgcode,
+          // orgname: res.orgname,
+          voucherCode: res.voucher_code || '',
+          tbdata: fromJS(data).toJS(),
+          oriAttachs: fromJS(files).toJS(),
+          attachments: res.attachments_int,
+          title: res.voucher_text || '',
+          remark: res.remark || '',
+          status: 'saved'
+        })
+      } else {
+        this.setState({
+          data: data,
+          tbdata: fromJS(data).toJS(),
+          title: res.voucher_text || '',
+          tempTypeClass: res.typechartwo || '',
+          tempTypeName: res.typecharthree || '',
+          status: 'saved'
+        })
+      }
+    })
+  }
+
+  triggersave = (t) => {
+    const { tbdata } = this.state
+
+    let err = ''
+    let tip = ''
+    let list = []
+
+    tbdata.forEach((line, index) => {
+      if (err) return
+      if (line.type === 'total') {
+        if (line.debit !== line.credit) {
+          err = '鍊熻捶涓嶅钩琛★紒'
+        }
+        return
+      }
+
+      let _index = index + 1
+
+      if (!line.subject_voucher_text && !line.subject_code && !line.debit && line.debit !== 0 && !line.credit && line.credit !== 0) {
+        if (_index === 1) {
+          err = '绗�1琛屼笉鍙负绌恒��'
+        }
+
+        return
+      }
+
+      if (!line.subject_voucher_text) {
+        err = `绗�${_index}琛岋紝鎽樿涓嶅彲涓虹┖銆俙
+      } else if (!line.subject_code) {
+        err = `绗�${_index}琛岋紝绉戠洰涓嶅彲涓虹┖銆俙
+      } else if (!line.debit && line.debit !== 0 && !line.credit && line.credit !== 0) {
+        err = `绗�${_index}琛岋紝璇疯緭鍏ラ噾棰濄�俙
+      } else if (line.debit === 0 || line.credit === 0) {
+        err = `绗�${_index}琛岋紝閲戦涓嶈兘涓�0銆俙
+      } else if (line.foreign_currency_type === 'Y' && !line.foreign_amount) {
+        err = `绗�${_index}琛岋紝鍘熷竵涓嶅彲涓虹┖鎴栦负0銆俙
+      } else if (line.sup_accounting && !line.supAccounts) {
+        err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+      } else if (line.sup_accounting && line.supAccounts) {
+        line.supAccounts.forEach(item => {
+          if (item.sup_acc_type === 'supplier') {
+            if (!item.suppliercode || !item.suppliername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'customer') {
+            if (!item.customercode || !item.customername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'department') {
+            if (!item.co_pro_code || !item.co_pro_name) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'project') {
+            if (!item.projectcode || !item.projectname) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'inventory') {
+            if (!item.productcode || !item.productname) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'employee') {
+            if (!item.workercode || !item.workername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'cash_flow') {
+            if (!item.cash_flow_code || !item.cash_flow_name) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (!item.sup_acc_type || !item.sup_acc_code || !item.sup_acc_name) {
+            err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+          }
+        })
+      }
+
+      if (line.count_type === 'Y' && !err) {
+        if (!line.fcc_count) {
+          tip += `绗�${_index}琛岋紝鏁伴噺涓虹┖鎴栦负0锛侊紱`
+        } else if (line.net_unitprice) {
+          if (line.debit && line.debit !== line.fcc_count * line.net_unitprice) {
+            tip += `绗�${_index}琛岋紝鏁伴噺鍜岄噾棰濅笉鍖归厤锛侊紱`
+          } else if (line.credit && line.credit !== line.fcc_count * line.net_unitprice) {
+            tip += `绗�${_index}琛岋紝鏁伴噺鍜岄噾棰濅笉鍖归厤锛侊紱`
+          }
+        }
+      }
+
+      list.push(line)
+    })
+
+    if (!err && list.length === 0) {
+      err = '绗�1琛屼笉鍙负绌恒��'
+    }
+
+    if (err) {
+      notification.warning({
+        top: 92,
+        message: err,
+        duration: 5
+      })
+      return
+    }
+
+    if (tip) {
+      const _this = this
+      confirm({
+        content: tip + '纭瑕佷繚瀛樺悧锛�',
+        onOk() {
+          _this.voucherSave(list, t)
+        },
+        onCancel() {}
+      })
+    } else {
+      this.voucherSave(list, t)
+    }
+  }
+
+  voucherSave = (list, t) => {
+    const { type, BID, data, config, voucherCode, charInt, charType, vouDate, book, remark, charName, attachments, title, orgcode, orgname, attachlist, oriAttachs } = this.state
+
+    let err = ''
+    if (!book) {
+      err = '璇烽�夋嫨璐﹀锛�'
+    } else if (!vouDate) {
+      err = '璇烽�夋嫨鏃ユ湡锛�'
+    } else if (!charName || !charInt) {
+      err = '璇烽�夋嫨鍑瘉鍙凤紒'
+    }
+
+    if (err) {
+      notification.warning({
+        top: 92,
+        message: err,
+        duration: 5
+      })
+      return
+    }
+
+    let param = {
+      func: 's_fcc_voucher_addupt',
+      BID: book.id,
+      ID: BID,
+      voucher_code: voucherCode || '',
+      voucher_text: title,
+      remark: remark,
+      account_year_code: book.account_year_code || '',
+      voucher_type: config.wrap.voucherType || '',
+      voucher_type_text: config.wrap.voucherTypeText || '',
+      orgcode: orgcode || '',
+      orgname: orgname || '',
+      voucher_class: charType,
+      years: book.years,
+      months: moment(vouDate).format('YYYY-MM'),
+      business_type: config.wrap.businessType || '',
+      voucher_sign: config.wrap.voucherSign || '',
+      voucher_char: charName,
+      voucher_char_int: charInt,
       account_code: book.account_code || '',
-      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD')
+      fibvoucherdate: moment(vouDate).format('YYYY-MM-DD'),
+      UserName: sessionStorage.getItem('User_Name') || '',
+      FullName: sessionStorage.getItem('Full_Name') || '',
+      attachments_int: attachments,
+      sup_data: '',
+      subject_data: '',
+      attachments_data: ''
+    }
+
+    // id,deleted
+    // 闄勪欢鍒楄〃
+
+    // subject_id,subject_voucher_code,voucher_lp,subject_code,subject_name,subject_voucher_text,fcc_count,net_unitprice,unit,net_amount,direction_type
+    // ,exratecode,exratename,unitratio,sup_accounting ,direction_type_count,src_amount,deleted,local_exratecode
+
+    // sup_id,sup_voucher_code,sup_voucher_lp,voucher_sup_lp,sup_subject_code,sup_subject_name,sup_voucher_text,sup_direction_type,sup_net_amount,customercode,customername,suppliercode,suppliername,co_pro_code,co_pro_name,workercode,workername,project_code,project_name,productcode,productname,cash_flow_code,cash_flow_name,sup_acc_code,sup_acc_name,sup_acc_type,sup_bid,deleted
+    // 杈呭姪绉戠洰琛宨d锛屾柊澧炴椂绌猴紝鍑瘉琛屽彿绌猴紝杈呭姪绉戠洰琛屽彿绌猴紝绉戠洰缂栫爜锛岀鐩悕绉帮紝杈呭姪绉戠洰鎽樿绌猴紝鏂瑰悜'debit'銆�'credit'锛岃閲戦锛屽鎴风紪鐮侊紝瀹㈡埛鍚嶇О锛屼緵搴斿晢缂栫爜锛屼緵搴斿晢鍚嶇О锛岄儴闂ㄧ紪鐮侊紝閮ㄩ棬鍚嶇О锛岃亴鍛樼紪鐮侊紝鑱屽憳鍚嶇О锛岄」鐩紪鐮侊紝椤圭洰鍚嶇О锛屼骇鍝佺紪鐮侊紝浜у搧鍚嶇О锛岀幇閲戠紪鐮侊紝鐜伴噾鍚嶇О锛岃嚜瀹氫箟绉戠洰缂栫爜锛岃嚜瀹氫箟绉戠洰鍚嶇О锛岃緟鍔╃鐩被鍨嬶紝鍑瘉琛孖D锛屽垹闄ゆ爣璁�
+    
+    let sup_data = []
+    let voucherMap = new Map()
+    let supMap = new Map()
+    let extract = localStorage.getItem(window.GLOB.host + '_voucher_extract')
+    extract = extract ? JSON.parse(extract) : []
+
+    data.forEach(item => {
+      voucherMap.set(item.uuid, item)
+
+      if (item.sup_accounting && item.supAccounts) {
+        item.supAccounts.forEach(cell => {
+          if (!cell.sup_acc_type) return
+
+          let _cell = {...cell}
+
+          _cell.sup_voucher_code = item.subject_voucher_code || ''
+          _cell.sup_voucher_lp = item.voucher_lp || ''
+          _cell.sup_subject_code = item.subject_code || ''
+          _cell.sup_subject_name = item.subject_name || ''
+          _cell.sup_bid = item.uuid || ''
+          _cell.sup_direct = item.debit ? 'debit' : 'credit'
+          _cell.sup_net_amount = item.debit || item.credit
+
+          supMap.set(item.uuid + cell.sup_acc_type, _cell)
+        })
+      }
+    })
+    
+    let subject_data = list.map(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      let direct = item.debit ? 'debit' : 'credit'
+      
+      if (type === 'createVoucher' && item.subject_voucher_text && item.subject_voucher_text.length < 20) {
+        extract.unshift(item.subject_voucher_text)
+      }
+
+      if (voucherMap.has(item.uuid)) {
+        voucherMap.delete(item.uuid)
+      }
+      if (item.sup_accounting && item.supAccounts) {
+        item.supAccounts.forEach(n => {
+          if (supMap.has(item.uuid + n.sup_acc_type)) {
+            supMap.delete(item.uuid + n.sup_acc_type)
+          }
+
+          sup_data.push(`'${n.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${n.voucher_sup_lp || ''}','${item.subject_code}','${item.subject_name}','${n.sup_voucher_text || ''}','${direct}',${item.debit || item.credit},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${item.uuid}',0`)
+        })
+      }
+      return `'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.debit ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},0,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`
+    })
+
+    if (type === 'createVoucher') {
+      extract = Array.from(new Set(extract))
+      if (extract.length > 20) {
+        extract.length = 20
+      }
+      localStorage.setItem(window.GLOB.host + '_voucher_extract', JSON.stringify(extract))
+    }
+
+    voucherMap.forEach(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      let direct = item.debit ? 'debit' : 'credit'
+
+      subject_data.push(`'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.debit ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},1,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`)
+    })
+
+    supMap.forEach(n => {
+      sup_data.push(`'${n.uuid}','${n.sup_voucher_code}','${n.sup_voucher_lp}','${n.voucher_sup_lp || ''}','${n.sup_subject_code}','${n.sup_subject_name}','${n.sup_voucher_text || ''}','${n.sup_direct}',${n.sup_net_amount},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${n.sup_bid}',1`)
+    })
+
+    let attachments_data = []
+    let ids = []
+
+    attachlist.forEach(item => {
+      ids.push(item.id)
+
+      attachments_data.push(`'${item.id}',0`)
+    })
+
+    if (oriAttachs.length > 0) {
+      oriAttachs.forEach(item => {
+        if (!ids.includes(item.id)) {
+          attachments_data.push(`'${item.id}',1`)
+        }
+      })
+    }
+
+    param.subject_data = window.btoa(window.encodeURIComponent(subject_data.join(';un')))
+    param.sup_data = window.btoa(window.encodeURIComponent(sup_data.join(';un')))
+    param.attachments_data = window.btoa(window.encodeURIComponent(attachments_data.join(';un')))
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      notification.success({
+        top: 92,
+        message: '淇濆瓨鎴愬姛锛�' + (res.voucher_char_int !== charInt ? charInt + '鍙峰嚟璇佸彿宸茬粡瀛樺湪锛屽凡涓烘偍鏇存柊涓�' + res.voucher_char_int + '鍙峰嚟璇併��'  : ''),
+        duration: 5
+      })
+
+      if (t === 'add') {
+        this.setState({
+          status: 'empty',
+          remark: '',
+          tbdata: [],
+          oriAttachs: fromJS(attachlist).toJS(),
+          charInt: res.voucher_char_int + 1,
+          BID: Utils.getguid(),
+          saved: false
+        })
+        MKEmitter.emit('cleartable', config.uuid)
+      } else {
+        this.setState({
+          status: 'saved',
+          charInt: res.voucher_char_int || charInt,
+          data: fromJS(list).toJS(),
+          oriAttachs: fromJS(attachlist).toJS(),
+          saved: true
+        })
+      }
+    })
+  }
+
+  triggerTempsave = (name, typeChar, typeName) => {
+    const { tbdata } = this.state
+
+    let err = ''
+    let list = []
+
+    tbdata.forEach((line, index) => {
+      if (err) return
+
+      let _index = index + 1
+
+      if (!line.subject_voucher_text && !line.subject_code) {
+        if (_index === 1) {
+          err = '绗�1琛屼笉鍙负绌恒��'
+        }
+
+        return
+      }
+
+      if (!line.subject_voucher_text) {
+        err = `绗�${_index}琛岋紝鎽樿涓嶅彲涓虹┖銆俙
+      } else if (!line.subject_code) {
+        err = `绗�${_index}琛岋紝绉戠洰涓嶅彲涓虹┖銆俙
+      } else if (line.sup_accounting && !line.supAccounts) {
+        err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+      } else if (line.sup_accounting && line.supAccounts) {
+        line.supAccounts.forEach(item => {
+          if (item.sup_acc_type === 'supplier') {
+            if (!item.suppliercode || !item.suppliername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'customer') {
+            if (!item.customercode || !item.customername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'department') {
+            if (!item.co_pro_code || !item.co_pro_name) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'project') {
+            if (!item.projectcode || !item.projectname) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'inventory') {
+            if (!item.productcode || !item.productname) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'employee') {
+            if (!item.workercode || !item.workername) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (item.sup_acc_type === 'cash_flow') {
+            if (!item.cash_flow_code || !item.cash_flow_name) {
+              err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+            }
+          } else if (!item.sup_acc_type || !item.sup_acc_code || !item.sup_acc_name) {
+            err = `绗�${_index}琛岋紝璇烽�夋嫨杈呭姪鏍哥畻銆俙
+          }
+        })
+      }
+
+      list.push(line)
+    })
+
+    if (!err && list.length === 0) {
+      err = '绗�1琛屼笉鍙负绌恒��'
+    }
+
+    if (err) {
+      notification.warning({
+        top: 92,
+        message: err,
+        duration: 5
+      })
+      return
+    }
+    
+    this.voucherTempSave(list, name, typeChar, typeName)
+  }
+
+  voucherTempSave = (list, name, typeChar, typeName) => {
+    const { type, BID, data, book, title, orgcode, orgname, tempTypeClass, tempTypeName } = this.state
+
+    if (!book) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨璐﹀锛�',
+        duration: 5
+      })
+      return
+    } else if (type !== 'createVoucher' && !title) {
+      notification.warning({
+        top: 92,
+        message: '璇峰~鍐欐ā鏉垮悕绉帮紒',
+        duration: 5
+      })
+      return
+    } else if (type !== 'createVoucher' && !tempTypeClass) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨妯℃澘绫诲瀷锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let id = BID
+    let _name = title
+    let _typeChar = tempTypeClass
+    let _typeName = tempTypeName
+
+    if (type === 'createVoucher') {
+      id = Utils.getguid()
+      _name = name
+      _typeChar = typeChar
+      _typeName = typeName
+    }
+
+    let param = {
+      func: 's_fcc_voucher_addupt_temp',
+      BID: book.id,
+      ID: id,
+      voucher_code: '',
+      voucher_text: _name,
+      remark: '',
+      account_year_code: book.account_year_code || '',
+      voucher_type: 'fcc_temp',
+      voucher_type_text: '鍑瘉妯℃澘',
+      orgcode: orgcode || '',
+      orgname: orgname || '',
+      voucher_class: 'temp',
+      years: book.years,
+      months: moment().format('YYYY-MM'),
+      business_type: '',
+      voucher_sign: 'temp',
+      voucher_char: '',
+      voucher_char_int: 0,
+      account_code: book.account_code || '',
+      fibvoucherdate: moment().format('YYYY-MM-DD'),
+      UserName: sessionStorage.getItem('User_Name') || '',
+      FullName: sessionStorage.getItem('Full_Name') || '',
+      attachments_int: 0,
+      typechartwo: _typeChar,
+      typecharthree: _typeName,
+      sup_data: '',
+      subject_data: ''
+    }
+
+    let sup_data = []
+    let voucherMap = new Map()
+    let supMap = new Map()
+
+    if (type !== 'createVoucher') {
+      data.forEach(item => {
+        voucherMap.set(item.uuid, item)
+  
+        if (item.sup_accounting && item.supAccounts) {
+          item.supAccounts.forEach(cell => {
+            if (!cell.sup_acc_type) return
+  
+            let _cell = {...cell}
+  
+            _cell.sup_voucher_code = item.subject_voucher_code || ''
+            _cell.sup_voucher_lp = item.voucher_lp || ''
+            _cell.sup_subject_code = item.subject_code || ''
+            _cell.sup_subject_name = item.subject_name || ''
+            _cell.sup_bid = item.uuid || ''
+            _cell.sup_direct = !item.credit ? 'debit' : 'credit'
+            _cell.sup_net_amount = item.debit || item.credit || 0
+  
+            supMap.set(item.uuid + cell.sup_acc_type, _cell)
+          })
+        }
+      })
+    }
+    
+    let subject_data = list.map(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      let direct = !item.credit ? 'debit' : 'credit'
+
+      if (voucherMap.has(item.uuid)) {
+        voucherMap.delete(item.uuid)
+      }
+      if (item.sup_accounting && item.supAccounts) {
+        item.supAccounts.forEach(n => {
+          if (supMap.has(item.uuid + n.sup_acc_type)) {
+            supMap.delete(item.uuid + n.sup_acc_type)
+          }
+
+          sup_data.push(`'${n.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${n.voucher_sup_lp || ''}','${item.subject_code}','${item.subject_name}','${n.sup_voucher_text || ''}','${direct}',${item.debit || item.credit || 0},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${item.uuid}',0`)
+        })
+      }
+      return `'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit || 0},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.direct ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},0,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`
+    })
+
+    voucherMap.forEach(item => {
+      let count = item.count_type === 'Y'
+      let curr = item.foreign_currency_type === 'Y'
+      let direct = !item.credit ? 'debit' : 'credit'
+
+      subject_data.push(`'${item.uuid}','${item.subject_voucher_code || ''}','${item.voucher_lp || ''}','${item.subject_code}','${item.subject_name}','${item.subject_voucher_text || ''}',${count ? item.fcc_count || 0 : 0},${count ? item.net_unitprice || 0 : 0},'${item.unit}',${item.debit || item.credit || 0},'${direct}','${curr ? item.exratecode : '01010001'}','${curr ? item.exratename : 'CNY'}',${curr ? item.unitratio || 0 : 0},'${item.sup_accounting}',${item.direct ? 1 : -1},${curr ? item.foreign_amount || 0 : 0},1,'${item.local_currency || ''}','${count ? 'Y' : ''}','${curr ? 'Y' : ''}'`)
+    })
+
+    supMap.forEach(n => {
+      sup_data.push(`'${n.uuid}','${n.sup_voucher_code}','${n.sup_voucher_lp}','${n.voucher_sup_lp || ''}','${n.sup_subject_code}','${n.sup_subject_name}','${n.sup_voucher_text || ''}','${n.sup_direct}',${n.sup_net_amount},'${n.customercode || ''}','${n.customername || ''}','${n.suppliercode || ''}','${n.suppliername || ''}','${n.co_pro_code || ''}','${n.co_pro_name || ''}','${n.workercode || ''}','${n.workername || ''}','${n.project_code || ''}','${n.project_name || ''}','${n.productcode || ''}','${n.productname || ''}','${n.cash_flow_code || ''}','${n.cash_flow_name || ''}','${n.sup_acc_code || ''}','${n.sup_acc_name || ''}','${n.sup_acc_type || ''}','${n.sup_bid}',1`)
+    })
+
+    param.subject_data = window.btoa(window.encodeURIComponent(subject_data.join(';un')))
+    param.sup_data = window.btoa(window.encodeURIComponent(sup_data.join(';un')))
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      notification.success({
+        top: 92,
+        message: '淇濆瓨鎴愬姛锛�',
+        duration: 5
+      })
+
+      if (type !== 'createVoucher') {
+        this.setState({
+          status: 'saved',
+          data: fromJS(list).toJS(),
+        })
+      }
+    })
+  }
+
+  dataChange = (data) => {
+    this.setState({
+      status: 'change',
+      tbdata: data
+    })
+  }
+
+  changeAttach = (val) => {
+    let _val = val
+
+    if (isNaN(val) || val < 0) {
+      _val = 0
+    } else {
+      _val = parseInt(val)
+    }
+    
+    this.setState({attachments: _val, status: 'change'})
+  }
+
+  changeVouDate = (val) => {
+    const { type, status, saved } = this.state
+
+    this.setState({vouDate: val, status: 'change'})
+
+    if (type === 'createVoucher' && val && !saved && (status === 'empty' || status === 'change')) {
+      this.updateVoucherChar(val)
+    }
+  }
+
+  updateVoucherChar = (val) => {
+    const { book, config } = this.state
+
+    if (!book) return
+
+    let param = {
+      func: 's_get_fcc_account_data',
+      search_type: 'Y',
+      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD'),
+      account_year_code: book.account_year_code || '',
+      months: moment(val).format('YYYY-MM'),
+      BID: book.id
     }
 
     Api.genericInterface(param).then(res => {
@@ -122,94 +963,200 @@
 
       let typeOptions = res.char || []
 
-      this.setState({
-        typeOptions: typeOptions,
-        charType: typeOptions[0] ? typeOptions[0].voucher_class : '',
-        charInt: typeOptions[0] ? typeOptions[0].voucher_char_int : '',
-        subjects: res.subjects || [],
-      })
+      if (typeOptions.length > 0) {
+        let charType = this.state.charType
+        let charName = this.state.charName
+        let charInt = this.state.charInt
+  
+        if (charType && typeOptions.filter(n => n.voucher_class === charType) > 0) {
+          typeOptions.forEach(n => {
+            if (n.voucher_class === charType) {
+              charName = n.voucher_char
+              charInt = n.voucher_char_int + 1
+            }
+          })
+        } else {
+          charType = typeOptions[0].voucher_class
+          charName = typeOptions[0].voucher_char
+          charInt = typeOptions[0].voucher_char_int + 1
+        }
 
-      setTimeout(() => {
-        this.getVoucher()
-      }, 200)
+        this.setState({
+          typeOptions: typeOptions,
+          charType: charType,
+          charName: charName,
+          charInt: charInt
+        })
+      }
+
+      let msg = window.GLOB.CacheVoucher.get(config.uuid) || {}
+      msg.currency = res.currency || []
+
+      window.GLOB.CacheVoucher.set(config.uuid, msg)
     })
   }
 
-
-  getVoucher = () => {
-    let data = [
-      {remark: '鎻愮幇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: 124, creditor: ''},
-      {remark: '璐叆鍥哄畾璧勪骇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: '', creditor: 124},
-      {remark: '杞粨閿�鍞垚鏈�', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: -524, creditor: ''},
-      {remark: '鎻愮幇', subjectscode: '1001', subjectsname: '搴撳瓨鐜伴噾', debtor: 34, creditor: ''},
-    ]
-
-    this.setState({
-      data: data
-    })
-  }
-
-  triggeradd = () => {
+  resetAttachList = (vals) => {
+    const { attachlist } = this.state
+    let num = this.state.attachments
     
+    if (num) {
+      num = num + (vals.length - attachlist.length)
+    } else {
+      num = vals.length
+    }
+
+    if (num < 0) {
+      num = 0
+    }
+
+    this.setState({status: 'change', attachlist: vals, attachments: num})
   }
 
-  triggersave = () => {
+  triggermore = () => {
 
   }
 
-  triggerprint = () => {
+  triggerclose = () => {
+    const { config, status } = this.state
 
+    if (status === 'change') {
+      confirm({
+        content: '鍐呭宸插彉鏇达紝纭畾瑕佸叧闂悧锛�',
+        onOk() {
+          MKEmitter.emit('closeTabView', config.$pageId)
+        },
+        onCancel() {}
+      })
+    } else {
+      MKEmitter.emit('closeTabView', config.$pageId)
+    }
+  }
+
+  triggerTempLoad = (id) => {
+    const { book } = this.state
+
+    if (!book) return
+
+    let param = {
+      func: 's_get_fcc_voucher_temp',
+      BID: book.id,
+      ID: id
+    }
+
+    Api.genericInterface(param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      let data = []
+      if (res.voucher) {
+        data = res.voucher.map(line => {
+          line.uuid = line.subject_id || ''
+
+          if (line.direction_type === 'credit') {
+            line.credit = line.net_amount || 0
+            line.debit = ''
+          } else {
+            line.debit = line.net_amount || 0
+            line.credit = ''
+          }
+
+          line.unitratio = line.foreign_unitratio || 0
+          line.exratecode = line.foreign_exratecode || ''
+          line.exratename = line.foreign_exratename || ''
+          line.local_currency = line.local_exratecode || ''
+          line.foreign_currency_type = line.foreign_type || ''
+
+          if (line.sup) {
+            line.supAccounts = line.sup.map(cell => {
+              cell.uuid = cell.sup_id
+              return cell
+            })
+            delete line.sup
+          }
+
+          return line
+        })
+      }
+
+      this.setState({
+        data: data,
+        tbdata: fromJS(data).toJS(),
+        status: 'change'
+      })
+    })
   }
 
   render() {
-    const { config, disableSave, disableAdd, typeOptions, charType, charInt, data, vouDate, subjects } = this.state
+    const { type, status, loading, config, orgcode, orgname, typeOptions, tempTypes, charType, charName, charInt, data, vouDate, username, remark, attachments, title, attachlist, tempTypeClass } = this.state
 
     return (
       <div className="menu-voucher-wrap" style={config.style}>
-        <div className="voucher-header">
-          <Button className="add-background header-btn" disabled={disableAdd} onClick={this.triggeradd}>鏂板</Button>
-          <Button className="add-background header-btn" disabled={disableSave} onClick={this.triggersave}>淇濆瓨</Button>
-          <Button className="print-background header-btn" disabled={disableSave} onClick={this.triggerprint}>鎵撳嵃</Button>
-          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggerprint}>瀵煎叆</Button>
-          <Button className="out-background header-btn" disabled={disableSave} onClick={this.triggerprint}>瀵煎嚭</Button>
-        </div>
-        {config.wrap.type === 'edit' ? <div className="voucher-body">
-          <div className="pre-wrap">
+        {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({charType: val, charInt: option.props.charint})}>
+              <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.voucher_char_int} value={option.voucher_class} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
+                  <Select.Option key={option.voucher_char_int} value={option.voucher_class} charName={option.voucher_char} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
                 )}
               </Select>
-              <Input value={charInt} autoComplete="off" onChange={(e) => this.setState({charInt: e.target.value})}/> 鍙�
+              <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={(val) => this.setState({vouDate: val})}/>
+              鏃ユ湡锛�<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">
-              闄勫崟鎹� <Input autoComplete="off" /> 寮�
-              <Button type="link" className="" onClick={this.triggerprint}>闄勪欢</Button>
-              <Button type="link" className="" onClick={this.triggerprint}>澶囨敞</Button>
+              闄勫崟鎹� <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} subjects={subjects} data={data}/>
-        </div> : null}
-        {config.wrap.type === 'check' ? <div className="voucher-body">
-          <div className="pre-wrap">
-            <div className="voucher-code">
-              璁� 1 鍙�
+          </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="voucher-date">
-              鏃ユ湡锛�2022-02-24
+            <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="voucher-affix">
-              闄勫崟鎹� 2 寮�
-              <Button type="link" className="" onClick={this.triggerprint}>闄勪欢</Button>
-              <Button type="link" className="" onClick={this.triggerprint}>澶囨敞</Button>
+            <div className="temp-action">
+              <Button className="add-background header-btn" onClick={() => this.triggerTempsave()}>淇濆瓨</Button>
+              <Button className="out-background header-btn" onClick={this.triggerclose}>鍏抽棴</Button>
             </div>
-          </div>
-          <VoucherTable config={config} data={data}/>
-        </div> : null}
+          </div> : null}
+          <VoucherTable config={config} loading={loading} data={data} onChange={this.dataChange}/>
+        </div>
+        {type === 'createVoucher' || type === 'checkVoucher' ? <div className="user">鍒跺崟浜猴細{username}</div> : null}
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/module/voucher/index.scss b/src/tabviews/custom/components/module/voucher/index.scss
index e3b1dd9..a2bae1b 100644
--- a/src/tabviews/custom/components/module/voucher/index.scss
+++ b/src/tabviews/custom/components/module/voucher/index.scss
@@ -7,6 +7,7 @@
   background-size: cover;
   min-height: 150px;
   overflow-y: auto;
+  overflow-x: hidden;
   color: #000000;
 
   .voucher-header {
@@ -20,7 +21,6 @@
     }
   }
   .voucher-body {
-    padding: 0 15px;
     .voucher-code {
       display: inline-block;
       width: 160px;
@@ -33,6 +33,22 @@
       .ant-input {
         width: 60px;
       }
+      .ant-input-number {
+        display: inline-block;
+        width: 60px;
+        .ant-input-number-handler-wrap {
+          display: none;
+        }
+      }
+    }
+    .voucher-affix {
+      .ant-input-number {
+        display: inline-block;
+        width: 50px;
+        .ant-input-number-handler-wrap {
+          display: none;
+        }
+      }
     }
     .pre-wrap {
       padding: 10px 0px;
@@ -43,11 +59,38 @@
         width: 120px;
       }
     }
+    .voucher-text {
+      display: inline-block;
+      width: calc(56% - 350px);
+      margin-left: 12px;
+    }
     .voucher-affix {
       float: right;
-      width: 250px;
+      width: 240px;
       .ant-input {
         width: 60px;
+      }
+    }
+    .pre-temp-wrap {
+      padding: 10px 0px;
+      .temp-text {
+        display: inline-block;
+        width: 22%;
+        white-space: nowrap;
+        padding-left: 10px;
+
+        .ant-input {
+          width: calc(100% - 70px);
+        }
+        .ant-select {
+          width: calc(100% - 70px);
+        }
+      }
+      .temp-action {
+        float: right;
+        .ant-btn {
+          margin-left: 15px;
+        }
       }
     }
   }
@@ -73,6 +116,9 @@
     border-color: var(--mk-sys-color);
     color: #ffffff;
   }
+  .user {
+    padding: 15px 30px 0px;
+  }
 }
 
 .mk-vcode-dropdown {
@@ -83,3 +129,30 @@
     display: none;
   }
 }
+.mk-voucher-dropdown-wrap {
+  background: #ffffff;
+  border: 1px solid #d8d8d8;
+  border-radius: 4px;
+  min-height: 66px;
+  .ant-btn {
+    display: block;
+    width: 100%;
+    border: none;
+  }
+  .split {
+    width: 100%;
+    height: 1px;
+    background: #d8d8d8;
+  }
+}
+.mk-temp-add-modal {
+  .ant-form-item {
+    .ant-form-item-label {
+      width: 170px;
+    }
+    .ant-form-item-control-wrapper {
+      width: 250px;
+      display: inline-block;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx b/src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx
new file mode 100644
index 0000000..a04a8ae
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/loadFromTemp/index.jsx
@@ -0,0 +1,103 @@
+import React, {Component} from 'react'
+import { Button, Modal, notification, Empty, Input } from 'antd'
+
+import './index.scss'
+
+const { Search } = Input
+
+class LoadFromTemp extends Component {
+  state = {
+    visible: false,
+    tempId: '',
+    searchkey: '',
+    temps: []
+  }
+
+  submit = () => {
+    const { tempId } = this.state
+
+    if (!tempId) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨妯℃澘锛�',
+        duration: 5
+      })
+      return
+    }
+
+    this.setState({visible: false})
+    this.props.onChange(tempId)
+  }
+
+  trigger = () => {
+    const { tempTypes } = this.props
+    let temps = []
+
+    tempTypes.forEach(item => {
+      if (item.temp_list && item.temp_list.length > 0) {
+        item.temp_list.forEach(cell => {
+          temps.push({
+            id: cell.temp_id,
+            voucher_text: cell.voucher_text || '',
+            data_name: item.data_name || ''
+          })
+        })
+      }
+    })
+
+    this.setState({visible: true, tempId: '', temps, searchkey: ''})
+  }
+
+  checkItem = (id) => {
+    this.setState({tempId: id})
+  }
+
+  render() {
+    const { visible, tempId, temps, searchkey } = this.state
+
+    let _temps = temps
+
+    if (searchkey) {
+      _temps = temps.filter(item => item.voucher_text.indexOf(searchkey) > -1 || item.data_name.indexOf(searchkey) > -1)
+    }
+
+    return (
+      <>
+        <Button onClick={() => this.trigger()}>浠庢ā鏉夸腑鍔犺浇</Button>
+        <Modal
+          title="浠庢ā鏉夸腑鍔犺浇"
+          wrapClassName="mk-temp-list-wrap"
+          visible={visible}
+          width={700}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          destroyOnClose
+        >
+          {visible ? <div className="document-wrap">
+            <Search placeholder="" defaultValue="" style={{ minWidth: '200px' }} onSearch={(val) => this.setState({searchkey: val, tempId: ''})}/>
+            <div className="document-title">
+              <div className="folder-box">妯℃澘绫诲瀷</div>
+              <div className="folder">
+                妯℃澘鍚嶇О
+              </div>
+            </div>
+            <div className="document-body">
+              {_temps.length ? <div className="file-wrap">
+                {_temps.map(doc => {
+                  return <div className="file-item" onClick={() => this.checkItem(doc.id)} key={doc.id}>
+                    <span className={'square-select' + (tempId === doc.id ? ' active' : '')}></span>
+                    <span className="folder-name">{doc.data_name}</span>
+                    <span className="file-name">{doc.voucher_text}</span>
+                  </div>
+                })}
+              </div> : <Empty style={{padding: '10px 0px'}} description={null}/>}
+            </div>
+          </div> : null}
+        </Modal>
+      </>
+    )
+  }
+}
+
+export default LoadFromTemp
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss b/src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss
new file mode 100644
index 0000000..17e09d8
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/loadFromTemp/index.scss
@@ -0,0 +1,117 @@
+.mk-temp-list-wrap {
+  .ant-modal-body {
+    padding: 15px 20px;
+  }
+  .document-wrap {
+    .ant-input-search {
+      width: 200px;
+      margin-bottom: 5px;
+    }
+    .document-title {
+      display: flex;
+      background: #e8e8e8;
+      line-height: 38px;
+      border: 1px solid #d8d8d8;
+      border-bottom: none;
+      padding-left: 38px;
+      .folder-box {
+        width: 200px;
+        text-align: center;
+      }
+      .folder {
+        flex: 1;
+        text-align: center;
+      }
+    }
+    .document-body {
+      border: 1px solid #d8d8d8;
+      height: 300px;
+      .file-wrap {
+        width: 100%;
+        height: 100%;
+        overflow-y: auto;
+        .file-item {
+          border-bottom: 1px solid #e8e8e8;
+          height: 40px;
+          line-height: 40px;
+          display: flex;
+
+          .square-select {
+            top: 12px;
+            margin: 0 10px;
+          }
+          .folder-name {
+            display: inline-block;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            vertical-align: top;
+            text-align: center;
+            width: 200px;
+            padding: 0 5px;
+          }
+          .file-name {
+            flex: 1;
+            display: inline-block;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            vertical-align: top;
+            text-align: center;
+            width: calc(100% - 200px);
+            padding: 0 5px;
+          }
+        }
+      }
+    }
+
+    .file-wrap::-webkit-scrollbar {
+      width: 7px;
+    }
+    .file-wrap::-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);
+    }
+    .file-wrap::-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);
+    }
+
+    .square-select {
+      position: relative;
+      display: inline-block;
+      width: 16px;
+      height: 16px;
+      border: 1px solid #cccccc;
+      box-sizing: content-box;
+      border-radius: 16px;
+      margin: auto;
+      margin-right: 5px;
+      background-color: #ffffff;
+      transition: border-color 0.2s;
+      cursor: pointer;
+    }
+
+    .square-select.active {
+      border-color: var(--mk-sys-color);
+      background: var(--mk-sys-color);
+    }
+
+    .square-select::before {
+      position: relative;
+      top: 1px;
+      left: 6px;
+      content: ' ';
+      display: block;
+      width: 5px;
+      height: 11px;
+      border-style: solid;
+      border-width: 0 2px 2px 0;
+      border-color: #ffffff;
+      transform: rotate(45deg);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/printVoucher/index.jsx b/src/tabviews/custom/components/module/voucher/printVoucher/index.jsx
new file mode 100644
index 0000000..d4fcd37
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/printVoucher/index.jsx
@@ -0,0 +1,354 @@
+import React, {Component} from 'react'
+import { Button } from 'antd'
+import moment from 'moment'
+import html2Canvas from 'html2canvas'
+import JsPDF from 'jspdf'
+
+import './index.scss'
+
+class printVoucher extends Component {
+  state = {
+    loading: false
+  }
+
+  trigger = () => {
+    this.setState({loading: true})
+
+    setTimeout(() => {
+      this.getCanvas()
+    }, 200)
+  }
+
+  getCanvas = () => {
+    const { ID } = this.props
+    let wrap = document.getElementById(ID)
+    let elements = wrap.querySelectorAll('.mk-voucher-print-pdf-wrap')
+    let  pageArr = []
+    const opts = {
+      scale: 1.5,        // 缂╂斁姣斾緥锛屾彁楂樼敓鎴愬浘鐗囨竻鏅板害
+      useCORS: false,    // 鍏佽鍔犺浇璺ㄥ煙鐨勫浘鐗�
+      allowTaint: false, // 鍏佽鍥剧墖璺ㄥ煙锛屽拰 useCORS 浜岃�呬笉鍙叡鍚屼娇鐢�
+      tainttest: false,  // 妫�娴嬫瘡寮犲浘鐗囧凡缁忓姞杞藉畬鎴�
+      logging: false     // 鏃ュ織寮�鍏筹紝鍙戝竷鐨勬椂鍊欒寰楁敼鎴� false
+    }
+    
+    elements = Array.from(elements)
+
+    for (let index = 0; index < elements.length; index++) {
+      // eslint-disable-next-line
+      html2Canvas(elements[index], opts).then(canvas => {
+        // a4绾哥殑灏哄[595.28,841.89]锛宧tml椤甸潰鐢熸垚鐨刢anvas鍦╬df涓浘鐗囩殑瀹介珮
+        const contentWidth = canvas.width
+        const contentHeight = canvas.height
+        const imgWidth = 595.28
+        const imgHeight = (592.28 / contentWidth) * contentHeight
+        const pageData = canvas.toDataURL('image/jpeg', 1.0)
+        // 涓�椤祊df鏄剧ずhtml椤甸潰鐢熸垚鐨刢anvas楂樺害;
+        const pageHeight = (contentWidth / 592.28) * 841.89
+        // 鏈敓鎴恜df鐨刪tml椤甸潰楂樺害
+        const leftHeight = contentHeight
+        pageArr.push({ pageData: pageData, pageHeight: pageHeight, leftHeight: leftHeight, imgWidth: imgWidth, imgHeight: imgHeight })
+
+        if (pageArr.length === elements.length) {
+          this.getPdf(pageArr)
+        }
+      })
+    }
+  }
+
+  getPdf = (pageArr) => {
+    const { orgname, vouDate, charName, charInt } = this.props
+    let title = moment(vouDate).format('YYYY-MM-DD') + charName + '-' + charInt + orgname + moment().format('YYYYMMDDHHmmss')
+    const PDF = new JsPDF('', 'pt', 'a4')
+
+    pageArr.forEach((data, index) => {
+      // 椤甸潰鍋忕Щ
+      let position = 0
+      // 杞崲瀹屾瘯锛宻ave淇濆瓨鍚嶇О鍚庢祻瑙堝櫒浼氳嚜鍔ㄤ笅杞�
+      // 褰撳唴瀹规湭瓒呰繃pdf涓�椤垫樉绀虹殑鑼冨洿锛屾棤闇�鍒嗛〉
+      if (data.leftHeight < data.pageHeight) {
+        // addImage(pageData, 'JPEG', 宸︼紝涓婏紝瀹藉害锛岄珮搴�)璁剧疆
+        PDF.addImage(data.pageData, 'JPEG', 0, 0, data.imgWidth, data.imgHeight)
+      } else {
+        // 瓒呰繃涓�椤垫椂锛屽垎椤垫墦鍗帮紙姣忛〉楂樺害841.89锛�
+        while (data.leftHeight > 0) {
+          PDF.addImage(data.pageData, 'JPEG', 0, position, data.imgWidth, data.imgHeight)
+          data.leftHeight -= data.pageHeight
+          position -= 841.89
+          if (data.leftHeight > 0) {
+            PDF.addPage()
+          }
+        }
+      }
+
+      if (index + 1 === pageArr.length) {
+        PDF.save(title + '.pdf')
+
+        this.setState({loading: false})
+      } else {
+        // 鏈浆鎹㈠埌鏈�鍚庝竴椤垫椂锛宲df澧炲姞涓�椤�
+        PDF.addPage()
+      }
+    })
+  }
+
+  getContent = () => {
+    const { data, orgname, vouDate, charName, charInt, attachments } = this.props
+
+    let list = []
+    let items = []
+    let index = 0
+
+    data.forEach((cell, i) => {
+      if (index < 10) {
+        items.push(cell)
+        index++
+      } else {
+        list.push([...items])
+        index = 0
+        items = []
+      }
+    })
+
+    if (items.length > 0) {
+      while (items.length < 5) {
+        items.push({uuid: index + ''})
+        index++
+      }
+
+      list.push(items)
+    } else if (list.length === 0) {
+      list = [[{uuid: '1'}, {uuid: '2'}, {uuid: '3'}, {uuid: '4'}, {uuid: '5'}]]
+    }
+
+    let total = this.getTotalLine(data)
+
+    if (total.debit) {
+      total.debit = total.debit.toFixed(2)
+    }
+    if (total.credit) {
+      total.credit = total.credit.toFixed(2)
+    }
+
+    return <>
+      {list.map((page, i) => (<div className="mk-voucher-print-pdf-wrap" key={i}>
+        <div className="print-header">
+          <div className="line">
+            <div className="left"></div>
+            <div className="center">璁拌处鍑瘉</div>
+            <div className="right">闄勫崟鎹暟锛歿attachments}</div>
+          </div>
+          <div className="line">
+            <div className="left">鍗曚綅锛歿orgname}</div>
+            <div className="center">鏃ユ湡锛歿moment(vouDate).format('YYYY-MM-DD')}</div>
+            <div className="right">鍑瘉鍙凤細{charName}-{charInt}{list.length > 1 ? `(${i + 1}/${list.length})` : ''}</div>
+          </div>
+        </div>
+        <div className="print-body">
+          <div className="print-line" key="0">
+            <div className="remark" style={{textAlign: 'center'}}>鎽樿</div>
+            <div className="subject" style={{textAlign: 'center'}}>绉戠洰</div>
+            <div className="credit" style={{textAlign: 'center'}}>鍊熸柟閲戦</div>
+            <div className="credit" style={{textAlign: 'center'}}>璐锋柟閲戦</div>
+          </div>
+          {page.map(record => {
+            let remark = record.subject_voucher_text || ''
+
+            if (record.count_type === 'Y') {
+              remark += `锛堟暟閲�:${record.fcc_count !== undefined ? record.fcc_count : ''}锛屽崟浠�:${record.net_unitprice !== undefined ? record.net_unitprice : ''}锛塦
+            }
+            if (record.foreign_currency_type === 'Y') {
+              remark += `锛堣揣甯侊細${record.exratename || ''}锛屾眹鐜囷細${record.unitratio !== undefined ? record.unitratio : ''}锛屽師甯侊細${record.foreign_amount !== undefined ? record.foreign_amount : ''}锛塦
+            }
+
+            let val = ''
+            if (record.subject_code) {
+              val = (record.subject_code || '') + ' ' + (record.subject_name || '')
+  
+              if (record.sup_accounting && record.supAccounts) {
+                record.supAccounts.forEach(item => {
+                  if (item.sup_acc_type === 'supplier') {
+                    val += item.suppliername ? '_'  + item.suppliername : ''
+                  } else if (item.sup_acc_type === 'customer') {
+                    val += item.customername ? '_'  + item.customername : ''
+                  } else if (item.sup_acc_type === 'department') {
+                    val += item.co_pro_name ? '_' + item.co_pro_name : ''
+                  } else if (item.sup_acc_type === 'project') {
+                    val += item.projectname ? '_' + item.projectname : ''
+                  } else if (item.sup_acc_type === 'inventory') {
+                    val += item.productname ? '_' + item.productname : ''
+                  } else if (item.sup_acc_type === 'employee') {
+                    val += item.workername ? '_' + item.workername : ''
+                  } else if (item.sup_acc_type === 'cash_flow') {
+                    val += item.cash_flow_name ? '_' + item.cash_flow_name : ''
+                  } else if (item.sup_acc_name) {
+                    val += '_' + item.sup_acc_name
+                  }
+                })
+              }
+            }
+
+            let debit = record.debit || record.debit === 0 ? record.debit : ''
+            let credit = record.credit || record.credit === 0 ? record.credit : ''
+
+            if (debit) {
+              debit = debit.toFixed(2)
+            }
+            if (credit) {
+              credit = credit.toFixed(2)
+            }
+
+            return <div className="print-line" key={record.uuid}>
+              <div className="remark">{remark}</div>
+              <div className="subject">{val}</div>
+              <div className="credit">{debit}</div>
+              <div className="credit">{credit}</div>
+            </div>
+          })}
+          <div className="print-line" key="total">
+            <div className="remark" style={{width: '60%'}}>鍚堣锛歿total.subject_voucher_text}</div>
+            <div className="credit">{total.debit}</div>
+            <div className="credit">{total.credit}</div>
+          </div>
+        </div>
+        <div className="print-footer">
+          <div>涓荤锛�</div>
+          <div>璁拌处锛�</div>
+          <div>瀹℃牳锛�</div>
+          <div>鍑虹撼锛�</div>
+          <div>鍒跺崟锛�</div>
+        </div>
+      </div>))}
+    </>
+  }
+
+  getTotalLine = (data) => {
+    let totalLine = {uuid: 'total', type: 'total'}
+    let debit = ''
+    let credit = ''
+
+    data.forEach(item => {
+      if (!isNaN(item.debit) && item.debit !== '') {
+        if (debit === '') {
+          debit = 0
+        }
+
+        debit += item.debit
+      } else if (!isNaN(item.credit) && item.credit !== '') {
+        if (debit === '') {
+          debit = 0
+        }
+        if (credit === '') {
+          credit = 0
+        }
+        credit += item.credit
+      }
+    })
+
+    totalLine.debit = debit
+    totalLine.credit = credit
+
+    totalLine.subject_voucher_text = this.changeMoneyToChinese(debit)
+    
+    return totalLine
+  }
+  
+  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 === '') return ''
+
+    if (money >= maxNum) return '瓒呭嚭鏈�澶у鐞嗘暟瀛�'
+
+    if (money === 0) {
+      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
+      return ChineseStr
+    }
+    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
+  }
+
+  render() {
+    const { disabled, ID } = this.props
+    const { loading } = this.state
+
+    return (
+      <>
+        <Button className="print-background header-btn" loading={loading} disabled={disabled} onClick={this.trigger}>鎵撳嵃</Button>
+        {loading ? <div id={ID} className="mk-voucher-print-wrap">
+          {this.getContent()}
+        </div> : null}
+      </>
+    )
+  }
+}
+
+export default printVoucher
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/printVoucher/index.scss b/src/tabviews/custom/components/module/voucher/printVoucher/index.scss
new file mode 100644
index 0000000..4ad7c24
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/printVoucher/index.scss
@@ -0,0 +1,126 @@
+.mk-voucher-print-wrap {
+  position: absolute;
+  width: 0;
+  height: 0;
+  overflow: hidden;
+}
+
+.mk-voucher-print-pdf-wrap {
+  width: 1200px;
+  padding: 80px;
+  color: #000000;
+  background: #ffffff;
+  .print-header {
+    .line {
+      display: flex;
+      margin-bottom: 10px;
+
+      div {
+        flex: 1;
+        width: 33.33%;
+        min-height: 5px;
+      }
+      .center {
+        text-align: center;
+      }
+      .right {
+        text-align: right;
+      }
+    }
+    .line:first-child {
+      .center {
+        font-size: 24px;
+      }
+      .right {
+        padding-top: 15px;
+      }
+    }
+  }
+  .print-footer {
+    display: flex;
+
+    div {
+      flex: 1;
+      width: 20%;
+    }
+  }
+  .print-body {
+    position: relative;
+    border: 1px solid #000000;
+    margin: 20px 0px;
+
+    .print-line {
+      position: relative;
+      height: 60px;
+      .remark {
+        display: inline-block;
+        width: 25%;
+        padding: 0 3px;
+      }
+      .subject {
+        display: inline-block;
+        width: 35%;
+        padding: 0 3px;
+      }
+      .credit {
+        display: inline-block;
+        width: 20%;
+        line-height: 60px;
+        text-align: right;
+        padding: 0 3px;
+      }
+
+      .remark::after {
+        content: '';
+        position: absolute;
+        width: 0px;
+        height: 60px;
+        left: 25%;
+        top: 0;
+        border-right: 1px solid #000000;
+      }
+    }
+    .print-line:first-child {
+      > div {
+        text-align: center;
+      }
+    }
+    .print-line:last-child {
+      .remark {
+        width: 60%;
+      }
+      .remark::after {
+        display: none;
+      }
+    }
+    .print-line:not(:last-child)::after {
+      // border: 1px solid #000000;
+      content: '';
+      position: absolute;
+      width: 100%;
+      height: 0px;
+      left: 0;
+      bottom: 0;
+      border-bottom: 1px solid #000000;
+    }
+  }
+
+  .print-body::before {
+    content: '';
+    position: absolute;
+    width: 0px;
+    height: 100%;
+    left: 60%;
+    top: 0;
+    border-right: 1px solid #000000;
+  }
+  .print-body:after {
+    content: '';
+    position: absolute;
+    width: 0px;
+    height: 100%;
+    left: 80%;
+    top: 0;
+    border-right: 1px solid #000000;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.jsx b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.jsx
new file mode 100644
index 0000000..627a699
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.jsx
@@ -0,0 +1,266 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import moment from 'moment'
+import { Upload, Button, Progress, notification } from 'antd'
+import { UploadOutlined } from '@ant-design/icons'
+import SparkMD5 from 'spark-md5'
+import Api from '@/api'
+import './index.scss'
+
+class FileUpload extends Component {
+  static propTpyes = {
+    config: PropTypes.object,  // 琛ㄥ崟淇℃伅
+    onChange: PropTypes.func,  // 琛ㄥ崟鍙樺寲
+  }
+
+  state = {
+    percent: 0,
+    accept: '',
+    accepts: null,
+    maxFile: null,
+    showprogress: false,
+    maxSize: 0,
+    filelist: []
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    let filelist = []
+    let accept = ''
+    let accepts = null
+
+    this.setState({
+      accept,
+      accepts,
+      filelist,
+      maxSize: config.maxSize || 0,
+      maxFile: config.maxfile
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  onChange = ({ fileList }) => {
+    fileList = fileList.map(item => {
+      if (item.status === 'error' && /^<!DOCTYPE html>/.test(item.response)) {
+        item.response = ''
+      }
+      return item
+    })
+
+    this.setState({filelist: fileList})
+  }
+
+  onRemove = file => {
+    this.setState({filelist: []})
+
+    this.props.onChange('')
+  }
+
+  onUpdate = (url, name) => {
+    let filelist = fromJS(this.state.filelist).toJS()
+
+    if (filelist[0] && url) {
+      filelist[0].status = 'done'
+      filelist[0].response = url
+    }
+
+    this.setState({filelist})
+    this.props.onChange(url, name)
+  }
+
+  onFail = (msg) => {
+    let filelist = this.state.filelist.map(item => {
+      if (!item.url && !item.response && !item.status) {
+        item.status = 'error'
+      }
+      return item
+    })
+
+    this.setState({filelist, showprogress: false, percent: 0})
+
+    notification.warning({
+      top: 92,
+      message: msg || '鏂囦欢涓婁紶澶辫触锛�',
+      duration: 5
+    })
+  }
+
+  shardupload = (param, name) => {
+    let form = new FormData()
+
+    form.append('file', param.binary)
+    form.append('fileMd5', param.fileMd5)
+    form.append('shardingMd5', param.fileMd5)
+    form.append('baseDomain', window.GLOB.baseurl)
+    form.append('rootPath', 'Content/images/upload/')
+    form.append('fileName', param.fileName)
+    form.append('fileExt', param.fileType)
+    form.append('shardingCnt', 1)
+    form.append('shardingNo', 1)
+    form.append('LoginUID', sessionStorage.getItem('LoginUID') || '')
+    form.append('UserID', sessionStorage.getItem('UserID') || '')
+
+    Api.getLargeFileUpload(form).then(res => {
+      if (res.status) {
+        if (res.urlPath) {
+          this.onUpdate(res.urlPath, name)
+        } else {
+          this.onFail()
+        }
+        this.setState({
+          percent: 100
+        }, () => {
+          setTimeout(() => {
+            this.setState({
+              showprogress: false,
+              percent: 0
+            })
+          }, 200)
+        })
+      } else {
+        this.onFail(res.message)
+      }
+    })
+  }
+
+  getuuid = () => {
+    let uuid = []
+    let _options = '0123456789abcdefghigklmnopqrstuv'
+    for (let i = 0; i < 19; i++) {
+      uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
+    }
+    uuid = uuid.join('')
+    return uuid
+  }
+
+  beforeUpload = (file) => {
+    const { accepts, maxSize } = this.state
+
+    if (accepts && file.name) {
+      let pass = false
+      accepts.forEach(type => {
+        if (new RegExp(type + '$', 'ig').test(file.name)) {
+          pass = true
+        }
+      })
+      
+      if (!pass) {
+        setTimeout(() => {
+          this.onFail('鏂囦欢鏍煎紡閿欒锛�')
+        }, 10)
+        return false
+      }
+    }
+    if (maxSize) {
+      let fileSize = file.size / 1024 / 1024
+
+      if (fileSize > maxSize) {
+        setTimeout(() => {
+          this.onFail(`鏂囦欢澶у皬涓嶅彲瓒呰繃${maxSize}M`)
+        }, 10)
+        return false
+      }
+    }
+
+    this.setState({
+      showprogress: true,
+      percent: 0
+    })
+
+    // 鍏煎鎬х殑澶勭悊
+    let spark = new SparkMD5.ArrayBuffer()         // 瀵筧rrayBuffer鏁版嵁杩涜md5鍔犲瘑锛屼骇鐢熶竴涓猰d5瀛楃涓�
+    let totalFileReader = new FileReader()         // 鐢ㄤ簬璁$畻鍑烘�绘枃浠剁殑fileMd5
+    let param = {}
+
+    param.fileName = file.name.replace(/\.{1}[^.]*$/ig, '')  // 鏂囦欢鍚嶏紙鍘婚櫎鍚庣紑鍚嶏級
+    param.fileType = file.name.replace(/^.*\.{1}/ig, '')     // 鏂囦欢绫诲瀷
+
+    if (!/^[A-Za-z0-9]+$/.test(param.fileName)) {            // 鏂囦欢鍚嶇О鍚湁鑻辨枃鍙婃暟瀛椾箣澶栧瓧绗︽椂锛屽悕绉扮郴缁熺敓鎴�
+      param.fileName = moment().format('YYYYMMDDHHmmss') + this.getuuid()
+    }
+
+    totalFileReader.readAsArrayBuffer(file)
+    totalFileReader.onload = (e) => {   // 瀵规暣涓猼otalFile鐢熸垚md5
+      spark.append(e.target.result)
+      param.fileMd5 = spark.end()       // 璁$畻鏁翠釜鏂囦欢鐨刦ileMd5
+      param.binary = file
+
+      let _param = new FormData()
+      _param.append('fileMd5', param.fileMd5)
+      
+      Api.getFilePreUpload(_param).then(res => {
+        if (res.status && res.urlPath) {
+          this.onUpdate(res.urlPath, file.name)
+          this.setState({
+            percent: 100
+          }, () => {
+            setTimeout(() => {
+              this.setState({
+                showprogress: false,
+                percent: 0
+              })
+            }, 200)
+          })
+        } else {
+          this.shardupload(param, file.name)
+        }
+      })
+    }
+
+    totalFileReader.onerror = () => {
+      this.onFail('鏂囦欢璇诲彇澶辫触锛�')
+    }
+
+    return false
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { showprogress, percent, filelist, accept } = this.state
+
+    let uploadable = 'attach-form-container '
+
+    if (filelist.length >= 1) {
+      uploadable += 'limit-fileupload'
+    }
+
+    const props = {
+      name: 'file',
+      disabled: showprogress,
+      listType: 'text',
+      fileList: filelist,
+      action: null,
+      accept: accept,
+      method: 'post',
+      multiple: false,
+      onChange: this.onChange,
+      onRemove: this.onRemove,
+      beforeUpload: this.beforeUpload,
+      className: uploadable
+    }
+
+    return (
+      <Upload {...props}>
+        <Button>
+          <UploadOutlined /> 鐐瑰嚮涓婁紶
+        </Button>
+        {showprogress ? <Progress percent={percent} size="small" /> : null}
+      </Upload>
+    )
+  }
+}
+
+export default FileUpload
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.scss b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.scss
new file mode 100644
index 0000000..c49de9f
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/fileupload/index.scss
@@ -0,0 +1,29 @@
+.attach-form-container {
+  .ant-progress-small.ant-progress-line {
+    position: absolute;
+    bottom: -20px;
+    left: 0px;
+  }
+  a[href^="data"] {
+    pointer-events: none;
+    .anticon-eye-o {
+      display: none;
+    }
+  }
+}
+.attach-form-container.limit-fileupload {
+  > .ant-upload {
+    display: inline;
+    >.ant-upload {
+      >input {
+        display: none;
+      }
+      >button {
+        display: none;
+      }
+    }
+  }
+  > .ant-upload-select-picture-card {
+    display: none;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx
new file mode 100644
index 0000000..a47a6e2
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/addAttach/index.jsx
@@ -0,0 +1,160 @@
+import React, {Component} from 'react'
+import { Form, Input, Select, Radio, Col } from 'antd'
+
+import MKFileUpload from './fileupload'
+
+const { TextArea } = Input
+
+class AddAttach extends Component {
+  state = {
+    f_method: 'upload',
+  }
+
+  handleConfirm = () => {
+    const { files } = this.props
+
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (err) return
+
+        files.forEach(item => {
+          if (item.data_code === values.data_code) {
+            values.data_name = item.data_name
+            values.BID = item.id
+          }
+        })
+
+        if (values.f_method === 'input') {
+          values.url = values.fileurl
+        }
+
+        resolve(values)
+      })
+    })
+  }
+
+  fileChange = (val, name) => {
+    if (name) {
+      this.props.form.setFieldsValue({attachments_title: name})
+    }
+  }
+
+  render() {
+    const { files } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { f_method } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} onKeyDown={this.onEnterSubmit}>
+        <Col span={12}>
+          <Form.Item label="鏂囦欢澶�">
+            {getFieldDecorator('data_code', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇烽�夋嫨鏂囦欢澶癸紒'
+                }
+              ]
+            })(<Select>
+              {files.map(option =>
+                <Select.Option key={option.id} value={option.data_code}>{option.data_name}</Select.Option>
+              )}
+            </Select>)}
+          </Form.Item>
+        </Col>
+        <Col span={12}>
+          <Form.Item label="娣诲姞鏂瑰紡">
+            {getFieldDecorator('f_method', {
+              initialValue: 'upload',
+              rules: [
+                {
+                  required: true,
+                  message: '璇烽�夋嫨娣诲姞鏂瑰紡锛�'
+                }
+              ]
+            })(<Radio.Group onChange={(e) => this.setState({f_method: e.target.value})}>
+                <Radio value="upload">涓婁紶</Radio>
+                <Radio value="input">杈撳叆</Radio>
+              </Radio.Group>)}
+          </Form.Item>
+        </Col>
+        {f_method === 'upload' ? <Col span={12}>
+          <Form.Item label="鏂囦欢">
+            {getFieldDecorator('url', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇锋坊鍔犳枃浠讹紒'
+                }
+              ]
+            })(<MKFileUpload config={{
+                initval: '',
+                compress: 'false',
+                suffix: '',
+                maxfile: 1,
+                fileType: 'text'
+              }} onChange={(val, name) => this.fileChange(val, name)} />)}
+          </Form.Item>
+        </Col> : <Col span={24}>
+          <Form.Item label="鏂囦欢鍦板潃">
+            {getFieldDecorator('fileurl', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ枃浠跺湴鍧�锛�'
+                }
+              ]
+            })(<TextArea autoSize={{ minRows: 2 }}/>)}
+          </Form.Item>
+        </Col>}
+        <Col span={12}>
+          <Form.Item label="鏂囦欢鍚�">
+            {getFieldDecorator('attachments_title', {
+              initialValue: '',
+              rules: [
+                {
+                  required: true,
+                  message: '璇疯緭鍏ユ枃浠跺悕锛�'
+                },
+                {
+                  max: 50,
+                  message: '鏈�澶ч暱搴︿负50浣嶏紒'
+                }
+              ]
+            })(<Input />)}
+          </Form.Item>
+        </Col>
+        <Col span={24}>
+          <Form.Item label="澶囨敞">
+            {getFieldDecorator('remark', {
+              initialValue: '',
+              rules: [
+                {
+                  max: 512,
+                  message: '鏈�澶ч暱搴︿负512浣嶏紒'
+                }
+              ]
+            })(<TextArea autoSize={{ minRows: 2 }}/>)}
+          </Form.Item>
+        </Col>
+        <div style={{clear: 'both'}}></div>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(AddAttach)
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx b/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx
new file mode 100644
index 0000000..ea36b1c
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.jsx
@@ -0,0 +1,120 @@
+import React, {Component} from 'react'
+
+class Documents extends Component {
+  state = {
+    selectKey: [],
+    actFolder: null
+  }
+
+  UNSAFE_componentWillMount() {
+    const { documents } = this.props
+
+    let actFolder = documents[0] || null
+
+    this.setState({selectKey: [], actFolder: actFolder})
+  }
+
+  submit = () => {
+    const { selectKey, actFolder } = this.state
+
+    let items = []
+
+    if (actFolder && selectKey.length > 0) {
+      actFolder.attachments.forEach(doc => {
+        if (selectKey.includes(doc.id)) {
+          items.push(doc)
+        }
+      })
+    }
+
+    this.props.onChange(items)
+  }
+
+  checkfolder = (id) => {
+    const { documents } = this.props
+    const { actFolder } = this.state
+
+    if (!actFolder || actFolder.id === id) return
+
+    let _actFolder = null
+    documents.forEach(item => {
+      if (item.id === id) {
+        _actFolder = item
+      }
+    })
+
+    this.setState({actFolder: _actFolder, selectKey: []}, () => {
+      this.submit()
+    })
+  }
+
+  checkItem = (id) => {
+    const { selectKey } = this.state
+
+    if (selectKey.includes(id)) {
+      this.setState({selectKey: selectKey.filter(key => key !== id)}, () => {
+        this.submit()
+      })
+    } else {
+      this.setState({selectKey: [...selectKey, id]}, () => {
+        this.submit()
+      })
+    }
+  }
+
+  checkAllItem = () => {
+    const { selectKey, actFolder } = this.state
+
+    if (!actFolder || actFolder.attachments.length === 0) return
+
+    if (selectKey.length === actFolder.attachments.length) {
+      this.setState({selectKey: []}, () => {
+        this.submit()
+      })
+    } else {
+      this.setState({selectKey: actFolder.attachments.map(item => item.id)}, () => {
+        this.submit()
+      })
+    }
+  }
+
+  render() {
+    const { documents } = this.props
+    const { selectKey, actFolder } = this.state
+
+    let checkAll = ''
+    if (actFolder && selectKey.length > 0) {
+      checkAll = selectKey.length < actFolder.attachments.length ? ' half' : ' active'
+    } else if (!actFolder || actFolder.attachments.length === 0) {
+      checkAll = ' disabled'
+    }
+
+    return (
+      <div className="document-wrap">
+        <div className="document-title">
+          <div className="folder-box">鏂囦欢澶�</div>
+          <div className="folder">
+            <span onClick={this.checkAllItem} className={'square-select' + checkAll}></span>
+            <span>鏂囦欢</span>
+          </div>
+        </div>
+        <div className="document-body">
+          <div className="doc-name">
+            {documents.map(folder => (<div className={actFolder.id === folder.id ? 'active' : ''} onClick={() => this.checkfolder(folder.id)} key={folder.id}>{folder.data_name}</div>))}
+          </div>
+          <div className="file-wrap">
+            {actFolder && actFolder.attachments.map(doc => {
+              return <div className="file-item" key={doc.id}>
+                <span onClick={() => this.checkItem(doc.id)} className={'square-select' + (selectKey.indexOf(doc.id) > -1 ? ' active' : '')}></span>
+                <img src={doc.icon} alt=""/>
+                <span className="file-name">{doc.attachments_title}</span>
+              </div>
+            })}
+          </div>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default Documents
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.scss b/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/documents/index.scss
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx b/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
new file mode 100644
index 0000000..fcbcb81
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/index.jsx
@@ -0,0 +1,297 @@
+import React, {Component} from 'react'
+import { fromJS } from 'immutable'
+import { Button, Modal, notification, Spin } from 'antd'
+import moment from 'moment'
+import { DeleteOutlined } from '@ant-design/icons'
+// import md5 from 'md5'
+
+import Api from '@/api'
+import AddAttach from './addAttach'
+import Documents from './documents'
+import './index.scss'
+
+import wordImg from '@/assets/img/file-word-fill.png'
+import excelImg from '@/assets/img/file-excel-fill.png'
+import fileImg from '@/assets/img/file-fill.png'
+import pdfImg from '@/assets/img/file-pdf-fill.png'
+import pptImg from '@/assets/img/file-ppt-fill.png'
+import picImg from '@/assets/img/picture-fill.png'
+import rarImg from '@/assets/img/rar.png'
+
+class ResetAttach extends Component {
+  state = {
+    visible: false,
+    upVisible: false,
+    docVisible: false,
+    files: [],
+    list: [],
+    documents: [],
+    selectDocs: [],
+    loading: false
+  }
+
+  submit = () => {
+    this.setState({visible: false})
+    this.props.onChange(this.state.list)
+  }
+
+  trigger = () => {
+    const { voucherCode, orgcode } = this.props
+    let list = fromJS(this.props.attachlist).toJS()
+
+    list = list.map(item => {
+      item.icon = this.getIcon(item.attachments_url)
+      return item
+    })
+
+    this.setState({visible: true, loading: true, list: list, files: [], documents: []})
+
+    let param = {
+      func: 's_get_fcc_voucher_attachments',
+      voucher_code: voucherCode || '',
+      orgcode: orgcode
+    }
+
+    Api.genericInterface(param).then(result => {
+      this.setState({loading: false})
+
+      if (!result.status) {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return
+      }
+
+      if (result.fcc_files) {
+        let files = []
+        let documents = []
+
+        result.fcc_files.forEach(file => {
+          files.push({data_code: file.data_code, data_name: file.data_name, id: file.id})
+
+          file.attachments = file.attachments.map(item => {
+            item.id = item.attach_id
+            item.icon = this.getIcon(item.attachments_url)
+            item.data_code = file.data_code
+            item.data_name = file.data_name
+            item.BID = file.id
+
+            return item
+          })
+
+          documents.push(file)
+        })
+
+        this.setState({files, documents})
+      }
+    })
+  }
+
+  upSubmit = () => {
+    const { config, orgcode } = this.props
+
+    if (!orgcode) {
+      notification.warning({
+        top: 92,
+        message: '鍏徃缂栫爜涓嶅彲涓虹┖锛�',
+        duration: 5
+      })
+      return
+    }
+
+    let ID = (() => {
+      let uuid = []
+      let options = '0123456789abcdefghigklmnopqrstuv'
+      for (let i = 0; i < 19; i++) {
+        uuid.push(options.substr(Math.floor(Math.random() * 0x20), 1))
+      }
+      uuid = moment().format('YYYYMMDDHHmmssSSS') + uuid.join('')
+      return uuid.toUpperCase()
+    })()
+
+    this.formRef.handleConfirm().then(res => {
+      let param = {
+        func: 's_fcc_voucher_attachments_addupt',
+        data_code: res.data_code,
+        data_name: res.data_name,
+        id: ID,
+        orgcode: orgcode,
+        voucher_at_lp: '',
+        attachments_title: res.attachments_title,
+        f_method: res.f_method,
+        attachments_url: res.url,
+        remark: res.remark,
+        status: config.wrap.attachStatus !== 10 ? 0 : 10,
+        statusname: config.wrap.attachStatus !== 10 ? '寰呭鏍�' : '宸插鏍�',
+        typename: config.name,
+        UserName: sessionStorage.getItem('User_Name') || '',
+        FullName: sessionStorage.getItem('Full_Name') || '',
+        BID: res.BID
+      }
+
+      Api.genericInterface(param).then(result => {
+        if (!result.status) {
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+          return
+        }
+
+        let list = fromJS(this.state.list).toJS()
+        let item = {
+          id: ID,
+          data_code: res.data_code,
+          data_name: res.data_name,
+          attachments_title: res.attachments_title,
+          attachments_url: res.url,
+          BID: res.BID
+        }
+
+        item.icon = this.getIcon(res.url)
+
+        list.push(item)
+
+        this.setState({list: list, upVisible: false})
+      })
+    })
+  }
+
+  deleteFile = (id) => {
+    this.setState({list: this.state.list.filter(item => item.id !== id)})
+  }
+
+  getIcon = (url) => {
+    let type = 'file'
+
+    if (/(.png|.jpg|.gif|.jpeg)$/i.test(url)) {
+      type = 'pic'
+    } else if (/(.doc|.docx)$/i.test(url)) {
+      type = 'word'
+    } else if (/(.xls|.xlsx)$/i.test(url)) {
+      type = 'excel'
+    } else if (/(.zip|.rar)$/i.test(url)) {
+      type = 'rar'
+    } else if (/.pdf$/i.test(url)) {
+      type = 'pdf'
+    } else if (/.pptx$/i.test(url)) {
+      type = 'ppt'
+    }
+
+    let icon = fileImg
+    if (type === 'excel') {
+      icon = excelImg
+    } else if (type === 'word') {
+      icon = wordImg
+    } else if (type === 'pdf') {
+      icon = pdfImg
+    } else if (type === 'pic') {
+      icon = picImg
+    } else if (type === 'ppt') {
+      icon = pptImg
+    } else if (type === 'rar') {
+      icon = rarImg
+    }
+
+    return icon
+  }
+
+  docSubmit = () => {
+    const { selectDocs, list } = this.state
+
+    
+    if (selectDocs.length > 0 && list.length > 0) {
+      let _list = fromJS(list).toJS()
+      let err = ''
+      let ids = list.map(item => item.id)
+
+      selectDocs.forEach(item => {
+        if (!ids.includes(item.id)) {
+          _list.push(item)
+        } else {
+          err += (err ? '銆�' : '') + item.attachments_title
+        }
+      })
+
+      this.setState({list: _list, docVisible: false})
+
+      if (err) {
+        notification.warning({
+          top: 92,
+          message: '鏂囦欢' + err + '宸叉坊鍔犮��',
+          duration: 5
+        })
+      }
+    } else {
+      this.setState({list: [...list, ...selectDocs], docVisible: false})
+    }
+  }
+
+  render() {
+    const { visible, upVisible, docVisible, files, list, documents, loading } = this.state
+
+    return (
+      <>
+        <Button type="link" onClick={this.trigger}>闄勪欢</Button>
+        <Modal
+          title="娣诲姞闄勪欢"
+          wrapClassName="voucher-attach-wrap"
+          visible={visible}
+          width={700}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          cancelText=""
+          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>
+          <div className="attach-selected-list">
+            {list.map(item => {
+              return <div className="attach-item" key={item.id}>
+                <img src={item.icon} alt=""/>
+                <div className="attach-msg">
+                  <div>{item.attachments_title}</div>
+                  <div>{item.data_name ? item.data_name + ' / ' : ''}{item.attachments_url}</div>
+                </div>
+                <div>
+                  <DeleteOutlined onClick={() => this.deleteFile(item.id)}/>
+                </div>
+              </div>
+            })}
+          </div>
+        </Modal>
+        <Modal
+          title="娣诲姞闄勪欢"
+          wrapClassName="voucher-attach-add-wrap"
+          visible={upVisible}
+          width={700}
+          maskClosable={false}
+          onOk={this.upSubmit}
+          onCancel={() => { this.setState({ upVisible: false })}}
+          destroyOnClose
+        >
+          <AddAttach files={files} wrappedComponentRef={(inst) => this.formRef = inst} submit={this.upSubmit}/>
+        </Modal>
+        <Modal
+          title="鐢靛瓙妗f"
+          wrapClassName="voucher-attach-document-wrap"
+          visible={docVisible}
+          width={700}
+          maskClosable={false}
+          onOk={this.docSubmit}
+          onCancel={() => { this.setState({ docVisible: false, selectDocs: [] })}}
+          destroyOnClose
+        >
+          {docVisible ? <Documents documents={documents} onChange={(vals) => this.setState({selectDocs: vals})}/> : null}
+        </Modal>
+      </>
+    )
+  }
+}
+
+export default ResetAttach
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetAttach/index.scss b/src/tabviews/custom/components/module/voucher/resetAttach/index.scss
new file mode 100644
index 0000000..94b8bcf
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetAttach/index.scss
@@ -0,0 +1,235 @@
+.voucher-attach-wrap {
+  .ant-modal-body {
+    position: relative;
+    padding: 15px;
+    .ant-spin {
+      position: absolute;
+      top: 150px;
+      left: 350px;
+    }
+
+    .attach-type-btn {
+      border-width: 1px;
+      color: var(--mk-sys-color);
+      border-color: var(--mk-sys-color);
+      margin-right: 15px;
+    }
+
+    .attach-selected-list {
+      height: 300px;
+      overflow-y: auto;
+      border: 1px solid #d8d8d8;
+      margin-top: 10px;
+
+      .attach-item {
+        display: flex;
+        border-bottom: 1px solid #f1f1f1;
+        img {
+          width: 45px;
+          height: 45px;
+          padding: 9px;
+          margin-top: 5px;
+        }
+        .attach-msg {
+          flex: 1;
+          width: calc(100% - 95px);
+          padding: 5px 0px;
+          div {
+            color: #000000;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+          }
+        }
+        .attach-msg + div {
+          width: 50px;
+          line-height: 45px;
+          margin-top: 5px;
+          text-align: center;
+          font-size: 16px;
+          cursor: pointer;
+          color: orangered;
+        }
+      }
+    }
+    .attach-selected-list::-webkit-scrollbar {
+      width: 7px;
+    }
+    .attach-selected-list::-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);
+    }
+    .attach-selected-list::-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);
+    }
+  }
+}
+.voucher-attach-add-wrap {
+  .ant-form {
+    > .ant-col {
+      float: none;
+      display: inline-block;
+      vertical-align: top;
+    }
+    > .ant-col-24 {
+      .ant-form-item-label {
+        width: 12.5%;
+      }
+      .ant-form-item-control-wrapper {
+        width: 84%;
+      }
+    }
+  }
+}
+.voucher-attach-document-wrap {
+  .ant-modal-body {
+    padding: 15px;
+  }
+  .document-wrap {
+    .document-title {
+      display: flex;
+      background: #e8e8e8;
+      line-height: 38px;
+      border: 1px solid #d8d8d8;
+      border-bottom: none;
+      .folder-box {
+        width: 200px;
+        text-align: center;
+        border-right: 1px solid #d8d8d8;
+      }
+      .folder {
+        flex: 1;
+        .square-select {
+          top: 3px;
+          margin: 0 10px;
+        }
+      }
+    }
+    .document-body {
+      border: 1px solid #d8d8d8;
+      height: 300px;
+      display: flex;
+      .doc-name {
+        width: 200px;
+        text-align: center;
+        border-right: 1px solid #d8d8d8;
+        height: 100%;
+        overflow-y: auto;
+        div {
+          border-bottom: 1px solid #e8e8e8;
+          height: 40px;
+          line-height: 40px;
+        }
+        .active {
+          background: var(--mk-sys-color1);
+        }
+      }
+      .file-wrap {
+        flex: 1;
+        width: calc(100% - 200px);
+        height: 100%;
+        overflow-y: auto;
+        .file-item {
+          border-bottom: 1px solid #e8e8e8;
+          height: 40px;
+          line-height: 40px;
+
+          .square-select {
+            top: 4px;
+            margin: 0 10px;
+          }
+          img {
+            width: 20px;
+            height: 20px;
+            margin-top: -2px;
+            margin-right: 5px;
+          }
+          .file-name {
+            display: inline-block;
+            overflow: hidden;
+            text-overflow: ellipsis;
+            white-space: nowrap;
+            vertical-align: top;
+            width: calc(100% - 90px);
+          }
+        }
+      }
+    }
+
+    .doc-name::-webkit-scrollbar, .file-wrap::-webkit-scrollbar {
+      width: 7px;
+    }
+    .doc-name::-webkit-scrollbar-thumb, .file-wrap::-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);
+    }
+    .doc-name::-webkit-scrollbar-track, .file-wrap::-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);
+    }
+
+    .square-select {
+      position: relative;
+      display: inline-block;
+      width: 16px;
+      height: 16px;
+      border: 1px solid #cccccc;
+      box-sizing: content-box;
+      margin: auto;
+      margin-right: 5px;
+      background-color: #ffffff;
+      transition: border-color 0.2s;
+      cursor: pointer;
+    }
+
+    .square-select.active {
+      border-color: var(--mk-sys-color);
+      background: var(--mk-sys-color);
+    }
+    .square-select.half {
+      border-color: var(--mk-sys-color);
+    }
+    .square-select.disabled {
+      border-color: #e8e8e8;
+      background: #e8e8e8;
+      cursor: default;
+    }
+    .square-select.disabled::before {
+      border-color: #e8e8e8;
+    }
+    .square-select.half::before {
+      display: none;
+    }
+    .square-select.half::after {
+      position: absolute;
+      top: 4px;
+      left: 4px;
+      content: ' ';
+      display: block;
+      width: 8px;
+      height: 8px;
+      background: var(--mk-sys-color);
+    }
+
+    .square-select::before {
+      position: relative;
+      top: 1px;
+      left: 6px;
+      content: ' ';
+      display: block;
+      width: 5px;
+      height: 11px;
+      border-style: solid;
+      border-width: 0 2px 2px 0;
+      border-color: #ffffff;
+      transform: rotate(45deg);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx b/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx
new file mode 100644
index 0000000..a2a28b9
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetRemark/index.jsx
@@ -0,0 +1,62 @@
+import React, {Component} from 'react'
+import { Button, Modal, Input, notification } from 'antd'
+
+// import './index.scss'
+
+const { TextArea } = Input
+
+class ResetRemark extends Component {
+  state = {
+    visible: false,
+    remark: ''
+  }
+
+  submit = () => {
+    const { ID } = this.props
+
+    let node = document.getElementById(ID)
+    let val = node.value
+
+    if (val && val.length > 512) {
+      notification.warning({
+        top: 92,
+        message: '褰撳墠鍐呭瓒呴暱锛屽娉ㄦ渶澶�512涓瓧绗︺��',
+        duration: 5
+      })
+      return
+    }
+
+    this.setState({remark: '', visible: false})
+    this.props.onChange(val)
+  }
+
+  trigger = () => {
+    const { remark } = this.props
+
+    this.setState({visible: true, remark: remark})
+  }
+
+  render() {
+    const { ID } = this.props
+    const { visible, remark } = this.state
+
+    return (
+      <>
+        <Button type="link" onClick={this.trigger}>澶囨敞</Button>
+        <Modal
+          title="澶囨敞"
+          visible={visible}
+          width={700}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          destroyOnClose
+        >
+          <TextArea id={ID} defaultValue={remark} rows={6}/>
+        </Modal>
+      </>
+    )
+  }
+}
+
+export default ResetRemark
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/resetRemark/index.scss b/src/tabviews/custom/components/module/voucher/resetRemark/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/resetRemark/index.scss
diff --git a/src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx b/src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx
new file mode 100644
index 0000000..6c5c151
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/saveAsTemp/index.jsx
@@ -0,0 +1,122 @@
+import React, {Component} from 'react'
+import { Button, Modal, Form, Input, notification, Select, Divider } from 'antd'
+import { PlusOutlined } from '@ant-design/icons'
+
+import MKEmitter from '@/utils/events.js'
+// import './index.scss'
+
+const { Option } = Select
+
+class SaveAsTemp extends Component {
+  state = {
+    visible: false,
+    name: '',
+    typeChar: '',
+    typeName: '',
+    menu: null
+  }
+
+  UNSAFE_componentWillMount() {
+    let menuId = '16289973311406f3ko9nm8ehotdmu80o'
+    let menu = window.GLOB.mkThdMenus.filter(m => m.MenuID === menuId)[0]
+
+    if (menu) {
+      let newtab = {
+        ...menu,
+        param: {}
+      }
+
+      this.setState({menu: newtab})
+    }
+  }
+
+  submit = () => {
+    const { name, typeChar, typeName } = this.state
+
+    if (!typeChar) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨妯℃澘绫诲瀷锛�',
+        duration: 5
+      })
+      return
+    } else if (!name) {
+      notification.warning({
+        top: 92,
+        message: '璇峰~鍐欐ā鏉垮悕绉帮紒',
+        duration: 5
+      })
+      return
+    }
+
+    this.setState({visible: false})
+    this.props.onChange(name, typeChar, typeName)
+  }
+
+  triggerSave = () => {
+    this.setState({visible: true, name: '', typeChar: '', typeName: ''})
+  }
+
+  changeType = (val, option) => {
+    if (option && option.props) {
+      this.setState({typeChar: option.props.value, typeName: option.props.children})
+    }
+  }
+
+  addType = () => {
+    const { menu } = this.state
+
+    this.setState({visible: false})
+
+    MKEmitter.emit('modifyTabs', menu, true)
+  }
+
+  render() {
+    const { tempTypes } = this.props
+    const { visible, menu } = this.state
+
+    return (
+      <>
+        <Button onClick={() => this.triggerSave()}>淇濆瓨涓烘ā鏉�</Button>
+        <Modal
+          title="娣诲姞妯℃澘"
+          wrapClassName="mk-temp-add-modal"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          destroyOnClose
+        >
+          {visible ? <Form>
+            <Form.Item label="妯℃澘绫诲瀷">
+              {menu ? <Select placeholder="璇烽�夋嫨妯℃澘绫诲瀷" onChange={this.changeType} dropdownRender={menus => (
+                <div>
+                  {menus}
+                  <Divider style={{ margin: '4px 0' }} />
+                  <div className="mk-add-book" onMouseDown={this.addType}>
+                    <PlusOutlined /> 娣诲姞
+                  </div>
+                </div>
+              )}>
+                {tempTypes.map(item => (
+                  <Option key={item.data_code} value={item.data_code}>{item.data_name}</Option>
+                ))}
+              </Select> : <Select placeholder="璇烽�夋嫨妯℃澘绫诲瀷" onChange={this.changeType}>
+                {tempTypes.map(item => (
+                  <Option key={item.data_code} value={item.data_code}>{item.data_name}</Option>
+                ))}
+              </Select>}
+            </Form.Item>
+            <Form.Item label="妯℃澘鍚嶇О">
+              <Input onChange={(e) => this.setState({name: e.target.value})}/>
+            </Form.Item>
+            <div style={{clear: 'both'}}></div>
+          </Form> : null}
+        </Modal>
+      </>
+    )
+  }
+}
+
+export default SaveAsTemp
\ No newline at end of file
diff --git a/src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss b/src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tabviews/custom/components/module/voucher/saveAsTemp/index.scss
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
index b79fdd7..2acf108 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
@@ -1,13 +1,11 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Table, Modal, Input, InputNumber, notification, message, AutoComplete, Select } from 'antd'
+import { Table, Form, Input, InputNumber, notification, AutoComplete, Select, Popover, Button } from 'antd'
+import { PlusOutlined, CloseOutlined } from '@ant-design/icons'
 
-import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
-import zhCN from '@/locales/zh-CN/main.js'
-import enUS from '@/locales/en-US/main.js'
 import './index.scss'
 
 class BodyRow extends React.Component {
@@ -24,14 +22,142 @@
   }
 }
 
+class Accounting extends React.Component {
+  state = {
+    subAccounts: []
+  }
+
+  UNSAFE_componentWillMount() {
+    const { data, tableId } = this.props
+    let subAccounts = fromJS(data.supAccounts).toJS()
+    let msg = window.GLOB.CacheVoucher.get(tableId) || {}
+
+    subAccounts = subAccounts.map(item => {
+      if (msg[item.field]) {
+        item.options = msg[item.field]
+      } else if (msg.others) {
+        item.options = msg.others.filter(cell => cell.parentId === item.field)
+      } else {
+        item.options = []
+      }
+
+      return item
+    })
+
+    this.setState({subAccounts: subAccounts})
+  }
+
+  selectChange = (option, key) => {
+    this.setState({
+      subAccounts: fromJS(this.state.subAccounts).toJS().map(cell => {
+        if (key === cell.field) {
+          cell.value = option ? option.props.value : ''
+          cell.name = option ? option.props.name : ''
+        }
+        return cell
+      })
+    })
+  }
+
+  getFields() {
+    const { subAccounts } = this.state
+
+    const fields = []
+
+    subAccounts.forEach((item) => {
+      fields.push(
+        <Form.Item label={item.label} key={item.field}>
+          <Select
+            showSearch
+            allowClear
+            defaultValue={item.initval}
+            dropdownMatchSelectWidth={false}
+            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+            onChange={(val, option) => this.selectChange(option, item.field)}
+          >
+            {item.options.map((option, i) =>
+              <Select.Option key={i} name={option.label} value={option.value}>{option.label}</Select.Option>
+            )}
+          </Select>
+        </Form.Item>
+      )
+    })
+    
+    return fields
+  }
+
+  confirm = () => {
+    const { data } = this.props
+    const { subAccounts } = this.state
+
+    let empty = ''
+    subAccounts.forEach(item => {
+      if (!empty && !item.value) {
+        empty = item.label
+      }
+    })
+
+    if (empty) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨' + empty,
+        duration: 5
+      })
+    } else {
+      let line = fromJS(data).toJS()
+      let account = {}
+
+      subAccounts.forEach(item => {
+        if (item.field === 'supplier') {
+          account[item.field] = {suppliercode: item.value, suppliername: item.name}
+        } else if (item.field === 'customer') {
+          account[item.field] = {customercode: item.value, customername: item.name}
+        } else if (item.field === 'department') {
+          account[item.field] = {co_pro_code: item.value, co_pro_name: item.name}
+        } else if (item.field === 'project') {
+          account[item.field] = {projectcode: item.value, projectname: item.name}
+        } else if (item.field === 'inventory') {
+          account[item.field] = {productcode: item.value, productname: item.name}
+        } else if (item.field === 'employee') {
+          account[item.field] = {workercode: item.value, workername: item.name}
+        } else if (item.field === 'cash_flow') {
+          account[item.field] = {cash_flow_code: item.value, cash_flow_name: item.name}
+        } else {
+          account[item.field] = {sup_acc_code: item.value, sup_acc_name: item.name}
+        }
+      })
+      
+      line.supAccounts = line.supAccounts.map(item => {
+        if (account[item.field]) {
+          item = {...item, ...account[item.field]}
+        }
+        return item
+      })
+
+      this.props.confirm(line)
+    }
+  }
+
+  render() {
+    return <div>
+      {this.getFields()}
+      <div className="footer">
+        <Button onClick={this.props.cancel}>鍙栨秷</Button>
+        <Button onClick={this.confirm}>纭畾</Button>
+      </div>
+    </div>
+  }
+}
+
 class BodyCell extends React.Component {
   state = {
     editing: false,
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props.record), fromJS(nextProps.record)) ||
-      nextState.editing !== this.state.editing
+    visible: false,
+    counting: false,
+    priceing: false,
+    curring: false,
+    ratioing: false,
+    origining: false,
   }
 
   componentDidMount () {
@@ -62,23 +188,56 @@
 
     this.setState({editing: false})
 
-    if (value !== record[col.field]) {
-      let line = {...record, [col.field]: value}
+    let line = {...record}
+    line[col.field] = value
 
-      if (col.field === 'debtor') {
-        line.creditor = ''
-      } else {
-        line.debtor = ''
-      }
-
+    if (col.field === 'subject_voucher_text') {
       MKEmitter.emit('changeRecord', col.tableId, line)
+
+      setTimeout(() => {
+        let cl = {subject_voucher_text: 'subject_code', subject_code: 'debit', debit: 'credit'}
+        MKEmitter.emit('tdFocus', cl[col.uuid] + record.uuid)
+      }, 50)
+      return
     }
 
+    if (col.field === 'debit') {
+      line.credit = ''
+      if (isNaN(line.debit)) {
+        line.debit = ''
+      }
+    } else {
+      line.debit = ''
+      if (isNaN(line.credit)) {
+        line.credit = ''
+      }
+    }
+
+    if (line.count_type === 'Y' && line.fcc_count) {
+      if (line.debit) {
+        line.net_unitprice = Math.round(line.debit / line.fcc_count * 10000) / 10000
+      } else if (line.credit) {
+        line.net_unitprice = Math.round(line.credit / line.fcc_count * 10000) / 10000
+      }
+    }
+
+    if (line.foreign_currency_type === 'Y' && line.foreign_amount) {
+      if (line.debit) {
+        line.unitratio = Math.round(line.debit / line.foreign_amount * 100000) / 100000
+      } else if (line.credit) {
+        line.unitratio = Math.round(line.credit / line.foreign_amount * 100000) / 100000
+      }
+    }
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
     setTimeout(() => {
-      if (col.field === 'creditor') {
+      if (col.field === 'debit' && (line.debit || line.debit === 0)) {
+        MKEmitter.emit('nextLine', col, record)
+      } else if (col.field === 'credit') {
         MKEmitter.emit('nextLine', col, record)
       } else {
-        let cl = {remark: 'subjectscode', subjectscode: 'debtor', debtor: 'creditor'}
+        let cl = {subject_voucher_text: 'subject_code', subject_code: 'debit', debit: 'credit'}
         MKEmitter.emit('tdFocus', cl[col.uuid] + record.uuid)
       }
     }, 50)
@@ -89,12 +248,10 @@
 
     if (record.type === 'total') return
 
-    if (col.field === 'subjectscode') {
+    if (col.field === 'subject_code') {
       this.setState({editing: true}, () => {
-        try {
-          let node = document.getElementById(col.uuid + record.uuid)
-          node.click()
-        } catch(e) {}
+        let node = document.getElementById(col.uuid + record.uuid)
+        node && node.click()
       })
     } else {
       this.setState({editing: true, value: record[col.field]}, () => {
@@ -110,15 +267,40 @@
 
     this.setState({editing: false})
 
-    if (col.field === 'subjectscode') return
-
     if (value !== record[col.field]) {
       let line = {...record, [col.field]: value}
 
-      if (col.field === 'debtor') {
-        line.creditor = ''
+      if (col.field === 'subject_voucher_text') {
+        MKEmitter.emit('changeRecord', col.tableId, line)
+        return
+      }
+
+      if (col.field === 'debit') {
+        line.credit = ''
+        if (isNaN(line.debit)) {
+          line.debit = ''
+        }
       } else {
-        line.debtor = ''
+        line.debit = ''
+        if (isNaN(line.credit)) {
+          line.credit = ''
+        }
+      }
+
+      if (line.count_type === 'Y' && line.fcc_count) {
+        if (line.debit) {
+          line.net_unitprice = Math.round(line.debit / line.fcc_count * 10000) / 10000
+        } else if (line.credit) {
+          line.net_unitprice = Math.round(line.credit / line.fcc_count * 10000) / 10000
+        }
+      }
+
+      if (line.foreign_currency_type === 'Y' && line.foreign_amount) {
+        if (line.debit) {
+          line.unitratio = Math.round(line.debit / line.foreign_amount * 100000) / 100000
+        } else if (line.credit) {
+          line.unitratio = Math.round(line.credit / line.foreign_amount * 100000) / 100000
+        }
       }
 
       MKEmitter.emit('changeRecord', col.tableId, line)
@@ -135,36 +317,404 @@
     })
   }
 
+  plusLine = () => {
+    const { col, record } = this.props
+
+    MKEmitter.emit('plusLine', col.tableId, record)
+  }
+
+  delRecord = () => {
+    const { col, record } = this.props
+
+    MKEmitter.emit('delRecord', col.tableId, record)
+  }
+
+  onSelectBlur = () => {
+    const { visible } = this.state
+
+    if (visible) return
+
+    this.setState({editing: false})
+  }
+
   onSelectChange = (val, option) => {
     const { col, record } = this.props
 
-    this.setState({editing: false})
-
     let line = {...record, ...option.props.extra}
+
+    line.supAccounts = []
+
+    if (line.sup_accounting) {
+      let msg = window.GLOB.CacheVoucher.get(col.tableId) || {}
+      let names = msg.names || {}
+
+      line.supAccounts = line.sup_accounting.split(',').map(item => {
+        return {
+          uuid: Utils.getguid(),
+          sup_acc_type: item,
+          field: item,
+          label: names[item] || item,
+          initval: ''
+        }
+      })
+    }
+
+    if (line.foreign_currency_type === 'Y' && line.foreign_currency) {
+      let msg = window.GLOB.CacheVoucher.get(col.tableId)
+      let cur = msg ? msg.currency.filter(n => n.exratename === line.foreign_currency)[0] : null
+      if (cur) {
+        line = {...line, ...cur}
+      }
+
+      this.currencyChange(line)
+    }
 
     MKEmitter.emit('changeRecord', col.tableId, line)
 
+    if (line.sup_accounting) {
+      setTimeout(() => {
+        this.setState({visible: true})
+      }, 100)
+    } else if (line.count_type === 'Y') {
+      this.setState({counting: true, value: line.fcc_count || 0}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'count')
+        node && node.select()
+      })
+    } else if (line.foreign_currency_type === 'Y') {
+      this.setState({curring: true}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'currency')
+        node && node.click()
+      })
+    } else {
+      this.setState({editing: false, visible: false, counting: false, priceing: false})
+      setTimeout(() => {
+        MKEmitter.emit('tdFocus', 'debit' + record.uuid)
+      }, 50)
+    }
+  }
+
+  confirm = (res) => {
+    const { col } = this.props
+
+    MKEmitter.emit('changeRecord', col.tableId, fromJS(res).toJS())
+
+    this.setState({editing: false, visible: false})
+
+    if (res.count_type === 'Y') {
+      this.setState({counting: true, value: res.fcc_count || 0}, () => {
+        let node = document.getElementById(col.uuid + res.uuid + 'count')
+        node && node.select()
+      })
+    } else {
+      setTimeout(() => {
+        MKEmitter.emit('tdFocus', 'debit' + res.uuid)
+      }, 50)
+    }
+  }
+
+  cancel = () => {
+    const { col } = this.props
+    let record = fromJS(this.props.record).toJS()
+    record.balance_direction = ''
+    record.count_type = ''
+    record.foreign_currency_type = ''
+    record.mnemonic_code = ''
+    record.subject_code = ''
+    record.subject_name = ''
+    record.sup_accounting = ''
+    record.supAccounts = []
+
+    MKEmitter.emit('changeRecord', col.tableId, record)
+
+    this.setState({editing: false, visible: false})
+  }
+
+  editCount = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({counting: true, value: record.fcc_count || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'count')
+      node && node.select()
+    })
+  }
+
+  editPrice = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({priceing: true, value: record.net_unitprice || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'price')
+      node && node.select()
+    })
+  }
+
+  countPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.fcc_count = value || 0
+
+    if (isNaN(line.fcc_count)) {
+      line.fcc_count = 0
+    }
+
+    this.countChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({counting: false, priceing: true, value: line.net_unitprice || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'price')
+      node && node.select()
+    })
+  }
+
+  countBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({counting: false})
+
+    let line = {...record}
+    line.fcc_count = value || 0
+
+    if (isNaN(line.fcc_count)) {
+      line.fcc_count = 0
+    }
+
+    this.countChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  pricePress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.net_unitprice = value || 0
+
+    if (isNaN(line.net_unitprice)) {
+      line.net_unitprice = 0
+    }
+
+    this.countChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({priceing: false})
     setTimeout(() => {
-      MKEmitter.emit('tdFocus', 'debtor' + record.uuid)
+      MKEmitter.emit('tdFocus', 'debit' + record.uuid)
     }, 50)
   }
 
+  priceBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({priceing: false})
+
+    let line = {...record}
+    line.net_unitprice = value || 0
+
+    if (isNaN(line.net_unitprice)) {
+      line.net_unitprice = 0
+    }
+
+    this.countChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  editCurrency = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({curring: true}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'currency')
+      node && node.click()
+    })
+  }
+
+  onCurrSelectChange = (val, option) => {
+    const { col, record } = this.props
+
+    let line = {...record, ...option.props.extra}
+
+    this.currencyChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    if (line.exratename === 'CNY') {
+      this.setState({curring: false, origining: true, value: line.foreign_amount || 0}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'origin')
+        node && node.select()
+      })
+    } else {
+      this.setState({curring: false, ratioing: true, value: line.unitratio || 1}, () => {
+        let node = document.getElementById(col.uuid + record.uuid + 'ratio')
+        node && node.select()
+      })
+    }
+  }
+
+  editRatio = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({ratioing: true, value: record.unitratio || 1}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'ratio')
+      node && node.select()
+    })
+  }
+
+  ratioPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.unitratio = value || 1
+
+    if (isNaN(line.unitratio)) {
+      line.unitratio = 1
+    }
+
+    this.currencyChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({ratioing: false, origining: true, value: line.foreign_amount || 0}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'origin')
+        node && node.select()
+    })
+  }
+
+  ratioBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({ratioing: false})
+
+    let line = {...record}
+    line.unitratio = value || 1
+
+    if (isNaN(line.unitratio)) {
+      line.unitratio = 1
+    }
+
+    this.currencyChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  editOrigin = (e) => {
+    const { col, record } = this.props
+    e.stopPropagation()
+
+    this.setState({origining: true, value: record.foreign_amount || 1}, () => {
+      let node = document.getElementById(col.uuid + record.uuid + 'origin')
+      node && node.select()
+    })
+  }
+
+  originPress = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    let line = {...record}
+    line.foreign_amount = value || 0
+
+    if (isNaN(line.foreign_amount)) {
+      line.foreign_amount = 0
+    }
+
+    this.currencyChange(line)
+
+    MKEmitter.emit('changeRecord', col.tableId, line)
+
+    this.setState({origining: false})
+
+    setTimeout(() => {
+      MKEmitter.emit('tdFocus', 'debit' + record.uuid)
+    }, 50)
+  }
+
+  originBlur = () => {
+    const { col, record } = this.props
+    const { value } = this.state
+
+    this.setState({origining: false})
+
+    let line = {...record}
+    line.foreign_amount = value || 0
+
+    if (isNaN(line.foreign_amount)) {
+      line.foreign_amount = 0
+    }
+
+    this.currencyChange(line)
+    
+    MKEmitter.emit('changeRecord', col.tableId, line)
+  }
+
+  countChange = (line) => {
+    if (line.fcc_count && line.net_unitprice) {
+      if (line.credit) {
+        line.credit = Math.round(line.fcc_count * line.net_unitprice * 100) / 100
+      } else {
+        line.debit = Math.round(line.fcc_count * line.net_unitprice * 100) / 100
+      }
+
+      if (line.foreign_currency_type === 'Y' && line.foreign_amount) {
+        if (line.debit) {
+          line.unitratio = Math.round(line.debit / line.foreign_amount * 100000) / 100000
+        } else if (line.credit) {
+          line.unitratio = Math.round(line.credit / line.foreign_amount * 100000) / 100000
+        }
+      }
+    }
+  }
+
+  currencyChange = (line) => {
+    if (line.unitratio && line.foreign_amount) {
+      if (line.credit) {
+        line.credit = Math.round(line.unitratio * line.foreign_amount * 100) / 100
+      } else {
+        line.debit = Math.round(line.unitratio * line.foreign_amount * 100) / 100
+      }
+
+      if (line.count_type === 'Y' && line.fcc_count) {
+        if (line.debit) {
+          line.net_unitprice = Math.round(line.debit / line.fcc_count * 10000) / 10000
+        } else if (line.credit) {
+          line.net_unitprice = Math.round(line.credit / line.fcc_count * 10000) / 10000
+        }
+      }
+    }
+  }
+
   render() {
-    let { col, record, subjects, className } = this.props
-    const { editing } = this.state
+    let { col, record, className } = this.props
+    const { editing, visible, counting, priceing, curring, ratioing, origining } = this.state
 
     let children = null
     let colSpan = 1
+    let extra = null
 
-    if (col.field === 'remark') {
-      let val = record.remark || ''
+    if (col.field === 'subject_voucher_text') {
+      let val = record.subject_voucher_text || ''
 
       if (record.type === 'total') {
         children = <div className="content-wrap" style={{lineHeight: '60px'}}>鍚堣: {val}</div>
         colSpan = 2
       } else {
+        extra = <PlusOutlined onClick={this.plusLine}/>
+
         if (editing) {
-          let options = ['鐜伴噾', '鍙戠エ']
+          let options = localStorage.getItem(window.GLOB.host + '_voucher_extract')
+          options = options ? JSON.parse(options) : []
+
           children = <AutoComplete
             dataSource={options.map((cell, i) => <AutoComplete.Option value={cell} key={i}>
               {cell}
@@ -181,65 +731,218 @@
           children = <div className="content-wrap" onClick={this.focus}>{val}</div>
         }
       }
-    } else if (col.field === 'subjectscode') {
+    } else if (col.field === 'subject_code') {
       if (record.type === 'total') {
         colSpan = 0
       } else {
         if (editing) {
-          children = <Select
-            showSearch
-            defaultValue={record.subjectscode || ''}
-            dropdownClassName="edit-table-dropdown"
-            id={col.uuid + record.uuid}
-            onBlur={this.onBlur}
-            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-            onSelect={this.onSelectChange}
-          >
-            {subjects.map((item, i) => (<Select.Option key={i} extra={item} value={item.subjectscode}>{item.subjectscode + ' ' + item.subjectsname}</Select.Option>))}
-          </Select>
+          let msg = window.GLOB.CacheVoucher.get(col.tableId)
+          let subjects = msg ? msg.subjects : []
+
+          children = <>
+            <Select
+              showSearch
+              defaultValue={record.subject_code || ''}
+              dropdownClassName="edit-table-dropdown"
+              id={col.uuid + record.uuid}
+              onBlur={this.onSelectBlur}
+              filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+              onSelect={this.onSelectChange}
+            >
+              {subjects.map((item, i) => (<Select.Option key={i} extra={item} value={item.subject_code}>{item.subject_code + ' ' + item.subject_name}</Select.Option>))}
+            </Select>
+            <Popover overlayClassName="subject-pop-wrap" placement="bottom" title="" visible={visible} content={<Accounting confirm={this.confirm} cancel={this.cancel} tableId={col.tableId} data={record}/>}>
+              <span className="pop-anchor"></span>
+            </Popover>
+          </>
         } else {
           let val = ''
-          if (record.subjectscode) {
-            val = (record.subjectscode || '') + ' ' + (record.subjectsname || '')
-          }
-          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
-        }
-      }
-    } else if (col.field === 'debtor') {
-      let val = record.debtor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
+          if (record.subject_code) {
+            val = (record.subject_code || '') + ' ' + (record.subject_name || '')
 
+            if (record.sup_accounting && record.supAccounts) {
+              record.supAccounts.forEach(item => {
+                if (item.sup_acc_type === 'supplier') {
+                  val += item.suppliercode ? '_' + item.suppliercode + ' ' + item.suppliername : ''
+                } else if (item.sup_acc_type === 'customer') {
+                  val += item.customercode ? '_' + item.customercode + ' ' + item.customername : ''
+                } else if (item.sup_acc_type === 'department') {
+                  val += item.co_pro_code ? '_' + item.co_pro_code + ' ' + item.co_pro_name : ''
+                } else if (item.sup_acc_type === 'project') {
+                  val += item.projectcode ? '_' + item.projectcode + ' ' + item.projectname : ''
+                } else if (item.sup_acc_type === 'inventory') {
+                  val += item.productcode ? '_' + item.productcode + ' ' + item.productname : ''
+                } else if (item.sup_acc_type === 'employee') {
+                  val += item.workercode ? '_' + item.workercode + ' ' + item.workername : ''
+                } else if (item.sup_acc_type === 'cash_flow') {
+                  val += item.cash_flow_code ? '_' + item.cash_flow_code + ' ' + item.cash_flow_name : ''
+                } else if (item.sup_acc_code) {
+                  val += '_' + item.sup_acc_code + ' ' + item.sup_acc_name
+                }
+              })
+            }
+          }
+
+          let countNode = null
+          let currencyNode = null
+
+          if (record.count_type === 'Y') {
+            if (counting) {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>鏁伴噺锛�</span>
+                  <span><InputNumber precision={4} className="inner-input" id={col.uuid + record.uuid + 'count'} defaultValue={record.fcc_count || 0} onChange={(val) => this.onChange(val)} onPressEnter={this.countPress} onBlur={this.countBlur}/></span>
+                </span>
+                <span onClick={this.editPrice}>
+                  <span>鍗曚环锛�</span>
+                  <span>{record.net_unitprice || 0}</span>
+                </span>
+              </div>
+            } else if (priceing) {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCount}>
+                  <span>鏁伴噺锛�</span>
+                  <span>{record.fcc_count || 0}</span>
+                </span>
+                <span onClick={(e) => e.stopPropagation()}>
+                  <span>鍗曚环锛�</span>
+                  <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 {
+              countNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCount}>
+                  <span>鏁伴噺锛�</span>
+                  <span>{record.fcc_count || 0}</span>
+                </span>
+                <span onClick={this.editPrice}>
+                  <span>鍗曚环锛�</span>
+                  <span>{record.net_unitprice || 0}</span>
+                </span>
+              </div>
+            }
+          }
+
+          if (record.foreign_currency_type === 'Y') {
+            if (curring) {
+              let msg = window.GLOB.CacheVoucher.get(col.tableId)
+              let currency = msg ? msg.currency : []
+
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>璐у竵锛�</span>
+                  <span>
+                    <Select
+                      className="currency-select"
+                      defaultValue={record.exratename || ''}
+                      dropdownClassName="edit-table-dropdown"
+                      id={col.uuid + record.uuid + 'currency'}
+                      onBlur={() => this.setState({curring: false})}
+                      onSelect={this.onCurrSelectChange}
+                    >
+                      {currency.map((item, i) => (<Select.Option key={i} extra={item} value={item.exratename}>{item.exratename}</Select.Option>))}
+                    </Select>
+                  </span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.foreign_amount || 0}</span>
+                </span>
+              </div>
+            } else if (ratioing) {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={(e) => e.stopPropagation()}>
+                  <span>姹囩巼锛�</span>
+                  <span><InputNumber precision={5} className="inner-input" id={col.uuid + record.uuid + 'ratio'} defaultValue={record.unitratio || 1} onChange={(val) => this.onChange(val)} onPressEnter={this.ratioPress} onBlur={this.ratioBlur}/></span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.foreign_amount || 0}</span>
+                </span>
+              </div>
+            } else if (origining) {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={(e) => e.stopPropagation()}>
+                  <span>鍘熷竵锛�</span>
+                  <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 {
+              currencyNode = <div className="count-wrap">
+                <span style={{marginRight: '5px'}} onClick={this.editCurrency}>
+                  <span>璐у竵锛�</span>
+                  <span>{record.exratename || ''}</span>
+                </span>
+                <span style={{marginRight: '5px'}} onClick={this.editRatio}>
+                  <span>姹囩巼锛�</span>
+                  <span>{record.unitratio || 1}</span>
+                </span>
+                <span onClick={this.editOrigin}>
+                  <span>鍘熷竵锛�</span>
+                  <span>{record.foreign_amount || 0}</span>
+                </span>
+              </div>
+            }
+          }
+
+          children = <div className="content-wrap" onClick={this.focus}>
+            {val}
+            {countNode}
+            {currencyNode}
+          </div>
+        }
+      }
+    } else if (col.field === 'debit') {
       if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+        children = <InputNumber id={col.uuid + record.uuid} precision={2} defaultValue={record.debit} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
       } else {
+        let val = record.debit
+        let down = false
+        let vals = []
+        if (!isNaN(val) && val !== '') {
+          if (val < 0) {
+            down = true
+            val = Math.abs(val)
+          }
+          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>
       }
-    } else if (col.field === 'creditor') {
-      let val = record.creditor
-      let down = false
-      let vals = []
-      if (typeof(val) === 'number') {
-        if (val < 0) {
-          down = true
-          val = Math.abs(val)
-        }
-        vals = (val * 100).toFixed(0).split('').reverse()
-      }
+    } else if (col.field === 'credit') {
+      extra = <CloseOutlined onClick={this.delRecord}/>
 
       if (editing) {
-        children = <InputNumber id={col.uuid + record.uuid} defaultValue={val} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
+        children = <InputNumber id={col.uuid + record.uuid} precision={2} defaultValue={record.credit} onChange={(val) => this.onChange(val)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
       } else {
+        let val = record.credit
+        let down = false
+        let vals = []
+        if (!isNaN(val) && val !== '') {
+          if (val < 0) {
+            down = true
+            val = Math.abs(val)
+          }
+          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>
@@ -249,55 +952,47 @@
 
     if (!colSpan) return null
 
-    return (<td colSpan={colSpan} className={className}>{children}</td>)
+    return (<td colSpan={colSpan} className={className}>{children}{extra}</td>)
   }
 }
 
 class VoucherTable extends Component {
   static propTpyes = {
     config: PropTypes.object,        // 鑿滃崟Id
-    subjects: PropTypes.array,       // 浼氳绉戠洰
-    BID: PropTypes.any,              // 涓昏〃ID
     data: PropTypes.any,             // 琛ㄦ牸鏁版嵁
-    total: PropTypes.any,            // 鎬绘暟
     loading: PropTypes.bool,         // 琛ㄦ牸鍔犺浇涓�
-    refreshdata: PropTypes.func,     // 琛ㄦ牸涓帓搴忓垪銆侀〉鐮佺殑鍙樺寲鏃跺埛鏂�
+    onChange: PropTypes.func,        // 琛ㄦ牸鍙樺姩
   }
 
   state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     data: [],
     edData: [],
-    edColumns: [],
     tableId: '',          // 琛ㄦ牸ID
-    pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     columns: null,        // 鏄剧ず鍒�
-    loading: false,
   }
 
   UNSAFE_componentWillMount () {
-    const { config, subjects, data } = this.props
+    const { config, data } = this.props
 
     let columns = [
       {
         title: '鎽樿',
-        dataIndex: 'remark',
-        key: 'remark',
+        dataIndex: 'subject_voucher_text',
+        key: 'subject_voucher_text',
         width: '22%',
         onCell: record => ({
           record,
-          col: {uuid: 'remark', field: 'remark', tableId: config.uuid},
+          col: {uuid: 'subject_voucher_text', field: 'subject_voucher_text', tableId: config.uuid},
         })
       },
       {
         title: '浼氳绉戠洰',
-        dataIndex: 'subjectscode',
-        key: 'subjectscode',
+        dataIndex: 'subject_code',
+        key: 'subject_code',
         width: '34%',
         onCell: record => ({
           record,
-          subjects,
-          col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
+          col: {uuid: 'subject_code', field: 'subject_code', tableId: config.uuid},
         })
       },
       {
@@ -308,12 +1003,12 @@
             <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
           </div>
         </>),
-        dataIndex: 'debtor',
-        key: 'debtor',
+        dataIndex: 'debit',
+        key: 'debit',
         width: '22%',
         onCell: record => ({
           record,
-          col: {uuid: 'debtor', field: 'debtor', tableId: config.uuid},
+          col: {uuid: 'debit', field: 'debit', tableId: config.uuid},
         })
       },
       {
@@ -324,12 +1019,12 @@
             <span>鐧�</span> <span>鍗�</span> <span>鍏�</span> <span>瑙�</span> <span className="last">鍒�</span>
           </div>
         </>),
-        dataIndex: 'creditor',
-        key: 'creditor',
+        dataIndex: 'credit',
+        key: 'credit',
         width: '22%',
         onCell: record => ({
           record,
-          col: {uuid: 'creditor', field: 'creditor', tableId: config.uuid},
+          col: {uuid: 'credit', field: 'credit', tableId: config.uuid},
         })
       }
     ]
@@ -347,7 +1042,9 @@
 
   componentDidMount () {
     MKEmitter.addListener('nextLine', this.nextLine)
+    MKEmitter.addListener('plusLine', this.plusLine)
     MKEmitter.addListener('delRecord', this.delRecord)
+    MKEmitter.addListener('cleartable', this.cleartable)
     MKEmitter.addListener('changeRecord', this.changeRecord)
   }
 
@@ -359,40 +1056,24 @@
       return
     }
     MKEmitter.removeListener('nextLine', this.nextLine)
+    MKEmitter.removeListener('plusLine', this.plusLine)
     MKEmitter.removeListener('delRecord', this.delRecord)
+    MKEmitter.removeListener('cleartable', this.cleartable)
     MKEmitter.removeListener('changeRecord', this.changeRecord)
   }
 
   UNSAFE_componentWillReceiveProps(nextProps) {
     if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
       this.resetData(fromJS(nextProps.data).toJS())
-    } else if (!is(fromJS(this.props.subjects), fromJS(nextProps.subjects))) {
-      this.resetSubjects(nextProps.subjects)
     }
   }
 
-  resetSubjects = (subjects) => {
-    const { config } = this.props
-    let columns = fromJS(this.state.columns).toJS()
+  cleartable = (tbid) => {
+    const { tableId } = this.state
 
-    this.setState({
-      columns: columns.map(col => {
-        if (col.key === 'subjectscode') {
-          return {
-            title: '浼氳绉戠洰',
-            dataIndex: 'subjectscode',
-            key: 'subjectscode',
-            width: '34%',
-            onCell: record => ({
-              record,
-              subjects,
-              col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
-            })
-          }
-        }
-        return col
-      })
-    })
+    if (tbid !== tableId) return
+
+    this.resetData([])
   }
 
   resetData = (data) => {
@@ -400,13 +1081,17 @@
     data.push(this.getTotalLine(data))
 
     this.setState({
-      edData: data
+      edData: []
+    }, () => {
+      this.setState({
+        edData: data
+      })
     })
   }
 
   initData = (data) => {
     let _data = data.map((item, i) => {
-      item.uuid = Utils.getuuid()
+      // item.uuid = Utils.getguid()
       item.index = i
       
       return item
@@ -414,39 +1099,39 @@
 
     if (_data.length < 4) {
       for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+        _data.push({uuid: Utils.getguid(), index: i + 1, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''})
       }
     }
     return _data
   }
 
   getTotalLine = (data) => {
-    let totalLine = {uuid: Utils.getuuid(), type: 'total'}
-    let debtor = ''
-    let creditor = ''
+    let totalLine = {uuid: Utils.getguid(), type: 'total'}
+    let debit = ''
+    let credit = ''
 
     data.forEach(item => {
-      if (typeof(item.debtor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
+      if (!isNaN(item.debit) && item.debit !== '') {
+        if (debit === '') {
+          debit = 0
         }
 
-        debtor += item.debtor
-      } else if (typeof(item.creditor) === 'number') {
-        if (debtor === '') {
-          debtor = 0
+        debit += item.debit
+      } else if (!isNaN(item.credit) && item.credit !== '') {
+        if (debit === '') {
+          debit = 0
         }
-        if (creditor === '') {
-          creditor = 0
+        if (credit === '') {
+          credit = 0
         }
-        creditor += item.creditor
+        credit += item.credit
       }
     })
 
-    totalLine.debtor = debtor
-    totalLine.creditor = creditor
+    totalLine.debit = debit
+    totalLine.credit = credit
 
-    totalLine.remark = this.changeMoneyToChinese(debtor)
+    totalLine.subject_voucher_text = this.changeMoneyToChinese(debit)
     
     return totalLine
   }
@@ -540,30 +1225,36 @@
     if (col.tableId !== tableId) return
 
     if (record.index < edData.length - 2) {
-      MKEmitter.emit('tdFocus', 'remark' + edData[record.index + 1].uuid)
+      MKEmitter.emit('tdFocus', 'subject_voucher_text' + edData[record.index + 1].uuid)
     } else {
       let _data = fromJS(edData).toJS()
-      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''}
+      let line = {uuid: Utils.getguid(), index: _data.length - 1, subject_voucher_text: record.subject_voucher_text || '', subject_code: '', subject_name: '', debit: '', credit: ''}
 
       _data.splice(_data.length - 1, 0, line)
 
       this.setState({edData: _data}, () => {
-        MKEmitter.emit('tdFocus', 'remark' + line.uuid)
+        MKEmitter.emit('tdFocus', 'subject_voucher_text' + line.uuid)
       })
+      this.props.onChange(_data)
     }
   }
 
-  plusLine = (initEditLine) => {
-    const { edData } = this.state
+  plusLine = (tid, record) => {
+    const { edData, tableId } = this.state
 
-    let item = {...edData[edData.length - 1]}
+    if (tid !== tableId) return
 
-    item.key = item.key + 1
-    item.$$uuid = '$new'
+    let _data = fromJS(edData).toJS()
+    let line = {uuid: Utils.getguid(), index: 0, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''}
 
-    this.setState({edData: [...edData, item]}, () => {
-      MKEmitter.emit('tdFocus', initEditLine.uuid + item.uuid)
+    _data.splice(record.index, 0, line)
+    _data = _data.map((item, index) => {
+      item.index = index
+      return item
     })
+
+    this.setState({edData: _data})
+    this.props.onChange(_data)
   }
 
   delRecord = (id, record) => {
@@ -571,19 +1262,25 @@
 
     if (id !== tableId) return
 
-    let _data = edData.filter(item => item.uuid !== record.uuid)
+    let _data = fromJS(edData).toJS().filter(item => item.uuid !== record.uuid)
 
     _data.pop()
 
     if (_data.length < 4) {
-      for (let i = _data.length - 1; i < 4; i++) {
-        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+      for (let i = _data.length; i < 4; i++) {
+        _data.push({uuid: Utils.getguid(), index: 0, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''})
       }
     }
+
+    _data = _data.map((item, index) => {
+      item.index = index
+      return item
+    })
 
     _data.push(this.getTotalLine(_data))
 
     this.setState({edData: _data})
+    this.props.onChange(_data)
   }
 
   changeRecord = (tableId, record) => {
@@ -600,187 +1297,13 @@
     _data.pop()
 
     if (record.index === _data.length - 1) {
-      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
+      _data.push({uuid: Utils.getguid(), index: record.index + 1, subject_voucher_text: '', subject_code: '', subject_name: '', debit: '', credit: ''})
     }
 
     _data.push(this.getTotalLine(_data))
 
     this.setState({edData: _data})
-  }
-
-  addLine = () => {
-    const { BID } = this.props
-    const { edData } = this.state
-
-    let item = {}
-    if (edData.length > 0) {
-      item = {...edData[edData.length - 1]}
-      item.key = item.key + 1
-      item.$$uuid = '$new'
-    } else {
-      item.key = 0
-      item.$$uuid = '$new'
-      item.$$BID = BID || ''
-    }
-
-    this.setState({edData: [...edData, item]})
-  }
-
-  checkData = () => {
-    const { edData } = this.state
-
-    if (edData.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '鎻愪氦鏁版嵁涓嶅彲涓虹┖锛�',
-        duration: 5
-      })
-      return
-    }
-    let err = ''
-    let data = fromJS(edData).toJS().map(item => {
-      // let line = []
-      // fields.forEach(col => {
-      //   if (col.editable !== 'true' || item.$deleted) {
-      //     if (col.type === 'number') {
-      //       item[col.field] = +item[col.field]
-      //       if (isNaN(item[col.field])) {
-      //         item[col.field] = 0
-      //       }
-      //     } else {
-      //       item[col.field] = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     }
-      //     return
-      //   }
-      //   if (col.type === 'text') {
-      //     let val = item[col.field] !== undefined ? (item[col.field] + '') : ''
-      //     if (col.required === 'true' && !val) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //     }
-      //     item[col.field] = val
-      //   } else if (col.type === 'number') {
-      //     let val = item[col.field]
-      //     if (!val && val !== 0) {
-      //       line.push(`${col.label}涓嶅彲涓虹┖`)
-      //       return
-      //     }
-      //     val = +val
-      //     if (isNaN(val)) {
-      //       line.push(`${col.label}鏁版嵁鏍煎紡閿欒`)
-      //       return
-      //     }
-
-      //     val = +val.toFixed(col.decimal || 0)
-          
-      //     if (typeof(col.max) === 'number' && val > col.max) {
-      //       line.push(`${col.label}涓嶅彲澶т簬${col.max}`)
-      //     } else if (typeof(col.min) === 'number' && val < col.min) {
-      //       line.push(`${col.label}涓嶅彲灏忎簬${col.min}`)
-      //     }
-
-      //     item[col.field] = val
-      //   }
-      // })
-
-      return item
-    })
-
-    if (err) {
-      notification.warning({
-        top: 92,
-        message: err,
-        duration: 5
-      })
-    } else {
-      this.submit(data)
-    }
-  }
-
-  submit = (data) => {
-    const { BID } = this.props
-
-    let param = {
-      // excel_in: result.lines,
-      BID: BID || ''
-    }
-
-    this.setState({
-      loading: true
-    })
-
-    param.func = 'submit.innerFunc'
-
-    Api.genericInterface(param).then((res) => {
-      if (res.status) {
-        this.execSuccess(res)
-      } else {
-        this.execError(res)
-      }
-    }, () => {
-      this.execError({})
-    })
-  }
-
-  execSuccess = (res) => {
-    const { submit } = this.props
-
-    if (res && res.ErrCode === 'S') { // 鎵ц鎴愬姛
-      notification.success({
-        top: 92,
-        message: res.ErrMesg || this.state.dict['main.action.confirm.success'],
-        duration: submit.stime ? submit.stime : 2
-      })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
-      Modal.success({
-        title: res.ErrMesg || this.state.dict['main.action.confirm.success']
-      })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
-
-    }
-
-    this.setState({
-      loading: false
-    })
-
-    if (submit.closetab === 'true') {
-      MKEmitter.emit('popclose')
-    }
-    if (submit.execSuccess !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit)
-    }
-  }
-
-  execError = (res) => {
-    const { submit } = this.props
-
-    if (res.ErrCode === 'E') {
-      Modal.error({
-        title: res.message || res.ErrMesg,
-      })
-    } else if (res.ErrCode === 'N') {
-      notification.error({
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ntime ? submit.ntime : 10
-      })
-    } else if (res.ErrCode === 'F') {
-      notification.error({
-        className: 'notification-custom-error',
-        top: 92,
-        message: res.message || res.ErrMesg,
-        duration: submit.ftime ? submit.ftime : 10
-      })
-    } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
-    }
-    
-    this.setState({
-      loading: false
-    })
-
-    if (submit.execError !== 'never') {
-      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit)
-    }
+    this.props.onChange(_data)
   }
 
   render() {
@@ -801,7 +1324,7 @@
           columns={columns}
           dataSource={edData}
           bordered={true}
-          // loading={this.props.loading}
+          loading={this.props.loading}
           onRow={(record, index) => {
             return {
               data: record
diff --git a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
index 4d4702a..fa2baa2 100644
--- a/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
+++ b/src/tabviews/custom/components/module/voucher/voucherTable/index.scss
@@ -90,10 +90,30 @@
         vertical-align: top;
 
         .content-wrap {
-          padding: 5px;
+          padding: 0px 5px;
           height: 100%;
           font-size: 13px;
           font-weight: bold;
+
+          .count-wrap {
+            text-align: right;
+            height: 20px;
+          }
+          .currency-select {
+            height: 20px;
+            vertical-align: top;
+            .ant-select-selection--single {
+              height: 20px;
+            }
+            .ant-select-selection__rendered {
+              line-height: 20px;
+              margin-left: 8px;
+              margin-right: 22px;
+            }
+            .ant-select-arrow {
+              right: 6px;
+            }
+          }
         }
         .money-uint {
           height: 100%;
@@ -129,7 +149,7 @@
     border-radius: 0;
     resize: none;
   }
-  .ant-input-number {
+  .ant-input-number:not(.inner-input) {
     height: 60px;
     border-radius: 0;
     
@@ -141,7 +161,22 @@
       height: 60px;
     }
   }
-  .ant-select {
+  .ant-input-number.inner-input {
+    display: inline-block;
+    width: 50px;
+    border-radius: 0;
+    height: 20px;
+
+    .ant-input-number-handler-wrap {
+      display: none;
+    }
+    .ant-input-number-input {
+      border-radius: 0;
+      height: 18px;
+      padding: 0 3px;
+    }
+  }
+  .ant-select:not(.currency-select) {
     padding: 0px;
     position: absolute;
     top: 0px;
@@ -175,12 +210,12 @@
       bottom: 0px;
       border: 1px solid #1890ff;
     }
-    .anticon {
-      color: #ff4d4f;
-      position: absolute;
-      right: 3px;
-      top: calc(50% - 8px);
-    }
+    // .anticon {
+    //   color: #ff4d4f;
+    //   position: absolute;
+    //   right: 3px;
+    //   top: calc(50% - 8px);
+    // }
   }
   td.pointer {
     position: relative;
@@ -196,8 +231,93 @@
       right: 0;
     }
   }
-}
 
+  .anticon-plus {
+    position: absolute;
+    left: 0px;
+    height: 60px;
+    top: 0px;
+    line-height: 60px;
+    width: 25px;
+    color: #26C281;
+    cursor: pointer;
+    display: none;
+  }
+  .anticon-close {
+    position: absolute;
+    right: 0px;
+    height: 60px;
+    top: 0px;
+    line-height: 60px;
+    width: 25px;
+    color: #ff4d4f;
+    cursor: pointer;
+    display: none;
+  }
+  tr:hover {
+    .anticon-plus {
+      left: -25px;
+      display: inline-block;
+    }
+    .anticon-close {
+      right: -25px;
+      display: inline-block;
+    }
+  }
+  .pop-anchor {
+    position: absolute;
+    bottom: 0;
+    left: 50%;
+  }
+}
+.subject-pop-wrap {
+  padding-top: 0px;
+  .ant-popover-arrow {
+    display: none;
+  }
+  .ant-popover-content {
+    position: relative;
+    z-index: 1;
+  }
+
+  .ant-form-item {
+    display: flex;
+    margin-bottom: 15px;
+    width: 200px;
+
+    .ant-form-item-label {
+      width: 60px;
+    }
+    .ant-form-item-control-wrapper {
+      width: calc(100% - 60px);
+      .ant-select {
+        width: 100%;
+      }
+    }
+  }
+  .ant-popover-inner-content {
+    padding-right: 30px;
+  }
+  .footer {
+    text-align: right;
+    .ant-btn {
+      border: none;
+      box-shadow: none;
+      margin-right: 15px;
+    }
+    .ant-btn:last-child {
+      color: var(--mk-sys-color);
+    }
+  }
+}
+.subject-pop-wrap::before {
+  content: '';
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+}
 .edit-table-dropdown {
   .ant-select-dropdown-menu-item {
     white-space: unset;
diff --git a/src/tabviews/custom/components/share/normalTable/index.jsx b/src/tabviews/custom/components/share/normalTable/index.jsx
index 328ccb5..1926c23 100644
--- a/src/tabviews/custom/components/share/normalTable/index.jsx
+++ b/src/tabviews/custom/components/share/normalTable/index.jsx
@@ -936,7 +936,7 @@
 
   render() {
     const { setting, statFValue, lineMarks, data } = this.props
-    const { selectedRowKeys, activeIndex, pickup, tableId, pageOptions } = this.state
+    const { selectedRowKeys, activeIndex, pickup, tableId, pageOptions, columns } = this.state
 
     // 璁剧疆琛ㄦ牸閫夋嫨灞炴�э細鍗曢�夈�佸閫夈�佷笉鍙��
     let rowSelection = null
@@ -992,7 +992,7 @@
     }
 
     return (
-      <div className={`normal-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''}`} id={tableId}>
+      <div className={`normal-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length}`} id={tableId}>
         {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
           <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} /> : null
         }
@@ -1001,7 +1001,7 @@
           size={setting.size || 'middle'}
           bordered={setting.bordered !== 'false'}
           rowSelection={rowSelection}
-          columns={this.state.columns}
+          columns={columns}
           dataSource={_data}
           loading={loading}
           scroll={{ x: '100%', y: height }}
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index aebf282..f7bbac1 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -22,6 +22,7 @@
 const AntvScatter = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-scatter'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
+const DoubleDataCard = asyncComponent(() => import('@/tabviews/custom/components/card/double-data-card'))
 const EditTable = asyncComponent(() => import('@/tabviews/custom/components/table/edit-table'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const NormalGroup = asyncComponent(() => import('@/tabviews/custom/components/group/normal-group'))
@@ -204,6 +205,12 @@
             <NormalTable config={item} data={data} mainSearch={mainSearch}/>
           </Col>
         )
+      } else if (item.type === 'card' && item.subtype === 'dualdatacard') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <DoubleDataCard config={item} mainSearch={mainSearch}/>
+          </Col>
+        )
       } else if (item.type === 'bar' || item.type === 'line') {
         return (
           <Col span={item.width} style={style} key={item.uuid}>
diff --git a/src/tabviews/custom/components/table/base-table/index.jsx b/src/tabviews/custom/components/table/base-table/index.jsx
index f8f7454..80579fb 100644
--- a/src/tabviews/custom/components/table/base-table/index.jsx
+++ b/src/tabviews/custom/components/table/base-table/index.jsx
@@ -46,7 +46,6 @@
    */
   UNSAFE_componentWillMount () {
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
 
     let BID = ''
     let BData = ''
@@ -75,17 +74,6 @@
     } else {
       setting.orisel = true
     }
-
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
-    _config.cols.forEach(column => {
-      if (column.type === 'action') {
-        column.operations = column.elements
-      }
-    })
 
     _config.style = _config.style || {}
 
diff --git a/src/tabviews/custom/components/table/edit-table/index.jsx b/src/tabviews/custom/components/table/edit-table/index.jsx
index 49dae01..3496def 100644
--- a/src/tabviews/custom/components/table/edit-table/index.jsx
+++ b/src/tabviews/custom/components/table/edit-table/index.jsx
@@ -48,7 +48,6 @@
    */
   UNSAFE_componentWillMount () {
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
     let setting = {..._config.setting, ..._config.wrap}
     setting.tableId = Utils.getuuid()
 
@@ -82,11 +81,6 @@
       setting.operType = 'btnMode'
     }
 
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
     let _columns = []
     let signAdd = false
     _config.cols.forEach(column => {
@@ -115,17 +109,6 @@
   
           return !cell.Hide
         })
-      }
-
-      if (column.type === 'custom') {
-        column.elements = column.elements.map(item => {
-          if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-            item.decimal = _cols.get(item.field).decimal || 0
-          }
-          return item
-        })
-      } else if (column.type === 'action') {
-        column.operations = column.elements
       }
 
       _columns.push(column)
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 bcf4ee3..8c85c47 100644
--- a/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -916,7 +916,7 @@
     pageIndex: 1,         // 鍒濆椤甸潰绱㈠紩
     pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     columns: null,        // 鏄剧ず鍒�
-    fields: [],
+    forms: [],
     pickup: false,        // 鏀惰捣鏈�夋嫨椤�
     orderfields: {},      // 鎺掑簭id涓巉ield杞崲
     loading: false,
@@ -932,51 +932,81 @@
 
     let _columns = []
     let deForms = []
-    columns.forEach(item => {
-      if (!initEditLine && item.editable === 'true') {
-        initEditLine = item
-      }
+    let _forms = {}
 
-      if (item.type === 'text' && item.editable === 'true' && item.editType === 'select' && item.resourceType === '1') {
-        let _option = Utils.getSelectQueryOptions(item)
+    let getColumns = (cols) => {
+      return cols.map(item => {
+        let cell = null
+  
+        if (item.type === 'colspan') {
+          cell = { title: item.label, align: item.Align }
+          cell.children = getColumns(item.subcols)
+        } else {
+          if (item.editable === 'true') {
+            _forms[item.field] = item
+            if (!initEditLine) {
+              initEditLine = item
+            }
+          }
+    
+          if (item.type === 'text' && item.editable === 'true' && item.editType === 'select' && item.resourceType === '1') {
+            let _option = Utils.getSelectQueryOptions(item)
+    
+            if (window.GLOB.debugger === true || window.debugger === true) {
+              console.info(_option.sql)
+            }
+    
+            item.base_sql = window.btoa(window.encodeURIComponent(_option.sql))
+            item.arr_field = _option.field
+    
+            deForms.push(item)
+          }
+    
+          if (item.field) {
+            orderfields[item.uuid] = item.field
+          }
 
-        if (window.GLOB.debugger === true || window.debugger === true) {
-          console.info(_option.sql)
+          cell = {
+            align: item.Align,
+            dataIndex: item.uuid,
+            title: item.label,
+            sorter: !!(item.field && item.IsSort === 'true'),
+            width: item.Width || 120,
+            $type: item.type,
+            onCell: record => ({
+              record,
+              col: item,
+              config: item.type === 'custom' || item.type === 'action' ? {setting, columns: fields} : null,
+            })
+          }
         }
+  
+        return cell
+      })
+    }
+    _columns = getColumns(columns)
 
-        item.base_sql = window.btoa(window.encodeURIComponent(_option.sql))
-        item.arr_field = _option.field
+    let forms = []
+    fields.forEach(item => {
+      if (item.field === setting.primaryKey) return
 
-        deForms.push(item)
+      if (_forms[item.field]) {
+        forms.push({..._forms[item.field], datatype: item.datatype})
+      } else {
+        forms.push(item)
       }
+    })
 
-      if (item.field) {
-        orderfields[item.uuid] = item.field
+    _columns.forEach(item => {
+      if (item.$type === 'action') return
+
+      let _copy = fromJS(item).toJS()
+      _copy.sorter = false
+
+      if (item.editable === 'true') {
+        _copy.title = <span>{item.label}<EditOutlined className="system-color mk-edit-sign"/></span>
       }
-
-      let _item = {
-        align: item.Align,
-        dataIndex: item.uuid,
-        title: item.label,
-        sorter: item.field && item.IsSort === 'true',
-        width: item.Width || 120,
-        onCell: record => ({
-          record,
-          col: item,
-          config: item.type === 'custom' || item.type === 'action' ? {setting, columns: fields} : null,
-        })
-      }
-
-      if (item.type !== 'action') {
-        let _copy = fromJS(_item).toJS()
-        _copy.sorter = false
-
-        if (item.editable === 'true') {
-          _copy.title = <span>{item.label}<EditOutlined className="system-color mk-edit-sign"/></span>
-        }
-        edColumns.push(_copy)
-      }
-      _columns.push(_item)
+      edColumns.push(_copy)
     })
 
     if (setting.delable !== 'false' && setting.operType !== 'buoyMode') {
@@ -993,13 +1023,6 @@
       })
     }
 
-    // if (setting.borderColor) { // 杈规棰滆壊
-    //   let style = `#${setting.tableId} table, #${setting.tableId} tr, #${setting.tableId} th, #${setting.tableId} td {border-color: ${setting.borderColor}}`
-    //   let ele = document.createElement('style')
-    //   ele.innerHTML = style
-    //   document.getElementsByTagName('head')[0].appendChild(ele)
-    // }
-
     let size = (setting.pageSize || 10) + ''
     let pageOptions = ['10', '25', '50', '100', '500', '1000']
 
@@ -1009,6 +1032,7 @@
     }
 
     this.setState({
+      forms,
       pageSize: setting.pageSize || 10,
       pageOptions,
       columns: _columns,
@@ -1035,12 +1059,6 @@
   }
 
   componentDidMount () {
-    const { fields, setting } = this.props
-
-    this.setState({
-      fields: fields.filter(item => item.field !== setting.primaryKey),
-    })
-
     MKEmitter.addListener('subLine', this.subLine)
     MKEmitter.addListener('nextLine', this.nextLine)
     MKEmitter.addListener('addRecord', this.addLine)
@@ -1286,7 +1304,7 @@
   }
 
   subLine = (col, record) => {
-    const { tableId, fields, edData } = this.state
+    const { tableId, forms, edData } = this.state
 
     if (col && col.tableId !== tableId) return
 
@@ -1300,7 +1318,7 @@
     setTimeout(() => {
       let item = fromJS(record).toJS()
       let line = []
-      fields.forEach(col => {
+      forms.forEach(col => {
         if (col.editable !== 'true' || item.$deleted) {
           if (col.type === 'number') {
             item[col.field] = +item[col.field]
@@ -1357,7 +1375,7 @@
   }
 
   plusLine = () => {
-    const { edData, fields, initEditLine } = this.state
+    const { edData, forms, initEditLine } = this.state
 
     let item = {...edData[edData.length - 1]}
 
@@ -1365,7 +1383,7 @@
     item.$type = 'add'
     item.$Index = ''
 
-    fields.forEach(col => {
+    forms.forEach(col => {
       if (col.initval !== '$copy') {
         item[col.field] = col.initval
       }
@@ -1434,7 +1452,7 @@
 
   addLine = (id, record) => {
     const { BID } = this.props
-    const { edData, fields, tableId } = this.state
+    const { edData, forms, tableId } = this.state
 
     if (id) {
       if (id !== tableId) return
@@ -1448,7 +1466,7 @@
       item.$Index = ''
       item.$$BID = BID || ''
   
-      fields.forEach(col => {
+      forms.forEach(col => {
         if (col.initval !== '$copy') {
           item[col.field] = col.initval
         }
@@ -1481,7 +1499,7 @@
         item.$$BID = BID || ''
       }
   
-      fields.forEach(col => {
+      forms.forEach(col => {
         if (col.initval !== '$copy') {
           item[col.field] = col.initval
         }
@@ -1502,7 +1520,7 @@
   }
 
   checkData = () => {
-    const { edData, fields } = this.state
+    const { edData, forms } = this.state
 
     if (edData.length === 0) {
       notification.warning({
@@ -1516,7 +1534,7 @@
     let Index = 1
     let data = fromJS(edData).toJS().map(item => {
       let line = []
-      fields.forEach(col => {
+      forms.forEach(col => {
         if (col.editable !== 'true' || item.$deleted) {
           if (col.type === 'number') {
             item[col.field] = +item[col.field]
@@ -1581,7 +1599,7 @@
 
   submit = (data, type) => {
     const { submit, BID, setting } = this.props
-    const { fields } = this.state
+    const { forms } = this.state
 
     if (type !== 'simple' && (setting.commit === 'change' || setting.commit === 'simple')) {
       data = data.filter(item => !item.$origin)
@@ -1596,7 +1614,7 @@
       return
     }
 
-    let result = getEditTableSql(submit, data, fields)
+    let result = getEditTableSql(submit, data, forms)
 
     let param = {
       excel_in: result.lines,
@@ -1996,9 +2014,9 @@
         </div> : null}
         <div className="edit-custom-table-btn-wrap" style={submit.wrapStyle}>
           {!submit.hasAction && pickup ? <Button style={submit.style} onClick={() => setTimeout(() => {this.checkData()}, 10)} loading={loading} className="submit-table" type="link">鎻愪氦</Button> : null}
-          <Switch title="缂栬緫" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" disabled={loading || this.props.loading} checked={pickup} onChange={this.pickupChange} />
+          {setting.switchable !== 'false' ? <Switch title="缂栬緫" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" disabled={loading || this.props.loading} checked={pickup} onChange={this.pickupChange} /> : null}
         </div>
-        <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${setting.operType || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''}`} id={tableId}>
+        <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${setting.operType || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} id={tableId}>
           <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 25f0089..6d3798c 100644
--- a/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
+++ b/src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -318,6 +318,11 @@
     }
   }
 }
+.edit-custom-table.mk-edit-multi {
+  th .ant-table-column-title .anticon-edit {
+    display: none;
+  }
+}
 .edit-custom-table.editable {
   td {
     background-color: #ffffff!important;
diff --git a/src/tabviews/custom/components/table/normal-table/index.jsx b/src/tabviews/custom/components/table/normal-table/index.jsx
index 0ffafaa..b4ec245 100644
--- a/src/tabviews/custom/components/table/normal-table/index.jsx
+++ b/src/tabviews/custom/components/table/normal-table/index.jsx
@@ -54,7 +54,6 @@
   UNSAFE_componentWillMount () {
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
     let _data = null
     let _sync = _config.setting.sync === 'true'
 
@@ -130,31 +129,6 @@
         }
       }
     }
-
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
-    _config.cols.forEach(column => {
-      if (column.type === 'custom') {
-        column.elements = column.elements.map(item => {
-          if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-            item.decimal = _cols.get(item.field).decimal || 0
-          }
-          return item
-        })
-      } else if (column.type === 'action') {
-        column.operations = column.elements
-      }
-    })
-
-    // if (setting.color) {
-    //   setting.style.color = setting.color
-    // }
-    // if (setting.fontSize) {
-    //   setting.style.fontSize = setting.fontSize
-    // }
 
     if (_config.wrap.collapse === 'true') {
       _config.wrap.title = _config.wrap.title || ' '
@@ -240,7 +214,7 @@
     let result = await Api.genericInterface(param)
     if (result.status) {
       this.loaded = true
-      if (config.$cache && pageIndex === 1) {
+      if (config.$cache && pageIndex === 1 && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
diff --git a/src/tabviews/custom/components/timeline/normal-timeline/index.jsx b/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
index d8ed53e..463c865 100644
--- a/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
+++ b/src/tabviews/custom/components/timeline/normal-timeline/index.jsx
@@ -41,7 +41,6 @@
   UNSAFE_componentWillMount () {
     const { data, initdata } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _cols = new Map()
 
     let _data = null
     let card = null
@@ -82,18 +81,7 @@
     _config.search = []
     _config.wrap.contentHeight = _config.wrap.title ? 'calc(100% - 45px)' : '100%'
 
-    _config.columns.forEach(item => {
-      if (item.type !== 'number') return
-      _cols.set(item.field, item)
-    })
-
     card = _config.subcards[0]
-    card.elements = card.elements.map(item => {
-      if (item.eleType === 'number' && item.field && _cols.has(item.field) && typeof(item.decimal) !== 'number') {
-        item.decimal = _cols.get(item.field).decimal || 0
-      }
-      return item
-    })
 
     this.setState({
       card,
@@ -230,7 +218,7 @@
     this.loadData()
   }
 
-   /**
+  /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
   queryModuleParam = (menuId, callback) => {
@@ -269,6 +257,7 @@
       return
     }
 
+    // 鍐呴儴鍑芥暟涓簔_mk_express锛岃〃绀烘煡璇㈠揩閫掍俊鎭�
     if (config.setting.interType === 'inner' && config.setting.innerFunc === 'z_mk_express') {
       this.getExpress()
       return
@@ -301,7 +290,7 @@
     let result = await Api.genericInterface(param)
     if (result.status) {
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
diff --git a/src/tabviews/custom/components/tree/antd-tree/index.jsx b/src/tabviews/custom/components/tree/antd-tree/index.jsx
index 688fe7a..6b287c2 100644
--- a/src/tabviews/custom/components/tree/antd-tree/index.jsx
+++ b/src/tabviews/custom/components/tree/antd-tree/index.jsx
@@ -1,17 +1,20 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, Empty, notification, Input, Tree, Modal } from 'antd'
-import { FolderOpenOutlined, FolderOutlined, FileOutlined } from '@ant-design/icons'
+import { Spin, Empty, notification, Input, Tree, Modal, Dropdown } from 'antd'
+import { FolderOpenOutlined, FolderOutlined, FileOutlined, MoreOutlined } from '@ant-design/icons'
 
 import Api from '@/api'
 import UtilsDM from '@/utils/utils-datamanage.js'
 import MKEmitter from '@/utils/events.js'
 import TimerTask from '@/utils/timer-task.js'
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
 const { TreeNode } = Tree
 const { Search } = Input
+
+const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
 
 class NormalTree extends Component {
   static propTpyes = {
@@ -117,6 +120,8 @@
 
     MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
     
     if (config.timer) {
       this.timer = new TimerTask()
@@ -145,6 +150,8 @@
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
 
     this.timer && this.timer.stop()
   }
@@ -165,6 +172,55 @@
       this.setState({ BID: id }, () => {
         this.loadData()
       })
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  queryModuleParam = (menuId, callback) => {
+    const { mainSearch } = this.props
+    const { arr_field, config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    let searches = []
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key.toLowerCase())
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key.toLowerCase())) {
+          searches.push(item)
+        }
+      })
+    }
+
+    callback({
+      arr_field: arr_field,
+      orderBy: config.setting.order || '',
+      search: searches,
+      menuName: config.name
+    })
+  }
+
+  /**
+   * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂�
+   * @param {*} menuId     // 鑿滃崟Id
+   * @param {*} position   // 鍒锋柊浣嶇疆
+   * @param {*} btn        // 鎵ц鐨勬寜閽�
+   */
+  refreshByButtonResult = (menuId, position, btn) => {
+    const { config, BID } = this.state
+
+    if (config.uuid !== menuId) return
+
+    if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) { // 鍒锋柊婧愮粍浠舵椂锛岄檮甯﹀埛鏂颁笂绾ц涓庡綋鍓嶇粍浠�
+      MKEmitter.emit('reloadData', config.setting.supModule, BID)
+    } else {
+      this.loadData()
+    }
+
+    if (position === 'popclose') { // 鎵ц鍚姩寮圭獥鐨勬寜閽墍閫夋嫨鐨勫埛鏂伴」
+      btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
     }
   }
 
@@ -204,7 +260,7 @@
     let result = await Api.genericInterface(param)
     if (result.status) {
       this.loaded = true
-      if (config.$cache) {
+      if (config.$cache && config.setting.onload !== 'false') {
         Api.writeCacheConfig(config.uuid, result.data || '')
       }
 
@@ -257,6 +313,7 @@
     data.forEach(item => {
       let pval = item[config.wrap.parentField]
       let val = item[config.wrap.valueField]
+      let uuid = item[config.setting.primaryKey] || ''
 
       if (!val || logMap.has(val)) return
 
@@ -264,6 +321,7 @@
         hasSelectKey = true
         selectData = {
           ...item,
+          $$uuid: uuid,
           $title: item[config.wrap.labelField] || '',
           $key: val,
           $parentId: ''
@@ -274,6 +332,7 @@
       if (pval === config.wrap.mark) {
         parentNodes.push({
           ...item,
+          $$uuid: uuid,
           $title: item[config.wrap.labelField] || '',
           $key: val,
           $parentId: ''
@@ -281,6 +340,7 @@
       } else if (pval) {
         _options.push({
           ...item,
+          $$uuid: uuid,
           $title: item[config.wrap.labelField] || '',
           $key: val,
           $parentId: pval
@@ -309,7 +369,7 @@
       })
 
       setTimeout(() => {
-        MKEmitter.emit('resetSelectLine', config.uuid, _treeNodes[0].$key, _treeNodes[0])
+        MKEmitter.emit('resetSelectLine', config.uuid, _treeNodes[0].$$uuid, _treeNodes[0])
       }, 200)
     } else if (!hasSelectKey && selectKey) {
       this.setState({
@@ -318,7 +378,7 @@
 
       MKEmitter.emit('resetSelectLine', config.uuid, '', '')
     } else if (hasSelectKey) {
-      MKEmitter.emit('resetSelectLine', config.uuid, selectKey, selectData)
+      MKEmitter.emit('resetSelectLine', config.uuid, selectData.$$uuid, selectData)
     }
   }
 
@@ -401,6 +461,37 @@
     })
   }
 
+  renderActionTreeNodes = (nodes) => {
+    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>
+      </>
+
+      if (item.children) {
+        return (
+          <TreeNode icon={<span><FolderOpenOutlined /><FolderOutlined /></span>} title={title} key={item.$key} dataRef={item}>
+            {this.renderActionTreeNodes(item.children)}
+          </TreeNode>
+        )
+      }
+      return <TreeNode icon={<FileOutlined />} key={item.$key} title={title} dataRef={item} isLeaf />
+    })
+  }
+
   changeExpandedKeys = (expandedKeys) => {
     this.setState({
       expandedKeys: expandedKeys
@@ -446,7 +537,7 @@
 
     if (selected) {
       delete _data.children
-      MKEmitter.emit('resetSelectLine', config.uuid, (_data ? _data.$key : ''), _data)
+      MKEmitter.emit('resetSelectLine', config.uuid, (_data ? _data.$$uuid : ''), _data)
     }
 
     this.setState({
@@ -457,6 +548,8 @@
 
   render() {
     const { config, loading, treeNodes, expandedKeys, selectedKeys } = this.state
+
+    let extra = config.action && config.action.length > 0
 
     return (
       <div className="custom-tree-box" id={'anchor' + config.uuid} style={config.style}>
@@ -476,12 +569,12 @@
             onSelect={this.selectTreeNode}
             expandedKeys={expandedKeys}
             selectedKeys={selectedKeys}
-            onRightClick={this.changeExpandedAllKeys}
+            onRightClick={!extra ? this.changeExpandedAllKeys : null}
             onExpand={this.changeExpandedKeys}
             showIcon={config.wrap.showIcon === 'true'}
             showLine={config.wrap.showLine === 'true'}
           >
-            {this.renderTreeNodes(treeNodes)}
+            {!extra ? this.renderTreeNodes(treeNodes) : this.renderActionTreeNodes(treeNodes)}
           </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 0ab6c56..b384cef 100644
--- a/src/tabviews/custom/components/tree/antd-tree/index.scss
+++ b/src/tabviews/custom/components/tree/antd-tree/index.scss
@@ -54,6 +54,15 @@
     .ant-tree-node-content-wrapper-open > span > span > .anticon-folder {
       display: none;
     }
+    .ant-tree-node-content-wrapper {
+      position: relative;
+      .anticon-more {
+        position: absolute;
+        right: 0px;
+        padding: 5px 10px;
+        color: var(--mk-sys-color);
+      }
+    }
   }
 
   .tree-box::-webkit-scrollbar {
@@ -80,7 +89,8 @@
     }
   }
   .tree-header + .ant-empty {
-    margin-top: 35px;
+    position: static;
+    margin-top: 20px;
   }
   .loading-mask {
     position: absolute;
@@ -103,3 +113,25 @@
     }
   }
 }
+
+.mk-tree-dropdown-wrap {
+  box-shadow: 0 0 2px #bcbcbc;
+  background: #ffffff;
+  min-width: 85px;
+  .button-list.toolbar-button {
+    padding: 0px;
+  }
+  button {
+    display: block;
+    margin: 0!important;
+    width: 100%;
+    border-radius: 0px;
+    padding-left: 15px!important;
+    .anticon {
+      display: none;
+    }
+    .anticon + span {
+      margin-left: 0px;
+    }
+  }
+}
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 39687e8..cbf6415 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -21,6 +21,7 @@
 const AntvScatter = asyncComponent(() => import('./components/chart/antv-scatter'))
 const DataCard = asyncComponent(() => import('./components/card/data-card'))
 const PropCard = asyncComponent(() => import('./components/card/prop-card'))
+const DoubleDataCard = asyncComponent(() => import('./components/card/double-data-card'))
 const SimpleForm = asyncComponent(() => import('./components/form/simple-form'))
 const StepForm = asyncComponent(() => import('./components/form/step-form'))
 const TabForm = asyncComponent(() => import('./components/form/tab-form'))
@@ -241,6 +242,15 @@
         config,
         mainSearch
       }, () => {
+        if (config.normalcss) {
+          let node = document.getElementById(config.uuid)
+          node && node.remove()
+    
+          let ele = document.createElement('style')
+          ele.id = config.uuid
+          ele.innerHTML = config.normalcss
+          document.getElementsByTagName('head')[0].appendChild(ele)
+        }
         if (params.length === 0) {
           setTimeout(() => { // 寤舵椂鍔犺浇鐘舵��
             this.setState({
@@ -506,7 +516,7 @@
       if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗″涓婄骇缁勪欢
         mutil = true
         item.setting.supModule = item.supNodes[0].componentId
-      } else if (item.setting && 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') {
           item.setting.supModule = pid
@@ -530,6 +540,9 @@
 
           if (!mutil && cell.syncComponentId === item.setting.supModule) {
             cell.syncComponentId = ''
+            if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+              cell.execSuccess = 'mainline'
+            }
           }
 
           if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
@@ -539,6 +552,14 @@
           if (cell.btnstyle) { // 鍏煎
             cell.style = cell.style || {}
             cell.style = {...cell.style, ...cell.btnstyle}
+          }
+
+          if (cell.controlField) {
+            if (/,/ig.test(cell.controlVal)) {
+              cell.controlVals = cell.controlVal.split(',')
+            } else {
+              cell.controlVals = [(cell.controlVal || '')]
+            }
           }
 
           return skip || permAction[cell.uuid]
@@ -568,14 +589,20 @@
 
               if (!mutil && cell.syncComponentId === item.setting.supModule) {
                 cell.syncComponentId = ''
+                if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                  cell.execSuccess = 'mainline'
+                }
               }
 
               if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
                 cell = this.getPrinter(cell, item.uuid)
               }
-              if (card.btnstyle) { // 鍏煎
-                card.style = card.style || {}
-                card.style = {...card.style, ...card.btnstyle}
+              if (cell.controlField) {
+                if (/,/ig.test(cell.controlVal)) {
+                  cell.controlVals = cell.controlVal.split(',')
+                } else {
+                  cell.controlVals = [(cell.controlVal || '')]
+                }
               }
             } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
               if (!cell.height) {
@@ -608,14 +635,20 @@
 
               if (!mutil && cell.syncComponentId === item.setting.supModule) {
                 cell.syncComponentId = ''
+                if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                  cell.execSuccess = 'mainline'
+                }
               }
 
               if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
                 cell = this.getPrinter(cell, item.uuid)
               }
-              if (card.btnstyle) { // 鍏煎
-                card.style = card.style || {}
-                card.style = {...card.style, ...card.btnstyle}
+              if (cell.controlField) {
+                if (/,/ig.test(cell.controlVal)) {
+                  cell.controlVals = cell.controlVal.split(',')
+                } else {
+                  cell.controlVals = [(cell.controlVal || '')]
+                }
               }
             } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
               if (!cell.height) {
@@ -653,10 +686,20 @@
 
             if (cell.syncComponentId === item.wrap.supModule) {
               cell.syncComponentId = ''
+              if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                cell.execSuccess = 'mainline'
+              }
             }
 
             if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
               cell = this.getPrinter(cell, item.uuid)
+            }
+            if (cell.controlField) {
+              if (/,/ig.test(cell.controlVal)) {
+                cell.controlVals = cell.controlVal.split(',')
+              } else {
+                cell.controlVals = [(cell.controlVal || '')]
+              }
             }
           } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
             if (!cell.height) {
@@ -688,6 +731,9 @@
 
             if (cell.syncComponentId === item.setting.supModule) {
               cell.syncComponentId = ''
+              if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                cell.execSuccess = 'mainline'
+              }
             }
 
             if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
@@ -697,6 +743,14 @@
             if (cell.btnstyle) { // 鍏煎
               cell.style = cell.style || {}
               cell.style = {...cell.style, ...cell.btnstyle}
+            }
+
+            if (cell.controlField) {
+              if (/,/ig.test(cell.controlVal)) {
+                cell.controlVals = cell.controlVal.split(',')
+              } else {
+                cell.controlVals = [(cell.controlVal || '')]
+              }
             }
 
             return skip || permAction[cell.uuid]
@@ -726,6 +780,9 @@
 
           if (group.subButton.syncComponentId === item.setting.supModule) {
             group.subButton.syncComponentId = ''
+            if (group.subButton.execSuccess === 'grid') {
+              group.subButton.execSuccess = 'mainline'
+            }
           }
 
           group.fields = group.fields.map(cell => {
@@ -890,7 +947,7 @@
 
       // dataName 绯荤粺鐢熸垚鐨勬暟鎹簮鍚嶇О
       if (component.setting.sync === 'true') {
-        component.dataName = Utils.getdataName()
+        component.dataName = 'mk' + component.uuid.slice(-18)
       }
 
       // floor    缁勪欢鐨勫眰绾�
@@ -941,6 +998,15 @@
     return interfaces.map(inter => {
       inter.setting.delay = delay
       delay += 15
+
+      if (inter.setting.supModule) {
+        let pid = inter.setting.supModule.pop()
+        if (pid && pid !== 'empty') {
+          inter.setting.supModule = pid
+        } else {
+          inter.setting.supModule = ''
+        }
+      }
 
       if (inter.setting.interType !== 'system') return inter
 
@@ -1152,6 +1218,12 @@
             <PropCard config={item} data={data} mainSearch={mainSearch}/>
           </Col>
         )
+      } else if (item.type === 'card' && item.subtype === 'dualdatacard') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <DoubleDataCard config={item} mainSearch={mainSearch}/>
+          </Col>
+        )
       } else if (item.type === 'table' && item.subtype === 'normaltable') {
         return (
           <Col span={item.width} style={style} key={item.uuid}>
@@ -1314,7 +1386,7 @@
     return (
       <div className={'custom-page-wrap ' + (loadingview || loading ? 'loading' : '')} id={this.state.ContainerId} style={config ? config.style : null}>
         {(loadingview || (loading && !config.$cache)) ? <Spin className="view-spin" size="large" /> : null}
-        <Row className="component-wrap">{this.getComponents()}</Row>
+        <Row id={config ? 'menu' + config.uuid : ''} className="component-wrap">{this.getComponents()}</Row>
         {config && config.interfaces.length > 0 ? <MkInterfaces BID={BID} interfaces={config.interfaces}/> : null}
         {config && window.GLOB.breakpoint ? <DebugTable /> : null}
         {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <TableNodes config={config} /> : null}
diff --git a/src/tabviews/custom/index.scss b/src/tabviews/custom/index.scss
index b01f497..7d331eb 100644
--- a/src/tabviews/custom/index.scss
+++ b/src/tabviews/custom/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/custom/popview/index.jsx b/src/tabviews/custom/popview/index.jsx
index 6862c55..6149fc0 100644
--- a/src/tabviews/custom/popview/index.jsx
+++ b/src/tabviews/custom/popview/index.jsx
@@ -20,6 +20,7 @@
 const AntvScatter = asyncComponent(() => import('../components/chart/antv-scatter'))
 const DataCard = asyncComponent(() => import('../components/card/data-card'))
 const PropCard = asyncComponent(() => import('../components/card/prop-card'))
+const DoubleDataCard = asyncComponent(() => import('../components/card/double-data-card'))
 const SimpleForm = asyncComponent(() => import('../components/form/simple-form'))
 const StepForm = asyncComponent(() => import('../components/form/step-form'))
 const TabForm = asyncComponent(() => import('../components/form/tab-form'))
@@ -362,7 +363,7 @@
       if (item.wrap && item.wrap.supType === 'multi') { // 鏁版嵁鍗″涓婄骇缁勪欢
         mutil = true
         item.setting.supModule = item.supNodes[0].componentId
-      } else if (item.setting && 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') {
           item.setting.supModule = pid
@@ -384,11 +385,22 @@
 
           if (!mutil && cell.syncComponentId === item.setting.supModule) {
             cell.syncComponentId = ''
+            if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+              cell.execSuccess = 'mainline'
+            }
           }
 
           if (cell.btnstyle) { // 鍏煎
             cell.style = cell.style || {}
             cell.style = {...cell.style, ...cell.btnstyle}
+          }
+
+          if (cell.controlField) {
+            if (/,/ig.test(cell.controlVal)) {
+              cell.controlVals = cell.controlVal.split(',')
+            } else {
+              cell.controlVals = [(cell.controlVal || '')]
+            }
           }
 
           return true
@@ -416,10 +428,16 @@
 
               if (!mutil && cell.syncComponentId === item.setting.supModule) {
                 cell.syncComponentId = ''
+                if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                  cell.execSuccess = 'mainline'
+                }
               }
-              if (card.btnstyle) { // 鍏煎
-                card.style = card.style || {}
-                card.style = {...card.style, ...card.btnstyle}
+              if (cell.controlField) {
+                if (/,/ig.test(cell.controlVal)) {
+                  cell.controlVals = cell.controlVal.split(',')
+                } else {
+                  cell.controlVals = [(cell.controlVal || '')]
+                }
               }
             } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
               if (!cell.height) {
@@ -450,11 +468,17 @@
 
               if (!mutil && cell.syncComponentId === item.setting.supModule) {
                 cell.syncComponentId = ''
+                if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                  cell.execSuccess = 'mainline'
+                }
               }
 
-              if (card.btnstyle) { // 鍏煎
-                card.style = card.style || {}
-                card.style = {...card.style, ...card.btnstyle}
+              if (cell.controlField) {
+                if (/,/ig.test(cell.controlVal)) {
+                  cell.controlVals = cell.controlVal.split(',')
+                } else {
+                  cell.controlVals = [(cell.controlVal || '')]
+                }
               }
             } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
               if (!cell.height) {
@@ -490,6 +514,16 @@
 
             if (cell.syncComponentId === item.wrap.supModule) {
               cell.syncComponentId = ''
+              if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                cell.execSuccess = 'mainline'
+              }
+            }
+            if (cell.controlField) {
+              if (/,/ig.test(cell.controlVal)) {
+                cell.controlVals = cell.controlVal.split(',')
+              } else {
+                cell.controlVals = [(cell.controlVal || '')]
+              }
             }
           } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
             if (!cell.height) {
@@ -519,11 +553,22 @@
 
             if (cell.syncComponentId === item.setting.supModule) {
               cell.syncComponentId = ''
+              if (cell.execSuccess === 'line' || cell.execSuccess === 'grid') {
+                cell.execSuccess = 'mainline'
+              }
             }
 
             if (cell.btnstyle) { // 鍏煎
               cell.style = cell.style || {}
               cell.style = {...cell.style, ...cell.btnstyle}
+            }
+
+            if (cell.controlField) {
+              if (/,/ig.test(cell.controlVal)) {
+                cell.controlVals = cell.controlVal.split(',')
+              } else {
+                cell.controlVals = [(cell.controlVal || '')]
+              }
             }
 
             return true
@@ -552,6 +597,9 @@
 
           if (group.subButton.syncComponentId === item.setting.supModule) {
             group.subButton.syncComponentId = ''
+            if (group.subButton.execSuccess === 'grid') {
+              group.subButton.execSuccess = 'mainline'
+            }
           }
 
           group.fields = group.fields.map(cell => {
@@ -712,7 +760,7 @@
 
       // dataName 绯荤粺鐢熸垚鐨勬暟鎹簮鍚嶇О
       if (component.setting.sync === 'true') {
-        component.dataName = Utils.getdataName()
+        component.dataName = 'mk' + component.uuid.slice(-18)
       }
 
       // floor    缁勪欢鐨勫眰绾�
@@ -864,6 +912,12 @@
             <PropCard config={item} data={data} mainSearch={mainSearch}/>
           </Col>
         )
+      } else if (item.type === 'card' && item.subtype === 'dualdatacard') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <DoubleDataCard config={item} mainSearch={mainSearch}/>
+          </Col>
+        )
       } else if (item.type === 'table' && item.subtype === 'basetable') {
         return (
           <Col span={item.width} style={style} key={item.uuid}>
diff --git a/src/tabviews/custom/popview/index.scss b/src/tabviews/custom/popview/index.scss
index 6938042..b69e65d 100644
--- a/src/tabviews/custom/popview/index.scss
+++ b/src/tabviews/custom/popview/index.scss
@@ -7,10 +7,7 @@
   padding-left: 16px;
   padding-right: 16px;
   background-size: 100%;
-  
-  .component-wrap >.ant-col {
-    min-height: 0;
-  }
+
   .box404 {
     padding-top: 30px;
   }
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index b261601..ac80f8f 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -241,6 +241,7 @@
       config.action.forEach(item => {
         item.logLabel = Tab.label + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
         item.$menuId = this.props.MenuID
+        item.$old = true
 
         if (item.OpenType === 'funcbutton' && item.funcType === 'print' && item.verify) { // 鎵撳嵃鏈鸿缃�
           let _item = window.GLOB.UserCacheMap.get(Tab.uuid + item.uuid)
@@ -256,6 +257,15 @@
             }
           }
         }
+
+        if (item.controlField) {
+          if (/,/ig.test(item.controlVal)) {
+            item.controlVals = item.controlVal.split(',')
+          } else {
+            item.controlVals = [(item.controlVal || '')]
+          }
+        }
+        
         if (item.position === 'toolbar') {
           item.$toolbtn = true
           _actions.push(item)
diff --git a/src/tabviews/subtabtable/index.jsx b/src/tabviews/subtabtable/index.jsx
index 154233c..ef20200 100644
--- a/src/tabviews/subtabtable/index.jsx
+++ b/src/tabviews/subtabtable/index.jsx
@@ -211,6 +211,15 @@
       config.action.forEach(item => {
         item.logLabel = Tab.label + '-' + item.label // 鐢ㄤ簬sPC_TableData_InUpDe璁板綍鎿嶄綔鎸夐挳
         item.$menuId = this.props.MenuID
+        item.$old = true
+
+        if (item.controlField) {
+          if (/,/ig.test(item.controlVal)) {
+            item.controlVals = item.controlVal.split(',')
+          } else {
+            item.controlVals = [(item.controlVal || '')]
+          }
+        }
 
         if (item.position === 'toolbar') {
           item.$toolbtn = true
diff --git a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
index 36e44fc..fc411f4 100644
--- a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -31,31 +31,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -69,36 +49,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({disabled, hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -108,6 +64,43 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
   
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
diff --git a/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx
index 86891ed..7610cae 100644
--- a/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx
+++ b/src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx
@@ -45,7 +45,7 @@
         let sheetName = btn.verify.sheet
         let errDetail = ''
 
-        if (Object.keys(workbook.Sheets).length === 1) {
+        if (sheetName === 'Sheet1' && Object.keys(workbook.Sheets).length === 1) {
           sheetName = Object.keys(workbook.Sheets)[0]
         }
 
diff --git a/src/tabviews/zshare/actionList/excelInbutton/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
index d0cba8c..b632588 100644
--- a/src/tabviews/zshare/actionList/excelInbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -36,31 +36,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -74,36 +54,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({disabled, hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -113,6 +69,43 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
   
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
diff --git a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
index 3d93b36..be05ea6 100644
--- a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -18,6 +18,7 @@
   static propTpyes = {
     BID: PropTypes.string,            // 涓昏〃ID
     BData: PropTypes.any,             // 涓昏〃鏁版嵁
+    selectedData: PropTypes.any,      // 瀛愯〃涓�夋嫨鏁版嵁
     btn: PropTypes.object,            // 鎸夐挳
     setting: PropTypes.any,           // 椤甸潰閫氱敤璁剧疆
     updateStatus: PropTypes.func,     // 鎸夐挳鐘舵�佹洿鏂�
@@ -41,7 +42,7 @@
         this.setState({hidden: true})
       } else {
         let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+        if (btn.controlVals.includes(s)) {
           this.setState({hidden: true})
         } else {
           this.setState({hidden: false})
@@ -70,7 +71,7 @@
         this.setState({hidden: true})
       } else {
         let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+        if (btn.controlVals.includes(s)) {
           this.setState({hidden: true})
         } else {
           this.setState({hidden: false})
@@ -593,29 +594,68 @@
 
         this.table2excel(column, table, this.state.excelName.replace(/\.xlsx/ig, '.xls'))
 
-        if (btn.verify && btn.verify.enable === 'true' && btn.verify.script) {
+        if (btn.verify.enable === 'true' && btn.verify.script) {
           this.execCustomScript()
         } else {
           this.execSuccess({ErrCode: 'S', ErrMesg: '瀵煎嚭鎴愬姛锛�'})
         }
       } 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 = {}
         let colwidth = []
         let requires = []
+        let merges = []
 
         columns.forEach((col, i) => {
           _header.push(col.Column)
           _topRow[col.Column] = col.Text
-          colwidth.push({width: col.Width || 20})
+          colwidth.push({wch: col.Width || 20})
           if (col.required === 'true') {
             requires.push(i)
           }
         })
-  
-        let table = []
-  
-        table.push(_topRow)
+
+        if (btn.verify.merge === 'true') {
+          let fLine = {}
+          let sLine = {}
+          let sign = ''
+          columns.forEach((col, i) => {
+            if (/.+-.+/.test(col.Text)) {
+              let _sign = col.Text.split('-')[0]
+              let _name = col.Text.split('-')[1]
+              fLine[col.Column] = _sign
+              sLine[col.Column] = _name
+
+              if (sign === _sign) {
+                merges[merges.length - 1] = merges[merges.length - 1].split(':')[0] + `:${cols[i]}1`
+              } else {
+                merges.push(`${cols[i]}1:${cols[i]}2`)
+                sign = _sign
+              }
+            } else {
+              fLine[col.Column] = col.Text
+              sLine[col.Column] = col.Text
+              sign = ''
+              merges.push(`${cols[i]}1:${cols[i]}2`)
+            }
+          })
+
+          table.push(fLine)
+          table.push(sLine)
+        } else {
+          table.push(_topRow)
+        }
   
         data && data.forEach((item, index) => {
           let _row = {}
@@ -645,22 +685,42 @@
 
         ws['!cols'] = colwidth
 
+        if (btn.verify.rowHeight) {
+          ws['!rows'] = Array(table.length).fill({hpx: btn.verify.rowHeight})
+        }
+
         if (requires.length) {
-          let cols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
           requires.forEach(col => {
             if (cols[col]) {
               ws[cols[col] + '1'].s = {font: { color: { rgb: 'F5222D' } }}
             }
           })
         }
+
+        if (merges.length) {
+          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' }}
+          })
+        }
+
         // ws["A1"].s = {fill: { bgColor: { rgb: "FFFFAA"  }}, font: { color: { rgb: "1890FF" } }}
-  
+
         const wb = XLSX.utils.book_new()
-        XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
+        XLSX.utils.book_append_sheet(wb, ws, btn.verify.sheet || 'Sheet1')
   
         XLSX.writeFile(wb, this.state.excelName)
   
-        if (btn.verify && btn.verify.enable === 'true' && btn.verify.script) {
+        if (btn.verify.enable === 'true' && btn.verify.script) {
           this.execCustomScript()
         } else {
           this.execSuccess({ErrCode: 'S', ErrMesg: '瀵煎嚭鎴愬姛锛�'})
@@ -776,6 +836,7 @@
    * @description 鑾峰彇鐢ㄦ埛鑷畾涔夊瓨鍌ㄨ繃绋嬩紶鍙�
    */
   getExcelCustomParam = (orderBy, search, pagination = false, pageIndex = 1, pageSize = 100) => {
+    const { btn, selectedData } = this.props
     let _search = Utils.formatCustomMainSearch(search)
 
     let param = {
@@ -786,6 +847,13 @@
     // 鏁版嵁绠$悊鏉冮檺
     if (sessionStorage.getItem('dataM') === 'true') {
       param.dataM = 'Y'
+    }
+
+    if (btn.Ot === 'requiredOnce' && selectedData && selectedData.length > 0) {
+      let primaryId = selectedData.map(d => d.$$uuid || '').filter(Boolean).join(',')
+      if (primaryId) {
+        param.ID = primaryId
+      }
     }
 
     if (this.props.BID) {
@@ -804,17 +872,19 @@
    * @description 鑾峰彇榛樿瀛樺偍杩囩▼璇锋眰鍙傛暟
    */
   getExcelDefaultParam = (arr_field, orderBy, search, pagination = false, pageIndex = 1, pageSize = 100) => {
-    const { setting, btn } = this.props
+    const { setting, btn, selectedData, BID } = this.props
 
     let defaultSql = setting.execute || setting.default || 'true'
     let customScript = setting.customScript || ''
     let _dataresource = setting.dataresource || ''
     let queryType = setting.queryType
+    let primaryKey = setting.primaryKey || 'ID'
 
     if (btn.verify.dataType === 'custom') {
       defaultSql = btn.verify.defaultSql || 'true'
       _dataresource = btn.verify.dataresource || ''
       queryType = btn.verify.queryType
+      primaryKey = btn.verify.primaryKey || 'ID'
 
       if (/\s/.test(_dataresource)) {
         _dataresource = '(' + _dataresource + ') tb'
@@ -857,8 +927,8 @@
       param.dataM = 'Y'
     }
 
-    if (this.props.BID) {
-      param.BID = this.props.BID
+    if (BID) {
+      param.BID = BID
     }
 
     let userName = sessionStorage.getItem('User_Name') || ''
@@ -914,6 +984,16 @@
       _search = ''
     }
 
+    let primaryId = ''
+    if (btn.Ot === 'requiredOnce' && selectedData && selectedData.length > 0) {
+      primaryId = selectedData.map(d => d.$$uuid || '').filter(Boolean).join(',')
+      if (_search && primaryId) {
+        _search += ` and ${primaryKey} in (select ID from  dbo.SplitComma('${primaryId}'))`
+      } else if (primaryId) {
+        _search = `where ${primaryKey} in (select ID from  dbo.SplitComma('${primaryId}'))`
+      }
+    }
+
     let LText = ''
 
     if (defaultSql !== 'false' && !pagination) {
@@ -949,6 +1029,21 @@
       `
     }
 
+    LText = LText.replace(/@ID@/ig, `'${primaryId || ''}'`)
+    param.custom_script = param.custom_script.replace(/@ID@/ig, `'${primaryId || ''}'`)
+    LText = LText.replace(/@BID@/ig, `'${BID}'`)
+    param.custom_script = param.custom_script.replace(/@BID@/ig, `'${BID}'`)
+    LText = LText.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
+    LText = LText.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
+    LText = LText.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
+    param.custom_script = param.custom_script.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
+    LText = LText.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    param.custom_script = param.custom_script.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    LText = LText.replace(/@typename@/ig, `'admin'`)
+    param.custom_script = param.custom_script.replace(/@typename@/ig, `'admin'`)
+
     // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
     if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
       param.custom_script && console.info(`${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${param.custom_script}`)
diff --git a/src/tabviews/zshare/actionList/funcMegvii/index.jsx b/src/tabviews/zshare/actionList/funcMegvii/index.jsx
index 2f8cdd5..6da5dc4 100644
--- a/src/tabviews/zshare/actionList/funcMegvii/index.jsx
+++ b/src/tabviews/zshare/actionList/funcMegvii/index.jsx
@@ -34,20 +34,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (btn.controlVals.includes(s)) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -57,25 +48,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (btn.controlVals.includes(s)) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -90,6 +68,43 @@
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
 
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
+
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
    */
diff --git a/src/tabviews/zshare/actionList/funczip/index.jsx b/src/tabviews/zshare/actionList/funczip/index.jsx
index 9a5aed2..124190f 100644
--- a/src/tabviews/zshare/actionList/funczip/index.jsx
+++ b/src/tabviews/zshare/actionList/funczip/index.jsx
@@ -28,20 +28,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (btn.controlVals.includes(s)) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -51,25 +42,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (btn.controlVals.includes(s)) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -84,6 +62,43 @@
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
 
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
+
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
    */
diff --git a/src/tabviews/zshare/actionList/index.jsx b/src/tabviews/zshare/actionList/index.jsx
index 94ab9c5..10871f6 100644
--- a/src/tabviews/zshare/actionList/index.jsx
+++ b/src/tabviews/zshare/actionList/index.jsx
@@ -94,6 +94,7 @@
             btn={item}
             BData={BData}
             setting={setting}
+            selectedData={selectedData}
           />
         )
       } else if (item.OpenType === 'popview') {
diff --git a/src/tabviews/zshare/actionList/index.scss b/src/tabviews/zshare/actionList/index.scss
index 8efb160..99ac35f 100644
--- a/src/tabviews/zshare/actionList/index.scss
+++ b/src/tabviews/zshare/actionList/index.scss
@@ -49,6 +49,7 @@
     height: 34px;
     border-radius: 0px;
     padding-left: 15px!important;
+    border-bottom-width: 1px!important;
     .anticon {
       display: none;
     }
diff --git a/src/tabviews/zshare/actionList/newpagebutton/index.jsx b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
index 2ca6b55..33f3232 100644
--- a/src/tabviews/zshare/actionList/newpagebutton/index.jsx
+++ b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -27,31 +27,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -65,36 +45,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -104,6 +60,43 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
   
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
diff --git a/src/tabviews/zshare/actionList/normalbutton/index.jsx b/src/tabviews/zshare/actionList/normalbutton/index.jsx
index 0654d5f..4b9f777 100644
--- a/src/tabviews/zshare/actionList/normalbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -13,6 +13,7 @@
 import { updateForm } from '@/utils/utils-update.js'
 import MKEmitter from '@/utils/events.js'
 import MkIcon from '@/components/mk-icon'
+import MkCounter from './mkcounter'
 // import './index.scss'
 
 const MutilForm = asyncSpinComponent(() => import('@/tabviews/zshare/mutilform'))
@@ -43,42 +44,35 @@
     disabled: false,
     hidden: false,
     autoMatic: false,
-    check: false
+    check: false,
+    count: 0
   }
 
   moduleParams = null
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
     
     if (btn.OpenType === 'form') {
       let data = selectedData && selectedData[0] ? selectedData[0] : null
-      this.setState({check: data && data[btn.field] === btn.openVal})
+      if (btn.formType === 'counter') {
+        let count = 0
+        if (data && data[btn.field]) {
+          count = +data[btn.field]
+          if (isNaN(count)) {
+            count = 0
+          }
+        }
+        this.setState({count: count })
+      } else {
+        this.setState({check: data && data[btn.field] === btn.openVal})
+      }
     } else if (btn.OpenType === 'formSubmit') {
       this.setState({
         selines: selectedData || []
@@ -104,41 +98,28 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
 
     if (btn.OpenType === 'form') {
       let data = nextProps.selectedData && nextProps.selectedData[0] ? nextProps.selectedData[0] : null
-      this.setState({check: data && data[btn.field] === btn.openVal})
+      if (btn.formType === 'counter') {
+        let count = 0
+        if (data && data[btn.field]) {
+          count = +data[btn.field]
+          if (isNaN(count)) {
+            count = 0
+          }
+        }
+        this.setState({count: count })
+      } else {
+        this.setState({check: data && data[btn.field] === btn.openVal})
+      }
     } else if (btn.OpenType === 'formSubmit') {
       this.setState({
         selines: nextProps.selectedData || []
@@ -153,6 +134,43 @@
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
     MKEmitter.removeListener('triggerFormSubmit', this.actionSubmit)
     MKEmitter.removeListener('triggerBtnPopSubmit', this.triggerBtnPopSubmit)
+  }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
   }
 
   triggerBtnPopSubmit = (id) => {
@@ -358,29 +376,41 @@
         this.improveAction()
       })
     } else if (btn.OpenType === 'form') {
-      this.setState({
-        loading: true,
-        check: !this.state.check
-      }, () => {
-        let type = 'text'
-        let fieldlen = 50
-        let value = this.state.check ? btn.openVal : btn.closeVal
-
-        if (typeof(value) === 'number') {
-          type = 'number'
-          fieldlen = 0
-        }
-        
+      if (btn.formType === 'counter') {
         let item = {
-          type: type,
+          type: 'number',
           readin: true,
           writein: true,
-          fieldlen: fieldlen,
+          fieldlen: btn.decimal || 0,
           key: btn.field,
-          value: value
+          value: this.state.count
         }
-        this.execSubmit(data, () => { this.setState({loading: false})}, [item])
-      })
+        this.execSubmit(data, () => {}, [item])
+      } else {
+        this.setState({
+          loading: true,
+          check: !this.state.check
+        }, () => {
+          let type = 'text'
+          let fieldlen = 50
+          let value = this.state.check ? btn.openVal : btn.closeVal
+  
+          if (typeof(value) === 'number') {
+            type = 'number'
+            fieldlen = 0
+          }
+          
+          let item = {
+            type: type,
+            readin: true,
+            writein: true,
+            fieldlen: fieldlen,
+            key: btn.field,
+            value: value
+          }
+          this.execSubmit(data, () => { this.setState({loading: false})}, [item])
+        })
+      }
     }
 
     if (window.GLOB.systemType === 'production') {
@@ -973,6 +1003,7 @@
     _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'`)
 
     return _sql
   }
@@ -1022,7 +1053,7 @@
 
       if (params[0].$unCheckParam) {
         this.checkLoopRequest(params, _resolve)
-      } else if (params.length <= 20) {
+      } else if (params.length <= 20 && btn.execType !== 'single') {
         let deffers = params.map((param, i) => {
           return new Promise(resolve => {
             setTimeout(() => {
@@ -1068,6 +1099,7 @@
           let iserror = false
           let errorMsg = ''
           result.forEach(res => {
+            if (iserror) return
             if (res.status) {
               errorMsg = res
             } else {
@@ -1083,7 +1115,7 @@
           _resolve()
         })
       } else { // 瓒呭嚭20涓姹傛椂寰幆鎵ц
-        if (btn.progress === 'progressbar' && btn.$toolbtn) {
+        if (btn.progress === 'progressbar' && btn.$toolbtn && params.length > 1) {
           this.setState({
             loadingTotal: params.length
           })
@@ -1456,6 +1488,14 @@
       sql = sql.join('')
       sql = _prevCustomScript + sql
       sql = sql + _backCustomScript
+
+      sql = sql.replace(/@ID@/ig, `'${record.ID || ''}'`)
+      sql = sql.replace(/@BID@/ig, `'${this.props.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.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
         console.info(sql.replace(/\n\s{8}/ig, '\n'))
@@ -1918,21 +1958,40 @@
    * 4銆佹ā鎬佹鎵ц鎴愬姛鍚庢槸鍚﹀叧闂�
    * 5銆侀�氱煡涓诲垪琛ㄥ埛鏂�
    */
-  execSuccess = (res) => {
+  execSuccess = (res = {}) => {
     const { btn } = this.props
     const { btnconfig, autoMatic } = this.state
 
-    if ((res && (res.ErrCode === 'S' || !res.ErrCode)) || autoMatic) { // 鎵ц鎴愬姛
-      notification.success({
-        top: 92,
-        message: res.ErrMesg || this.state.dict['main.action.confirm.success'],
-        duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
-      })
-    } else if (res && res.ErrCode === 'Y') { // 鎵ц鎴愬姛
+    if (res.message && /^@speak@/.test(res.message)) {
+      res.message = res.message.replace('@speak@', '')
+      let val = res.message.match(/<<.*>>/)
+      res.message = res.message.replace(/\s*<<.*>>\s*/g, '')
+      val = val ? val[0].replace(/<<|>>/g, '') : ''
+
+      if (/^http/.test(val)) {
+        let audio = document.createElement('audio')
+        audio.src = val
+        audio.play()
+      }
+
+      if (!res.message) {
+        res.ErrCode = '-1'
+      }
+    }
+
+    if ((res.ErrCode === 'S' || !res.ErrCode) || autoMatic) { // 鎵ц鎴愬姛
+      if (btn.formType !== 'counter' || res.message) {
+        notification.success({
+          top: 92,
+          message: res.message || '鎵ц鎴愬姛锛�',
+          duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
+        })
+      }
+    } else if (res.ErrCode === 'Y') { // 鎵ц鎴愬姛
       Modal.success({
-        title: res.ErrMesg || this.state.dict['main.action.confirm.success']
+        title: res.message || '鎵ц鎴愬姛锛�'
       })
-    } else if (res && res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
+    } else if (res.ErrCode === '-1') { // 瀹屾垚鍚庝笉鎻愮ず
 
     }
 
@@ -2295,25 +2354,42 @@
     const { btn } = this.props
     const { btnconfig, autoMatic } = this.state
 
+    if (res.message && /^@speak@/.test(res.message)) {
+      res.message = res.message.replace('@speak@', '')
+      let val = res.message.match(/<<.*>>/)
+      res.message = res.message.replace(/\s*<<.*>>\s*/g, '')
+      val = val ? val[0].replace(/<<|>>/g, '') : ''
+
+      if (/^http/.test(val)) {
+        let audio = document.createElement('audio')
+        audio.src = val
+        audio.play()
+      }
+
+      if (!res.message) {
+        res.ErrCode = '-1'
+      }
+    }
+
     if (res.ErrCode === 'E' && !autoMatic) {
       Modal.error({
-        title: res.message || res.ErrMesg,
+        title: res.message || '鎵ц澶辫触锛�',
       })
     } else if (res.ErrCode === 'N' || autoMatic) {
       notification.error({
         top: 92,
-        message: res.message || res.ErrMesg,
+        message: res.message || '鎵ц澶辫触锛�',
         duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
       })
     } else if (res.ErrCode === 'F') {
       notification.error({
         className: 'notification-custom-error',
         top: 92,
-        message: res.message || res.ErrMesg,
+        message: res.message || '鎵ц澶辫触锛�',
         duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
       })
     } else if (res.ErrCode === 'NM') {
-      message.error(res.message || res.ErrMesg)
+      message.error(res.message || '鎵ц澶辫触锛�')
     }
 
     if (autoMatic) {
@@ -2344,7 +2420,7 @@
       MKEmitter.emit('popclose')
     } else if (btn.execError !== 'never') {
       MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.execError, btn, '', this.state.selines)
-    } else if (btn.OpenType === 'form') {
+    } else if (btn.OpenType === 'form' && btn.formType !== 'counter') {
       let data = this.props.selectedData && this.props.selectedData[0] ? this.props.selectedData[0] : null
       this.setState({check: data && data[btn.field] === btn.openVal})
     }
@@ -2390,7 +2466,20 @@
         this.setState({
           visible: true
         })
+
+        if (btnconfig.setting.display === 'modal' && btnconfig.setting.moveable === 'true') {
+          setTimeout(() => {
+            this.setMove()
+          }, 100)
+        }
       }
+    } else if (!btn.$old) {
+      notification.warning({
+        top: 92,
+        message: '鏈幏鍙栧埌鎸夐挳閰嶇疆淇℃伅锛�',
+        duration: 5
+      })
+      this.setState({ loading: false })
     } else {
       Api.getCacheConfig({
         func: 'sPC_Get_LongParam',
@@ -2643,15 +2732,17 @@
         width = btnconfig.setting.width > 100 ? btnconfig.setting.width : btnconfig.setting.width + '%'
         container = () => document.getElementById(btn.ContainerId)
       }
+
       return (
         <Modal
           title={title}
           maskClosable={clickouter}
           getContainer={container}
-          wrapClassName='action-modal'
+          wrapClassName={'action-modal' + (btnconfig.setting.moveable === 'true' ? ' moveable-modal modal-' + btn.uuid : '')}
           visible={visible}
           width={width}
           onOk={this.handleOk}
+          maskStyle={btnconfig.setting.moveable === 'true' ?  {backgroundColor: 'rgba(0, 0, 0, 0.15)'} : null}
           confirmLoading={this.state.confirmLoading}
           onCancel={this.handleCancel}
           destroyOnClose
@@ -2670,15 +2761,59 @@
     }
   }
 
+  setMove = () => {
+    const { btn } = this.props
+    let wrap = document.getElementsByClassName('modal-' + btn.uuid)[0]
+
+    if (!wrap) return
+
+    let node = wrap.getElementsByClassName('ant-modal-header')[0]
+
+    if (!node) return
+
+    node.onmousedown = function(e) {
+      let orileft = 0
+      let oritop = 0
+      let oleft = e.clientX
+      let otop = e.clientY
+
+      if (node.parentNode.style.left) {
+        orileft = parseFloat(node.parentNode.style.left)
+      }
+      if (node.parentNode.style.top) {
+        oritop = parseFloat(node.parentNode.style.top)
+      }
+
+      document.onmousemove = function(e) {
+        let left = e.clientX - oleft
+        let top = e.clientY - otop
+
+        node.parentNode.style.left = (orileft + left) + 'px'
+        node.parentNode.style.top = (oritop + top) + 'px'
+      }
+    }
+
+    document.onmouseup = function() {
+      document.onmousemove = null
+    }
+  }
+
+  changeCount = (count) => {
+    this.setState({count}, () => {
+      this.actionTrigger()
+    })
+  }
+
   render() {
     const { btn } = this.props
-    const { loadingNumber, loadingTotal, loading, disabled, hidden, check } = this.state
+    const { loadingNumber, loadingTotal, loading, disabled, hidden, check, count } = this.state
 
     if (hidden) return null
-
     if (btn.OpenType === 'form') {
       if (btn.formType === 'switch') { 
         return <Switch loading={loading} checked={check} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} onChange={(val,e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style} className={btn.size === 'large' ? 'ant-switch-large' : ''} size={btn.size} checkedChildren={btn.openText || ''} unCheckedChildren={btn.closeText || ''}/>
+      } else if (btn.formType === 'counter') {
+        return <MkCounter count={count} disabled={disabled} btn={btn} onChange={this.changeCount}/>
       } else if (btn.formType === 'radio') {
         return <Checkbox className={btn.checkType || ''} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} checked={check} onChange={(e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style}></Checkbox>
       } else {
diff --git a/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx b/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx
new file mode 100644
index 0000000..5c0bfe3
--- /dev/null
+++ b/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx
@@ -0,0 +1,116 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { message, InputNumber } from 'antd'
+import { PlusOutlined, MinusOutlined } from '@ant-design/icons'
+
+import './index.scss'
+
+class MkCounter extends Component {
+  static propTpyes = {
+    count: PropTypes.number,
+    btn: PropTypes.object,
+    disabled: PropTypes.any,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    count: 0,
+    orival: 0
+  }
+
+  timer = null
+
+  UNSAFE_componentWillMount() {
+    this.setState({count: this.props.count, orival: this.props.count})
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    this.setState({count: nextProps.count, orival: nextProps.count})
+  }
+
+  minus = () => {
+    const { btn } = this.props
+    const { count } = this.state
+    
+    let val = count - 1
+
+    if (btn.min !== '' && val < btn.min) {
+      message.warning(`涓嶅彲灏忎簬${btn.min}!`)
+      return
+    } else if (btn.max !== '' && val > btn.max) {
+      message.warning(`涓嶅彲澶т簬${btn.max}!`)
+      return
+    }
+
+    this.setState({count: val, orival: val})
+
+    clearTimeout(this.timer)
+
+    this.timer = setTimeout(() => {
+      this.props.onChange(val)
+    }, 1000)
+  }
+
+  plus = () => {
+    const { btn } = this.props
+    const { count } = this.state
+    
+    let val = count + 1
+
+    if (btn.min !== '' && val < btn.min) {
+      message.warning(`涓嶅彲灏忎簬${btn.min}!`)
+      return
+    } else if (btn.max !== '' && val > btn.max) {
+      message.warning(`涓嶅彲澶т簬${btn.max}!`)
+      return
+    }
+
+    this.setState({count: val, orival: val})
+
+    clearTimeout(this.timer)
+
+    this.timer = setTimeout(() => {
+      this.props.onChange(val)
+    }, 1000)
+  }
+
+  submit = () => {
+    const { btn } = this.props
+    const { count, orival } = this.state
+
+    if (count === '') {
+      message.warning(`涓嶅彲涓虹┖!`)
+      this.setState({count: 0})
+      return
+    } else if (btn.min !== '' && count < btn.min) {
+      message.warning(`涓嶅彲灏忎簬${btn.min}!`)
+      return
+    } else if (btn.max !== '' && count > btn.max) {
+      message.warning(`涓嶅彲澶т簬${btn.max}!`)
+      return
+    }
+
+    if (orival === count) return
+
+    clearTimeout(this.timer)
+
+    this.timer = setTimeout(() => {
+      this.props.onChange(count)
+    }, 1000)
+  }
+
+  render() {
+    const { btn, disabled } = this.props
+    const { count } = this.state
+
+    return (
+      <div onClick={(e) => e.stopPropagation()} className={'mk-btn-counter ' + (btn.size || '') + (disabled ? ' mk-disabled' : '')} style={btn.style}>
+        <span onClick={this.minus}><MinusOutlined /></span>
+        <span><InputNumber value={count} onChange={(val) => this.setState({count: val})} onBlur={this.submit} onPressEnter={this.submit}/></span>
+        <span onClick={this.plus}><PlusOutlined /></span>
+      </div>
+    )
+  }
+}
+
+export default MkCounter
\ No newline at end of file
diff --git a/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss b/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss
new file mode 100644
index 0000000..b31ba07
--- /dev/null
+++ b/src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss
@@ -0,0 +1,117 @@
+.mk-btn-counter {
+  position: relative;
+  display: inline-block;
+  white-space: nowrap;
+  border: 1px solid #d9d9d9;
+  font-size: 14px;
+  border-radius: 2px;
+  width: auto!important;
+  max-width: auto!important;
+  background: #ffffff;
+  overflow: hidden;
+
+  >span {
+    display: inline-block;
+    height: 20px;
+    line-height: 22px;
+    vertical-align: top;
+    text-align: center;
+  }
+  >span:first-child {
+    position: relative;
+    width: 22px;
+    text-align: center;
+    font-size: 12px;
+    cursor: pointer;
+  }
+  >span:first-child:after {
+    content: ' ';
+    display: inline-block;
+    width: 1px;
+    height: 26px;
+    background-color: #d9d9d9;
+    position: absolute;
+    right: 0px;
+  }
+  >span:nth-child(2) {
+    width: 42px;
+    .ant-input-number {
+      border: none;
+      border-radius: 0;
+      height: auto;
+      box-shadow: none!important;
+      .ant-input-number-handler-wrap {
+        display: none;
+      }
+      .ant-input-number-input {
+        padding: 0;
+        height: auto;
+        text-align: center;
+      }
+    }
+  }
+  >span:last-child {
+    position: relative;
+    width: 22px;
+    text-align: center;
+    font-size: 12px;
+    cursor: pointer;
+  }
+  >span:last-child::before {
+    content: ' ';
+    display: inline-block;
+    width: 1px;
+    height: 26px;
+    background-color: #d9d9d9;
+    position: absolute;
+    left: 0px;
+  }
+}
+.mk-btn-counter.mk-disabled .ant-input-number-input {
+  color: #bcbcbc !important;
+}
+.mk-btn-counter.mk-disabled::after {
+  content: ' ';
+  display: block;
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+}
+.mk-btn-counter.small {
+  font-size: 12px;
+  >span {
+    height: 18px;
+    line-height: 19px;
+  }
+  >span:first-child {
+    width: 20px;
+    font-size: 10px;
+  }
+  >span:nth-child(2) {
+    width: 38px;
+  }
+  >span:last-child {
+    width: 20px;
+    font-size: 10px;
+  }
+}
+.mk-btn-counter.large {
+  font-size: 16px;
+  >span {
+    height: 24px;
+    line-height: 25px;
+  }
+  >span:first-child {
+    width: 26px;
+    font-size: 13px;
+  }
+  >span:nth-child(2) {
+    width: 48px;
+  }
+  >span:last-child {
+    width: 26px;
+    font-size: 13px;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/actionList/popupbutton/index.jsx b/src/tabviews/zshare/actionList/popupbutton/index.jsx
index 4449ae5..c07cf91 100644
--- a/src/tabviews/zshare/actionList/popupbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -36,31 +36,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({disabled, hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -77,36 +57,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -118,6 +74,43 @@
     MKEmitter.removeListener('openNewTab', this.openNewTab)
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
     MKEmitter.removeListener('refreshPopButton', this.refreshPopButton)
+  }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
   }
   
   /**
@@ -348,7 +341,7 @@
           className={className}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{label}</Button>
-        <span onClick={(e) => {e.stopPropagation()}}>{this.getPop()}</span>
+        <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 1f9b31a..c8302d8 100644
--- a/src/tabviews/zshare/actionList/printbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -45,31 +45,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -89,36 +69,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({disabled, hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -128,6 +84,43 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
     MKEmitter.removeListener('triggerBtnPopSubmit', this.triggerBtnPopSubmit)
+  }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
   }
 
   triggerBtnPopSubmit = (id) => {
@@ -321,6 +314,16 @@
 
           // 鑷畾涔夋墦鍗�
           if (btn.verify.printMode === 'custom') {
+            result.list.forEach(cell => {
+              Object.keys(cell).forEach(key => {
+                let _key = key.toLowerCase()
+                if (['printtype', 'printcount'].includes(_key)) {
+                  cell[_key] = cell[key]
+                }
+              })
+              cell.printType = cell.printtype || ''
+              cell.printCount = +(cell.printcount || 1)
+            })
             this.execCustomPrint(result.list, formdata)
             resolve(false)
             return
@@ -1121,6 +1124,8 @@
     _customScript = _customScript.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
     _dataresource = _dataresource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
     _customScript = _customScript.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    _dataresource = _dataresource.replace(/@typename@/ig, `'admin'`)
+    _customScript = _customScript.replace(/@typename@/ig, `'admin'`)
 
 
     let LText = ''
@@ -2003,7 +2008,20 @@
         this.setState({
           visible: true
         })
+
+        if (btnconfig.setting.display === 'modal' && btnconfig.setting.moveable === 'true') {
+          setTimeout(() => {
+            this.setMove()
+          }, 100)
+        }
       }
+    } else if (!btn.$old) {
+      notification.warning({
+        top: 92,
+        message: '鏈幏鍙栧埌鎸夐挳閰嶇疆淇℃伅锛�',
+        duration: 5
+      })
+      this.setState({ loading: false })
     } else {
       Api.getCacheConfig({
         func: 'sPC_Get_LongParam',
@@ -2198,10 +2216,11 @@
         title={title}
         maskClosable={clickouter}
         getContainer={container}
-        wrapClassName='action-modal'
+        wrapClassName={'action-modal' + (btnconfig.setting.moveable === 'true' ? ' moveable-modal modal-' + btn.uuid : '')}
         visible={this.state.visible}
         confirmLoading={this.state.confirmLoading}
         width={width}
+        maskStyle={btnconfig.setting.moveable === 'true' ?  {backgroundColor: 'rgba(0, 0, 0, 0.15)'} : null}
         onOk={this.handleOk}
         onCancel={this.handleCancel}
         destroyOnClose
@@ -2219,6 +2238,43 @@
     )
   }
 
+  setMove = () => {
+    const { btn } = this.props
+    let wrap = document.getElementsByClassName('modal-' + btn.uuid)[0]
+
+    if (!wrap) return
+
+    let node = wrap.getElementsByClassName('ant-modal-header')[0]
+
+    if (!node) return
+
+    node.onmousedown = function(e) {
+      let orileft = 0
+      let oritop = 0
+      let oleft = e.clientX
+      let otop = e.clientY
+
+      if (node.parentNode.style.left) {
+        orileft = parseFloat(node.parentNode.style.left)
+      }
+      if (node.parentNode.style.top) {
+        oritop = parseFloat(node.parentNode.style.top)
+      }
+
+      document.onmousemove = function(e) {
+        let left = e.clientX - oleft
+        let top = e.clientY - otop
+
+        node.parentNode.style.left = (orileft + left) + 'px'
+        node.parentNode.style.top = (oritop + top) + 'px'
+      }
+    }
+
+    document.onmouseup = function() {
+      document.onmousemove = null
+    }
+  }
+
   render() {
     const { btn } = this.props
     const { loading, disabled, hidden } = this.state
diff --git a/src/tabviews/zshare/actionList/tabbutton/index.jsx b/src/tabviews/zshare/actionList/tabbutton/index.jsx
index c4b2567..fbdfe15 100644
--- a/src/tabviews/zshare/actionList/tabbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -27,31 +27,11 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { btn, selectedData, BData } = this.props
-    let disabled = false
+    const { btn, selectedData, BData, disabled } = this.props
 
-    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-      selectedData.forEach(item => {
-        let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          disabled = true
-        }
-      })
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent') {
-      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (this.props.disabled || disabled) {
+    if (btn.controlField) {
+      this.setStatus(btn, selectedData || [], BData, disabled)
+    } else if (disabled) {
       this.setState({disabled: true})
     }
   }
@@ -65,36 +45,12 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { btn, selectedData, BData } = this.props
+    const { btn } = this.props
 
-    let disabled = false
-    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
-      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
-        nextProps.selectedData.forEach(item => {
-          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
-          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-            disabled = true
-          }
-        })
-      }
-      this.setState({hidden: disabled && btn.control === 'hidden'})
-    } else if (btn.control === 'parent' && !is(fromJS(nextProps.BData || {}), fromJS(BData || {}))) {
-      if (!nextProps.BData || !nextProps.BData.hasOwnProperty(btn.controlField)) {
-        this.setState({hidden: true})
-      } else {
-        let s = nextProps.BData[btn.controlField] + ''
-        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
-          this.setState({hidden: true})
-        } else {
-          this.setState({hidden: false})
-        }
-      }
-    }
-
-    if (nextProps.disabled || disabled) {
-      this.setState({disabled: true})
+    if (btn.controlField) {
+      this.setStatus(btn, nextProps.selectedData || [], nextProps.BData, nextProps.disabled)
     } else {
-      this.setState({disabled: false})
+      this.setState({disabled: nextProps.disabled === true})
     }
   }
 
@@ -104,6 +60,43 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
   }
+
+  setStatus = (btn, data, BData, disprop) => {
+    let disabled = false
+    let hidden = false
+
+    if (btn.control !== 'parent') {
+      if (data.length > 0) {
+        data.forEach(item => {
+          let s = item[btn.controlField] !== undefined ? item[btn.controlField] + '' : ''
+          if (btn.controlVals.includes(s)) {
+            disabled = true
+          }
+        })
+      } else if (btn.controlVals.includes('')) {
+        disabled = true
+      }
+    } else {
+      if (!BData || !BData.hasOwnProperty(btn.controlField)) {
+        hidden = true
+      } else {
+        let s = BData[btn.controlField] + ''
+        if (btn.controlVals.includes(s)) {
+          hidden = true
+        }
+      }
+    }
+
+    if (disabled && btn.control === 'hidden') {
+      hidden = true
+    }
+
+    if (disprop) {
+      disabled = true
+    }
+
+    this.setState({hidden, disabled})
+  }
   
   /**
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx
index e69e00d..a1ea659 100644
--- a/src/tabviews/zshare/mutilform/index.jsx
+++ b/src/tabviews/zshare/mutilform/index.jsx
@@ -27,6 +27,7 @@
 const MKColor = asyncComponent(() => import('./mkColor'))
 const MkFormula = asyncComponent(() => import('./mkFormula'))
 const MkCascader = asyncComponent(() => import('./mkCascader'))
+const MkVercode = asyncComponent(() => import('./mkVercode'))
 const MKEditor = asyncComponent(() => import('@/components/editor'))
 
 class MainSearch extends Component {
@@ -41,6 +42,10 @@
 
   state = {
     formlist: [],    // 琛ㄥ崟椤�
+    ID: '',
+    send_type: '',
+    timestamp: '',
+    n_id: ''
   }
 
   record = {}
@@ -99,6 +104,12 @@
         delete item.style.marginRight
       }
 
+      if (item.type === 'split' && item.splitctrl) {
+        if (data.hasOwnProperty(item.splitctrl.toLowerCase()) && data[item.splitctrl.toLowerCase()] === '') {
+          return false
+        }
+      }
+
       if (item.type === 'split' || item.type === 'formula') return true
       if (item.type === 'hint') {
         if (item.field && data[item.field.toLowerCase()]) {
@@ -113,7 +124,7 @@
         item.precision = 'second'
       }
 
-      if (!item.field || !['text', 'number', 'switch', 'rate', 'select', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color'].includes(item.type)) return false
+      if (!item.field || !['text', 'number', 'switch', 'rate', 'select', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color', 'vercode'].includes(item.type)) return false
 
       if (/^\s+$/.test(item.label)) {
         item.style = item.style || {}
@@ -160,6 +171,10 @@
           })
         }
         item.oriOptions = fromJS(item.options).toJS()
+
+        if (item.empty === 'hidden' && item.oriOptions.length === 0) {
+          item.hidden = true
+        }
       }
 
       let newval = '$empty'
@@ -350,7 +365,7 @@
             message: formRule.input.formMessage.replace('@max', item.fieldlength)
           }
         ]
-      } else if (item.type === 'linkMain') {
+      } else if (item.type === 'linkMain' || item.type === 'vercode') {
         item.rules = [
           {
             required: item.required === 'true',
@@ -448,17 +463,19 @@
         item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.value === '')
       }
 
-      if (['select', 'link', 'radio'].includes(item.type) && item.resourceType === '0') { // 閫変腑绗竴椤�
+      if (['select', 'link', 'radio'].includes(item.type)) { // 閫変腑绗竴椤�
         if (typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) {
-          item.initval = item.options[0] ? item.options[0].value : ''
+          item.$first = true
+          item.initval = ''
+        }
+        if (item.resourceType === '0') { // 閫変腑绗竴椤�
+          if (item.$first) {
+            item.initval = item.options[0] ? item.options[0].value : ''
+          }
         }
       }
 
-      if (typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) {
-        record[item.field] = ''
-      } else {
-        record[item.field] = item.initval
-      }
+      record[item.field] = item.initval
 
       if (linkFields[item.field]) {
         item.linkFields = linkFields[item.field]
@@ -506,7 +523,7 @@
 
     this.record = record
 
-    this.setState({ formlist }, () => {
+    this.setState({ formlist, ID: this.props.data ? this.props.data.$$uuid || '' : '' }, () => {
       if (unload) return
       
       if (action.setting && action.setting.focus && fieldMap.has(action.setting.focus)) {
@@ -537,13 +554,17 @@
     let cache = action.setting.cache !== 'false'
     let debug = window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')
 
-    let _sql = `Declare @mk_organization nvarchar(512)  select @mk_organization='${sessionStorage.getItem('organization') || ''}'\n`
+    let _sql = `Declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)  select @mk_departmentcode='${sessionStorage.getItem('departmentcode') || ''}',@mk_organization='${sessionStorage.getItem('organization') || ''}',@mk_user_type='${sessionStorage.getItem('mk_user_type') || ''}'\n`
     let _sso = _sql
 
     deForms.forEach(item => {
       if (item.database === 'sso') {
         let sql = _sso + item.base_sql
         _sso = ''
+
+        sql = sql.replace(/@ID@/ig, `'${this.state.ID || ''}'`)
+        sql = sql.replace(/@BID@/ig, `'${BID}'`)
+
         if (debug) {
           console.info(sql)
         }
@@ -551,6 +572,10 @@
       } else {
         let sql = _sql + item.base_sql
         _sql = ''
+
+        sql = sql.replace(/@ID@/ig, `'${this.state.ID || ''}'`)
+        sql = sql.replace(/@BID@/ig, `'${BID}'`)
+
         if (debug) {
           console.info(sql)
         }
@@ -564,8 +589,7 @@
       LText: localItems.join(' union all '),
       obj_name: '',
       arr_field: '',
-      table_type: 'Y',
-      BID: BID || ''
+      table_type: 'Y'
     }
 
     if (param.LText) {
@@ -599,8 +623,7 @@
       LText: mainItems.join(' union all '),
       obj_name: '',
       arr_field: '',
-      table_type: 'Y',
-      BID: BID || ''
+      table_type: 'Y'
     }
 
     if (mainparam.LText) {
@@ -653,16 +676,18 @@
   improveSimpleActionForm = (deForms) => {
     let cache = this.props.action.setting.cache !== 'false'
     let debug = window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')
-    let _sql = `Declare @mk_organization nvarchar(512)  select @mk_organization='${sessionStorage.getItem('organization') || ''}'\n`
+    let _sql = `Declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)  select @mk_departmentcode='${sessionStorage.getItem('departmentcode') || ''}',@mk_organization='${sessionStorage.getItem('organization') || ''}',@mk_user_type='${sessionStorage.getItem('mk_user_type') || ''}'\n`
 
     let deffers = deForms.map((form, index) => {
       let param = {
         func: 'sPC_Get_SelectedList',
         LText: _sql + form.base_sql,
         obj_name: form.field,
-        arr_field: form.arr_field,
-        BID: this.props.BID || ''
+        arr_field: form.arr_field
       }
+
+      param.LText = param.LText.replace(/@ID@/ig, `'${this.state.ID || ''}'`)
+      param.LText = param.LText.replace(/@BID@/ig, `'${this.props.BID || ''}'`)
 
       if (debug) {
         console.info(param.LText)
@@ -775,7 +800,7 @@
           item.options = item.oriOptions
         }
 
-        if (['select', 'link', 'radio'].includes(item.type) && typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) { // 閫変腑绗竴椤�
+        if (['select', 'link', 'radio'].includes(item.type) && item.$first) { // 閫変腑绗竴椤�
           item.initval = item.options[0] ? item.options[0].value : ''
           this.record[item.field] = item.initval
         }
@@ -794,6 +819,10 @@
               reFieldsVal[n.field] = option[n.field]
             })
           }
+        }
+
+        if (item.empty === 'hidden' && item.oriOptions.length > 0) {
+          item.hidden = false
         }
       }
       
@@ -945,6 +974,8 @@
           content = (<MKTextArea config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})}/>)
         } else if (item.type === 'rate') {
           content = (<Rate count={item.rateCount} disabled={item.readonly} style={{color: item.color || '#fadb14'}} onChange={(val) => this.recordChange({[item.field]: val})} character={item.character ? <MkIcon type={item.character}/> : <StarFilled />} allowHalf={item.allowHalf}/>)
+        } else if (item.type === 'vercode') {
+          content = (<MkVercode config={item} record={this.record} onSend={(send_type, timestamp, n_id) => this.setState({send_type, timestamp, n_id})} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit}/>)
         } else if (item.type === 'brafteditor') {
           content = (<MKEditor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
           label = item.hidelabel !== 'true' ? label : ''
@@ -976,7 +1007,7 @@
   }
 
   handleConfirm = () => {
-    const { formlist } = this.state
+    const { formlist, send_type, timestamp, n_id } = this.state
 
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     return new Promise((resolve, reject) => {
@@ -985,7 +1016,7 @@
           reject(err)
           return
         }
-        let search = []
+        let forms = []
         let record = {...this.record, ...values}
 
         formlist.forEach(item => {
@@ -1027,12 +1058,40 @@
             if (item.declareType === 'nvarchar(50)') {
               _item.type = 'text'
             }
+          } else if (item.type === 'vercode') {
+            _item.type = 'text'
+            forms.push({
+              type: 'text',
+              readin: false,
+              writein: false,
+              fieldlen: 50,
+              key: 'mk_timestamp',
+              value: timestamp || ''
+            })
+
+            forms.push({
+              type: 'text',
+              readin: false,
+              writein: false,
+              fieldlen: 50,
+              key: 'mk_send_type',
+              value: send_type || ''
+            })
+
+            forms.push({
+              type: 'text',
+              readin: false,
+              writein: false,
+              fieldlen: 50,
+              key: 'mk_n_id',
+              value: n_id || ''
+            })
           }
     
-          search.push(_item)
+          forms.push(_item)
         })
 
-        resolve(search)
+        resolve(forms)
       })
     })
   }
diff --git a/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
index 58acdce..154b7bd 100644
--- a/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
@@ -23,8 +23,11 @@
     let config = fromJS(this.props.config).toJS()
 
     let selectKeys = config.initval
+    let initlength = 0
     if (config.multiple === 'true') {
       selectKeys = config.initval ? config.initval.split(',') : []
+      initlength = selectKeys.length
+      selectKeys = this.filterVals(config.options, selectKeys)
     }
 
     if (!config.selectStyle && config.backgroundColor) {
@@ -44,6 +47,10 @@
       config: config,
       options: fromJS(config.options).toJS(),
       selectKeys: selectKeys
+    }, () => {
+      if (config.multiple === 'true' && selectKeys.length < initlength) {
+        this.props.onChange(selectKeys.join(','))
+      }
     })
   }
 
@@ -60,9 +67,20 @@
   }
 
   UNSAFE_componentWillReceiveProps (nextProps) {
-    const { config } = this.state
+    const { config, selectKeys } = this.state
 
     if (!is(fromJS(config.oriOptions), fromJS(nextProps.config.oriOptions))) {
+      if (config.multiple === 'true') {
+        let keys = this.filterVals(nextProps.config.options, fromJS(selectKeys).toJS())
+        if (keys.length < selectKeys.length) {
+          this.setState({
+            selectKeys: keys
+          }, () => {
+            this.props.onChange(keys.join(','))
+          })
+        }
+      }
+
       this.setState({
         config: {...config, oriOptions: nextProps.config.oriOptions},
         options: fromJS(nextProps.config.options).toJS()
@@ -77,6 +95,16 @@
     MKEmitter.removeListener('mkFP', this.mkFormHandle)
   }
 
+  filterVals = (options, vals) => {
+    if (options.length === 0 || vals.length === 0) return vals
+
+    let ops = options.map(item => item.$value)
+
+    vals = vals.filter(val => ops.includes(val))
+
+    return vals
+  }
+
   mkFormHandle = (uuid, parentId, level) => {
     if (uuid !== this.state.config.uuid) return
 
diff --git a/src/tabviews/zshare/mutilform/mkInput/index.jsx b/src/tabviews/zshare/mutilform/mkInput/index.jsx
index 7bd5605..2092679 100644
--- a/src/tabviews/zshare/mutilform/mkInput/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkInput/index.jsx
@@ -131,6 +131,10 @@
     const { config } = this.props
     const { value } = this.state
 
+    if (config.inputType === 'password') {
+      return <Input.Password ref={this.inputRef} className="mk-form-input" placeholder={config.placeholder || ''} value={value} autoComplete="off" disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleInputSubmit}/>
+    }
+
     return <Input ref={this.inputRef} className="mk-form-input" allowClear placeholder={config.placeholder || ''} value={value} autoComplete="off" disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleInputSubmit} />
   }
 }
diff --git a/src/tabviews/zshare/mutilform/mkInput/index.scss b/src/tabviews/zshare/mutilform/mkInput/index.scss
index 21a1344..7161e2d 100644
--- a/src/tabviews/zshare/mutilform/mkInput/index.scss
+++ b/src/tabviews/zshare/mutilform/mkInput/index.scss
@@ -1,4 +1,4 @@
-.mk-form-input {
+.mk-form-input:not(.ant-input-password) {
   .ant-input-suffix {
     opacity: 0;
     transition: opacity 0.3s;
diff --git a/src/tabviews/zshare/mutilform/mkRadio/index.jsx b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
index 9bb5800..a541852 100644
--- a/src/tabviews/zshare/mutilform/mkRadio/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
@@ -52,7 +52,7 @@
         options: fromJS(nextProps.config.options).toJS()
       })
 
-      if (typeof(config.initval) === 'string' && config.initval.indexOf('$first') > -1) {
+      if (config.$first) {
         this.setState({
           value: nextProps.config.initval,
         })
diff --git a/src/tabviews/zshare/mutilform/mkSelect/index.jsx b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
index 821fb89..c46e4ed 100644
--- a/src/tabviews/zshare/mutilform/mkSelect/index.jsx
+++ b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -57,7 +57,7 @@
         options: fromJS(nextProps.config.options).toJS()
       })
 
-      if (typeof(config.initval) === 'string' && config.initval.indexOf('$first') > -1) {
+      if (config.$first) {
         this.setState({
           value: nextProps.config.initval,
         })
diff --git a/src/tabviews/zshare/mutilform/mkVercode/index.jsx b/src/tabviews/zshare/mutilform/mkVercode/index.jsx
new file mode 100644
index 0000000..ae8fb99
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkVercode/index.jsx
@@ -0,0 +1,220 @@
+import React, { Component } from 'react'
+import { is, fromJS } from 'immutable'
+import { Input, Button, message } from 'antd'
+import md5 from 'md5'
+import moment from 'moment'
+
+import Api from '@/api'
+import MKEmitter from '@/utils/events.js'
+
+// import './index.scss'
+
+/**
+ * @description 鑷畾涔夋枃鏈緭鍏�
+ */
+class MkVercode extends Component {
+  constructor(props) {
+    super(props)
+    
+    this.state = {
+      value: ''
+    }
+  }
+  
+  inputRef = React.createRef()
+  timer = null
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  handleChange = (e) => {
+    let val = e.target.value
+    val = val.replace(/\n/g, '')
+
+    this.props.onChange(val)
+    this.setState({value: val})
+
+    if (val.length === 6) {
+      setTimeout(() => {
+        this.handleInputSubmit()
+      }, 50)
+    }
+  }
+
+  handleInputSubmit = () => {
+    const { config } = this.props
+
+    if (config.enter === 'false') return
+    if (config.enter === 'tab') {
+      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+    } else {
+      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+      this.props.onSubmit()
+    }
+  }
+
+  getvercode = () => {
+    const { record, config } = this.props
+    let _phone = record[config.phoneField] || ''
+
+    if (!_phone) {
+      message.warning('璇疯緭鍏ユ墜鏈哄彿锛�')
+      return
+    } else if (!/^1[3456789]\d{9}$/.test(_phone)) {
+      message.warning('鎵嬫満鍙锋牸寮忛敊璇紝璇烽噸濉紒')
+      return
+    }
+
+    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    let send_type = 'web_no'
+    let n_id = (() => {
+      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
+    })()
+
+    this.setState({
+      verdisabled: true,
+      delay: 60
+    })
+    this.timer = setTimeout(this.resetVerCodeDelay, 1000)
+
+    if (config.sendType === 'sso') {
+      send_type = 'web'
+      n_id = ''
+
+      let _param = {
+        func: 'mes_sms_send_code_sso',
+        send_type: send_type,
+        mob: _phone,
+        ID: config.smsId,
+        LText: 'minke',
+        timestamp: timestamp,
+      }
+
+      _param.secretkey = md5(`${_param.LText}mingke${_param.timestamp}`)
+  
+      Api.getSystemConfig(_param).then(res => {
+        if (!res.status || !res.n_id) {
+          clearTimeout(this.timer)
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+          message.warning(res.message || '楠岃瘉鐮佽幏鍙栧け璐ワ紒')
+          return
+        }
+
+        n_id = res.n_id
+  
+        let param = {
+          func: 'MSN_sms_send_code',
+          send_type: send_type,
+          mob: _phone,
+          timestamp: timestamp,
+          ID: config.smsId,
+          n_id: res.n_id
+        }
+    
+        param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
+        param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
+  
+        param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
+        param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+        param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+    
+        Api.genericInterface(param).then(res => {
+          if (!res.status) {
+            clearTimeout(this.timer)
+            this.setState({
+              verdisabled: false,
+              delay: null
+            })
+            message.warning(res.message)
+          } else {
+            this.props.onSend(send_type, timestamp, n_id)
+          }
+        }, () => {
+          clearTimeout(this.timer)
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+        })
+      })
+    } else {
+      let param = {
+        func: 'MSN_sms_send_code',
+        send_type: send_type,
+        mob: _phone,
+        timestamp: timestamp,
+        ID: config.smsId,
+        n_id: n_id
+      }
+  
+      param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
+      param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
+
+      param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
+      param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+      param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+  
+      Api.genericInterface(param).then(res => {
+        if (!res.status) {
+          clearTimeout(this.timer)
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+          message.warning(res.message)
+        } else {
+          this.props.onSend(send_type, timestamp, n_id)
+        }
+      }, () => {
+        clearTimeout(this.timer)
+        this.setState({
+          verdisabled: false,
+          delay: null
+        })
+      })
+    }
+  }
+
+  resetVerCodeDelay = () => {
+    const { delay } = this.state
+    if (delay && delay > 1) {
+      this.setState({delay: delay - 1})
+      this.timer = setTimeout(this.resetVerCodeDelay, 1000)
+    } else {
+      this.setState({
+        verdisabled: false,
+        delay: null
+      })
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { value, verdisabled, delay } = this.state
+
+    return <Input ref={this.inputRef} className="mk-form-input" allowClear placeholder={config.placeholder || ''} value={value} autoComplete="off" disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleInputSubmit} addonAfter={
+      <Button type="link" disabled={verdisabled} style={{padding: 0, minWidth: '70px'}} size="small" onClick={this.getvercode}>
+        {delay ? `${delay}s` : '鑾峰彇楠岃瘉鐮�'}
+      </Button>
+    }/>
+  }
+}
+
+export default MkVercode
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkVercode/index.scss b/src/tabviews/zshare/mutilform/mkVercode/index.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkVercode/index.scss
diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx
index 0ef8ec8..e08b2cb 100644
--- a/src/tabviews/zshare/normalTable/index.jsx
+++ b/src/tabviews/zshare/normalTable/index.jsx
@@ -1214,7 +1214,7 @@
 
   render() {
     const { setting, pickup, statFValue } = this.props
-    const { selectedRowKeys, lineMarks, activeIndex, pageOptions } = this.state
+    const { selectedRowKeys, lineMarks, activeIndex, pageOptions, columns } = this.state
 
     let components = {
       body: {}
@@ -1276,14 +1276,14 @@
     }
 
     return (
-      <div className={'normal-data-table mingke-table ' + (height ? 'fixed-height' : '')}>
+      <div className={'normal-data-table mingke-table ' + (height ? 'fixed-height' : '') + ` table-col-${columns.length}`}>
         <Table
           components={components}
           size={setting.size || 'middle'}
           style={style}
           bordered={setting.bordered !== 'false'}
           rowSelection={rowSelection}
-          columns={this.state.columns}
+          columns={columns}
           dataSource={_data}
           rowClassName={(record) => {
             let className = ''
diff --git a/src/tabviews/zshare/tablenodes/index.jsx b/src/tabviews/zshare/tablenodes/index.jsx
index df97bc4..f46b98d 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 } from 'antd'
+import { Modal, Button, notification, Spin, Input, Typography, message } from 'antd'
 
 import Api from '@/api'
 import G6 from "@antv/g6"
@@ -166,6 +166,7 @@
               id: 'par' + i,
               direction: 'left',
               color: '#5AD8A6',
+              node: 'table',
               children: []
             }
 
@@ -345,6 +346,44 @@
         ev.preventDefault();
       },
     });
+
+    G6.registerBehavior('dice-mindmap', {
+      getEvents() {
+        return {
+          'node:dblclick': 'editNode',
+        };
+      },
+      editNode(evt) {
+        const item = evt.item;
+        const model = item.get('model');
+
+        // 閫変腑鑺傜偣
+        this.graph.getNodes().forEach(node => {
+          let _model = node.get('model')
+          if (_model.fontcolor === '#1890ff') {
+            _model.fontcolor = ''
+            this.graph.updateItem(node, _model, false)
+          }
+        })
+
+        if (model.direction === 'left') {
+          if (model.node === 'table') {
+            model.fontcolor = '#1890ff'
+            this.graph.updateItem(item, model, false)
+
+            let oInput = document.createElement('input')
+            oInput.value = model.label
+            document.body.appendChild(oInput)
+            oInput.select()
+            document.execCommand('Copy')
+            document.body.removeChild(oInput)
+            
+            message.success('琛ㄥ悕澶嶅埗鎴愬姛銆�')
+          }
+          return
+        }
+      }
+    });
     
     const dataTransform = (data) => {
       const changeData = (d, level = 0, color) => {
@@ -420,7 +459,8 @@
             },
           },
           'drag-canvas',
-          'zoom-canvas'
+          'zoom-canvas',
+          'dice-mindmap'
         ],
       },
     });
diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx
index 85fbb90..8f1b7d4 100644
--- a/src/tabviews/zshare/topSearch/index.jsx
+++ b/src/tabviews/zshare/topSearch/index.jsx
@@ -77,6 +77,7 @@
         _setting.labelwidth = config.wrap.searchLwidth !== undefined ? config.wrap.searchLwidth : 33.3
         _setting.labelCol = {style: {width: _setting.labelwidth + '%'}}
         _setting.wrapperCol = {style: {width: (100 - _setting.labelwidth) + '%'}}
+        _setting.borderRadius = config.wrap.borderRadius
       }
       _setting.style = null
       
@@ -552,6 +553,11 @@
     })
 
     if (setting.show || setting.showAdv) {
+      let style = {}
+      if (setting.borderRadius) {
+        style.borderRadius = setting.borderRadius
+      }
+
       fields.push(
         <Col span={setting.ratio} style={{ whiteSpace: 'nowrap' }} className="mk-search-col search-button" key="actions">
           <Form.Item
@@ -560,10 +566,10 @@
             labelCol={setting.labelCol}
             wrapperCol={setting.wrapperCol}
           >
-            {setting.show ? <Button type="primary" onClick={this.handleSubmit}>
+            {setting.show ? <Button style={style} type="primary" onClick={this.handleSubmit}>
               鎼滅储
             </Button> : null}
-            {setting.show ? <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
+            {setting.show ? <Button style={{ marginLeft: 8, ...style }} onClick={this.handleReset}>
               閲嶇疆
             </Button> : null}
             {setting.showAdv ? <Button className={visible ? 'visible' : ''} type="link" onClick={this.handleAdvance}>
diff --git a/src/templates/calendarconfig/index.jsx b/src/templates/calendarconfig/index.jsx
index 2284223..2bb9117 100644
--- a/src/templates/calendarconfig/index.jsx
+++ b/src/templates/calendarconfig/index.jsx
@@ -422,19 +422,19 @@
         return
       }
 
-      let tabParam = { // 娣诲姞鑿滃崟tab椤�
-        func: 'sPC_sMenusTab_AddUpt',
-        MenuID: menu.MenuID
-      }
+      // let tabParam = { // 娣诲姞鑿滃崟tab椤�
+      //   func: 'sPC_sMenusTab_AddUpt',
+      //   MenuID: menu.MenuID
+      // }
 
-      if (_config.tab) {
-        tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'${_config.tab.linkTab}' as Tabid,'${_config.tab.label}' as TabName ,'0' as Sort`)
-      } else {
-        tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`)
-      }
+      // if (_config.tab) {
+      //   tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'${_config.tab.linkTab}' as Tabid,'${_config.tab.label}' as TabName ,'0' as Sort`)
+      // } else {
+      //   tabParam.LText = Utils.formatOptions(`select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`)
+      // }
 
-      tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
+      // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
 
       let _vals = this.getFuncNames(_config.funcs, [], [])
       let _tables = Array.from(new Set(_vals.table))
@@ -478,41 +478,14 @@
           this.setState({
             config: _config,
             openEdition: response.open_edition || '',
-            originMenu: fromJS(_config).toJS()
+            originMenu: fromJS(_config).toJS(),
+            menuloading: false,
+            menucloseloading: false
           }, () => {
             reload && MKEmitter.emit('revert')
           })
 
           this.props.reloadmenu()
-
-          // 鏍囩淇℃伅淇濆瓨
-          Api.getSystemConfig(tabParam).then(result => {
-            if (result.status) {
-              notification.success({
-                top: 92,
-                message: '淇濆瓨鎴愬姛',
-                duration: 2
-              })
-              if (this.state.closeVisible) {
-                this.handleViewBack()
-              } else {
-                this.setState({
-                  menuloading: false,
-                  menucloseloading: false
-                })
-              }
-            } else {
-              notification.warning({
-                top: 92,
-                message: result.message,
-                duration: 5
-              })
-              this.setState({
-                menuloading: false,
-                menucloseloading: false
-              })
-            }
-          })
 
           localParam.func = 'sPC_TrdMenu_AddUpt_For_Local'
           delete localParam.LongParam
@@ -523,6 +496,16 @@
           delete localParam.open_edition
 
           Api.genericInterface(localParam)
+
+          notification.success({
+            top: 92,
+            message: '淇濆瓨鎴愬姛',
+            duration: 2
+          })
+          
+          if (this.state.closeVisible) {
+            this.handleViewBack()
+          }
         } else {
           this.setState({
             menuloading: false,
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index 2f79d57..62ac181 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/src/templates/comtableconfig/index.jsx
@@ -58,7 +58,6 @@
     delActions: [],          // 鍒犻櫎鎸夐挳鍒楄〃
     copyActions: [],         // 澶嶅埗鎸夐挳缁�
     tabviews: [],            // 鎵�鏈夋爣绛鹃〉
-    thawButtons: [],         // 宸查�夋嫨瑕佽В鍐荤殑鎸夐挳
     activeKey: '0',          // 榛樿灞曞紑鍩烘湰淇℃伅
     chartview: null,         // 褰撳墠瑙嗗浘
     openEdition: '',         // 缂栬緫鐗堟湰鏍囪锛岄槻姝㈠浜烘搷浣�
@@ -294,7 +293,7 @@
    */
   submitConfig = () => {
     const { menu } = this.props
-    const { delActions, thawButtons, openEdition } = this.state
+    const { delActions, openEdition } = this.state
 
     let _config = fromJS(this.state.config).toJS()
 
@@ -380,7 +379,7 @@
     }
 
     let _sort = 0
-    let btntabs = []
+    // let btntabs = []
 
     let btnParam = {             // 娣诲姞鑿滃崟鎸夐挳
       func: 'sPC_Button_AddUpt',
@@ -396,14 +395,14 @@
     _config.action.forEach(item => {
       if (item.hidden === 'true') return
       _sort++
-      if (item.OpenType === 'popview') {
-        btntabs.push({
-          uuid: item.uuid,
-          linkTab: item.linkTab,
-          label: item.label,
-          sort: _sort
-        })
-      }
+      // if (item.OpenType === 'popview') {
+      //   btntabs.push({
+      //     uuid: item.uuid,
+      //     linkTab: item.linkTab,
+      //     label: item.label,
+      //     sort: _sort
+      //   })
+      // }
       
       btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
     })
@@ -413,33 +412,33 @@
     btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
     btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
     
-    let tabParam = { // 娣诲姞鑿滃崟tab椤�
-      func: 'sPC_sMenusTab_AddUpt',
-      MenuID: menu.MenuID
-    }
+    // let tabParam = { // 娣诲姞鑿滃崟tab椤�
+    //   func: 'sPC_sMenusTab_AddUpt',
+    //   MenuID: menu.MenuID
+    // }
 
-    let _LText = []
+    // let _LText = []
 
-    btntabs.forEach(item => {
-      _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
-    })
-    _config.tabgroups.forEach(group => {
-      group.sublist.forEach(item => {
-        _sort++
-        _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
-      })
-    })
+    // btntabs.forEach(item => {
+    //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
+    // })
+    // _config.tabgroups.forEach(group => {
+    //   group.sublist.forEach(item => {
+    //     _sort++
+    //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
+    //   })
+    // })
 
-    _LText = _LText.join(' union all ')
+    // _LText = _LText.join(' union all ')
 
     // 娓呯┖鑿滃崟涓嬪叧鑱旂殑鏍囩
-    if (!_LText) {
-      _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
-    }
+    // if (!_LText) {
+    //   _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
+    // }
 
-    tabParam.LText = Utils.formatOptions(_LText)
-    tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
+    // tabParam.LText = Utils.formatOptions(_LText)
+    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
 
     let _vals = this.getFuncNames(_config)
 
@@ -538,26 +537,7 @@
       }).then(resp => {
         if (resp === false) return
 
-        if (thawButtons.length > 0) {
-          let defers = thawButtons.map(item => {
-            return new Promise((resolve) => {
-              Api.getSystemConfig({
-                func: 'sPC_MainMenu_ReDel',
-                MenuID: item
-              }).then(res => {
-                if (res.status) {
-                  resolve('')
-                } else {
-                  resolve(res.message)
-                }
-              })
-            })
-          })
-
-          return Promise.all(defers)
-        } else {
-          return true
-        }
+        return true
       }).then(res => {
         if (res === true || res === false) return res
 
@@ -570,9 +550,6 @@
           })
           return false
         } else {
-          this.setState({
-            thawButtons: []
-          })
           return true
         }
       }).then(resp => {
@@ -596,7 +573,7 @@
             delete localParam.EasyCode
             delete localParam.open_edition
 
-            this.submitAction(btnParam, tabParam, localParam)
+            this.submitAction(btnParam, localParam)
           } else {
             this.setState({
               menuloading: false,
@@ -616,52 +593,29 @@
   /**
    * @description 淇濆瓨鎴栦慨鏀硅彍鍗曟寜閽泦
    */
-  submitAction = (btnParam, tabParam, localParam) => {
+  submitAction = (btnParam, localParam) => {
     const { config } = this.state
 
     new Promise(resolve => {
-      let deffers = []
-
-      let defer = new Promise(resolve => {
-        Api.getSystemConfig(tabParam).then(result => {
-          resolve(result)
-        })
-      })
-      deffers.push(defer)
-
       if (btnParam.LText) {
-        let defer = new Promise(resolve => {
-          Api.getSystemConfig(btnParam).then(result => {
-            if (result.status) {
-              this.setState({ // 淇濆瓨鎴愬姛鍚庢竻绌哄鍒跺垪琛�
-                copyActions: []
-              })
-            }
+        Api.getSystemConfig(btnParam).then(result => {
+          if (result.status) {
+            this.setState({ // 淇濆瓨鎴愬姛鍚庢竻绌哄鍒跺垪琛�
+              copyActions: []
+            })
             resolve(result)
-          })
-        })
-        deffers.push(defer)
-      }
-
-      Promise.all(deffers).then(result => {
-        let error = false
-        result.forEach(res => {
-          if (!res.status) {
-            error = res
+          } else {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+            resolve(false)
           }
         })
-
-        if (error) {
-          notification.warning({
-            top: 92,
-            message: error.message,
-            duration: 5
-          })
-          resolve(false)
-        } else {
-          resolve(true)
-        }
-      })
+      } else {
+        resolve(true)
+      }
     }).then(response => {
       if (response === false) return response
 
@@ -1024,7 +978,6 @@
    */
   editConfig = (res) => {
     this.setState({
-      thawButtons: res.thawButtons,
       config: res.config
     })
   }
@@ -1250,7 +1203,7 @@
                 <Unattended config={config} updateConfig={this.updateconfig}/>
                 <Versions MenuId={menu.MenuID} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                 <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
-                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/>
+                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} refresh={this.editConfig}/>
                 <UpdateTable config={config}/>
                 <Switch className="big" checkedChildren="鍚�" unCheckedChildren="鍋�" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                 <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>淇濆瓨</Button>
diff --git a/src/templates/comtableconfig/updatetable/index.jsx b/src/templates/comtableconfig/updatetable/index.jsx
index 8aaf83b..ffe2380 100644
--- a/src/templates/comtableconfig/updatetable/index.jsx
+++ b/src/templates/comtableconfig/updatetable/index.jsx
@@ -705,21 +705,13 @@
       _resolve()
 
       if (res.status) {
-        notification.success({
-          top: 92,
-          message: '鍗囩骇鎴愬姛',
-          duration: 2
-        })
-
         delete urlparam.type
         delete urlparam.MenuType
 
         let _param = window.btoa(window.encodeURIComponent(JSON.stringify(urlparam)))
 
-        setTimeout(() => {
-          window.history.replaceState(null, null, window.location.href.split('#')[0] + `#/tabledesign/${_param}`)
-          window.location.reload()
-        }, 2000)
+        window.history.replaceState(null, null, window.location.href.split('#')[0] + `#/tabledesign/${_param}`)
+        window.location.reload()
       } else {
         Modal.warning({
           title: res.message,
@@ -821,6 +813,7 @@
           if (m.signType === 'line') {
             lineMarks.push({
               $index: lineMarks.length + 1,
+              uuid: Utils.getuuid(),
               field: field,
               color: color,
               contrastValue: m.contrastValue || '',
@@ -830,6 +823,7 @@
           } else {
             _col.marks.push({
               $index: _col.marks.length + 1,
+              uuid: Utils.getuuid(),
               field: field,
               color: color,
               contrastValue: m.contrastValue || '',
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index 028b214..a3e43f0 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/src/templates/formtabconfig/index.jsx
@@ -364,7 +364,6 @@
 
     _inputfields = _formfields.filter(item => ['text', 'number', 'textarea', 'color'].includes(item.type) && card.field !== item.field)
     _tabfields = _formfields.filter(item => card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
-    _tabfields.unshift({field: '', text: '鍘熻〃鍗�'})
     
     if (card.linkSubField && card.linkSubField.length > 0) {
       let fields = _inputfields.map(item => item.field)
@@ -380,12 +379,12 @@
         uniq.set(item.field, true)
 
         _linkableFields.push({
-          value: item.field,
-          text: item.label + ' (琛ㄥ崟)'
+          field: item.field,
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
-          value: item.field,
-          text: item.label
+          field: item.field,
+          label: item.label
         })
       }
     })
@@ -396,8 +395,8 @@
           uniq.set(col.field, true)
 
           _linkableFields.push({
-            value: col.field,
-            text: col.label + ' (鏄剧ず鍒�)'
+            field: col.field,
+            label: col.label + '-鏄剧ず鍒�'
           })
         }
       })
@@ -519,7 +518,7 @@
           let param = {
             func: 's_debug_sql',
             exec_type: 'y',
-            LText: `declare @mk_organization nvarchar(512)
+            LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
               ${res.dataSource}`
           }
 
@@ -952,26 +951,26 @@
         btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
         btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
         
-        let tabParam = { // 娣诲姞鑿滃崟tab椤�
-          func: 'sPC_sMenusTab_AddUpt',
-          MenuID: btnTab.uuid
-        }
+        // let tabParam = { // 娣诲姞鑿滃崟tab椤�
+        //   func: 'sPC_sMenusTab_AddUpt',
+        //   MenuID: btnTab.uuid
+        // }
         
-        let _LText = []
+        // let _LText = []
 
-        config.tabgroups.forEach(group => {
-          group.sublist.forEach(item => {
-            _sort++
-            _LText.push(`select '${btnTab.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
-          })
-        })
+        // config.tabgroups.forEach(group => {
+        //   group.sublist.forEach(item => {
+        //     _sort++
+        //     _LText.push(`select '${btnTab.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
+        //   })
+        // })
 
-        _LText = _LText.join(' union all ')
+        // _LText = _LText.join(' union all ')
 
-        tabParam.LText = Utils.formatOptions(_LText)
+        // tabParam.LText = Utils.formatOptions(_LText)
 
-        tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-        tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
+        // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+        // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
   
         let param = {
           func: 'sPC_ButtonParam_AddUpt',
@@ -1043,7 +1042,7 @@
                 originMenu: _config
               })
     
-              this.submitAction(btnParam, tabParam)
+              this.submitAction(btnParam)
             } else {
               this.setState({
                 menuloading: false,
@@ -1070,43 +1069,14 @@
   /**
    * @description 淇濆瓨鎴栦慨鏀硅彍鍗曟寜閽�
    */
-  submitAction = (btnParam, tabParam) => {
+  submitAction = (btnParam) => {
     new Promise(resolve => {
-      let deffers = []
-
-      if (tabParam.LText) {
-        let defer = new Promise(resolve => {
-          Api.getSystemConfig(tabParam).then(result => {
-            resolve(result)
-          })
-        })
-        deffers.push(defer)
-      }
-
       if (btnParam.LText) {
-        let defer = new Promise(resolve => {
-          Api.getSystemConfig(btnParam).then(result => {
-            resolve(result)
-          })
-        })
-        deffers.push(defer)
-      }
-
-      if (deffers.length === 0) {
-        resolve(true)
-      } else {
-        Promise.all(deffers).then(result => {
-          let error = false
-          result.forEach(res => {
-            if (!res.status) {
-              error = res
-            }
-          })
-
-          if (error) {
+        Api.getSystemConfig(btnParam).then(result => {
+          if (!result.status) {
             notification.warning({
               top: 92,
-              message: error.message,
+              message: result.message,
               duration: 5
             })
             resolve(false)
@@ -1114,8 +1084,15 @@
             resolve(true)
           }
         })
+      } else {
+        resolve(true)
       }
     }).then(response => {
+      this.setState({
+        menuloading: false,
+        menucloseloading: false
+      })
+
       if (response) {
         notification.success({
           top: 92,
@@ -1124,17 +1101,7 @@
         })
         if (this.state.closeVisible) {
           this.handleViewBack()
-        } else {
-          this.setState({
-            menuloading: false,
-            menucloseloading: false
-          })
         }
-      } else {
-        this.setState({
-          menuloading: false,
-          menucloseloading: false
-        })
       }
     })
   }
diff --git a/src/templates/modalconfig/dragelement/card.jsx b/src/templates/modalconfig/dragelement/card.jsx
index d4dc506..dad19c1 100644
--- a/src/templates/modalconfig/dragelement/card.jsx
+++ b/src/templates/modalconfig/dragelement/card.jsx
@@ -135,6 +135,12 @@
     formItem = <div style={{marginTop: '8px', color: 'rgba(0, 0, 0, 0.85)', lineHeight: '1.5', ...card.style}}>{card.formula}{card.postfix || ''}</div>
   } else if (card.type === 'split') {
     formItem = <div className="split-line" style={card.style}>{card.label}</div>
+  } else if (card.type === 'vercode') {
+    formItem = <Input style={{marginTop: '4px'}} placeholder={card.placeholder || ''} value={card.initval} addonAfter={
+      <Button type="link" style={{padding: 0}} size="small">
+        鑾峰彇楠岃瘉鐮�
+      </Button>
+    }/>
   } else if (card.type === 'checkcard') {
     className += ' checkcard'
     formItem = <CheckCard config={card} />
diff --git a/src/templates/modalconfig/dragelement/index.jsx b/src/templates/modalconfig/dragelement/index.jsx
index fcfb770..3cd1b5a 100644
--- a/src/templates/modalconfig/dragelement/index.jsx
+++ b/src/templates/modalconfig/dragelement/index.jsx
@@ -103,6 +103,8 @@
 
       if (item.subType === 'linkMain') {
         newcard.hidden = 'true'
+      } else if (item.subType === 'textarea') {
+        newcard.required = 'false'
       }
 
       let targetId = ''
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index 7ec9759..b4d6d8b 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/src/templates/modalconfig/index.jsx
@@ -249,35 +249,28 @@
     let index = null
     uniq.set(card.field, true)
 
-    let _inputIndex = 1
-    let _tabIndex = 1
-    let _linkIndex = 1
     config.fields.forEach((item, i) => {
       if (card.uuid === item.uuid) {
         index = i
       }
 
-      let label = `${item.field || ''}锛�${item.label}锛塦
-
       if (['text', 'number', 'textarea', 'color'].includes(item.type) && card.field !== item.field) {
         _inputfields.push({
           field: item.field,
-          label: _inputIndex + '銆�' + label
+          label: item.label
         })
-        _inputIndex++
       }
       if (card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type)) {
         _tabfields.push({
           field: item.field,
-          label: _tabIndex + '銆�' + label
+          label: item.label
         })
-        _tabIndex++
       }
 
       if (item.type === 'switch') {
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
       }
 
@@ -288,17 +281,14 @@
 
         _linkableFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + item.label + ' (琛ㄥ崟)'
+          label: item.label + '-琛ㄥ崟'
         })
         _linksupFields.push({
           field: item.field,
-          label: _linkIndex + '銆�' + label
+          label: item.label
         })
-        _linkIndex++
       }
     })
-
-    _tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
 
     if (index !== null) {
       if (index === 0) {
@@ -315,9 +305,8 @@
 
           _linkableFields.push({
             field: col.field,
-            label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+            label: col.label + '-鏄剧ず鍒�'
           })
-          _linkIndex++
         }
       })
     } else if (tabConfig) {
@@ -327,9 +316,8 @@
 
           _linkableFields.push({
             field: col.field,
-            label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+            label: col.label + '-鏄剧ず鍒�'
           })
-          _linkIndex++
         }
       })
     } else if (menu.LongParam) {
@@ -339,9 +327,8 @@
 
           _linkableFields.push({
             field: col.field,
-            label: _linkIndex + '銆�' + col.label + ' (鏄剧ず鍒�)'
+            label: col.label + '-鏄剧ず鍒�'
           })
-          _linkIndex++
         }
       })
     }
@@ -412,7 +399,7 @@
         let param = {
           func: 's_debug_sql',
           exec_type: 'y',
-          LText: `declare @mk_organization nvarchar(512)
+          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
             ${res.dataSource}`
         }
 
@@ -745,7 +732,6 @@
       onCancel() {}
     })
   }
-
 
   render () {
     const { editAction } = this.props
diff --git a/src/templates/modalconfig/settingform/index.jsx b/src/templates/modalconfig/settingform/index.jsx
index e3b7b22..b459117 100644
--- a/src/templates/modalconfig/settingform/index.jsx
+++ b/src/templates/modalconfig/settingform/index.jsx
@@ -111,7 +111,12 @@
             </Form.Item>
           </Col> */}
           <Col span={24}>
-            <Form.Item label="鏄剧ず鏂瑰紡">
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鍙�夋嫨琛ㄥ崟鐨勬樉绀哄舰寮忥紝娉細鏍囩鎵撳嵃鎸夐挳锛屾殏涓嶆敮鎸佷互鎶藉眽鏄剧ず琛ㄥ崟銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鏄剧ず鏂瑰紡
+              </Tooltip>
+            }>
               {getFieldDecorator('display', {
                 initialValue: display || 'modal'
               })(
@@ -134,6 +139,18 @@
             }>
               {getFieldDecorator('width', {
                 initialValue: config.setting.width || (appType !== 'mob' ? 60 : 100)
+              })(<InputNumber min={10} max={2000} precision={0} onPressEnter={this.handleSubmit}/>)}
+            </Form.Item>
+          </Col> : null}
+          {display === 'dialog' && appType === 'mob' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="灏忎簬100鏃朵负鐧惧垎鐜囷紝澶т簬100鏃朵负缁濆鍊笺�傜┖鍊兼椂瀹藉害鑷�傚簲銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                瀹藉害
+              </Tooltip>
+            }>
+              {getFieldDecorator('width', {
+                initialValue: config.setting.width || ''
               })(<InputNumber min={10} max={2000} precision={0} onPressEnter={this.handleSubmit}/>)}
             </Form.Item>
           </Col> : null}
@@ -335,6 +352,23 @@
               )}
             </Form.Item>
           </Col> : null}
+          {!appType && display === 'modal' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鏄惁鍙嫋鎷界Щ鍔ㄦā鎬佹銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鍙Щ鍔�
+              </Tooltip>
+            }>
+              {getFieldDecorator('moveable', {
+                initialValue: config.setting.moveable || 'false'
+              })(
+                <Radio.Group>
+                  <Radio value="false">鍚�</Radio>
+                  <Radio value="true">鏄�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
         </Row>
       </Form>
     )
diff --git a/src/templates/modalconfig/source.jsx b/src/templates/modalconfig/source.jsx
index 7c81e6e..58be363 100644
--- a/src/templates/modalconfig/source.jsx
+++ b/src/templates/modalconfig/source.jsx
@@ -179,6 +179,11 @@
     type: 'form',
     label: '鍏紡',
     subType: 'formula',
+  },
+  {
+    type: 'form',
+    label: '楠岃瘉鐮�',
+    subType: 'vercode',
   }
 ]
 
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
index 3c505eb..f599ffb 100644
--- a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -18,7 +18,7 @@
   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'],
-  excelOut: ['label', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search', 'hidden'],
+  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search', 'hidden'],
   popview: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose', 'display', 'ratio', 'clickouter', 'hidden'],
   tab: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'linkmenu', 'hidden'],
   innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position', 'hidden'],
@@ -238,6 +238,7 @@
       }
     } else if (openType === 'excelOut') {
       reOptions.intertype = this.state.interTypeOptions.filter(op => op.value !== 'custom')
+      reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredOnce'].includes(op.value))
 
       if (this.record.intertype === 'outer') {
         shows.push('innerFunc', 'sysInterface', 'interface', 'outerFunc')
@@ -255,6 +256,9 @@
       } else if (this.record.intertype === 'inner') {
         shows.push('innerFunc')
         reRequired.innerFunc = true
+      }
+      if (this.record.Ot !== 'notRequired' && this.record.Ot !== 'requiredOnce') {
+        this.record.Ot = 'notRequired'
       }
     } else if (openType === 'popview') {
       reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
@@ -323,7 +327,7 @@
       reOptions.Ot = requireOptions.filter(op => op.value === 'requiredSgl')
     }
     
-    if (Ot !== 'notRequired') {
+    if (Ot !== 'notRequired' && openType !== 'excelOut') {
       reOptions.control = [
         { value: '', text: '鏃�' },
         { value: 'disabled', text: '绂佺敤' },
@@ -393,6 +397,7 @@
         _fieldval.label = '瀵煎嚭Excel'
         _fieldval.class = 'dgreen'
         _fieldval.execSuccess = 'never'
+        _fieldval.Ot = 'notRequired'
         this.record.Ot = 'notRequired'
         this.record.label = '瀵煎嚭Excel'
         this.record.class = 'dgreen'
@@ -689,7 +694,7 @@
           values.position = values.position || 'toolbar'
 
           if (values.OpenType === 'excelOut') {
-            values.Ot = 'notRequired'
+            values.Ot = values.Ot || 'notRequired'
           } else if (values.OpenType === 'popview' && !values.linkTab) { // 娌℃湁鍏宠仈鏍囩锛堟柊寤烘椂锛夛紝鍒涘缓鏂版爣绛綢d
             values.linkTab = Utils.getuuid()
           } else if (['pop', 'prompt', 'exec'].includes(values.OpenType) && values.verify) {
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
index 5973e2d..249c732 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -249,7 +249,6 @@
       col.required = col.required || 'true'
       col.type = col.type || 'Nvarchar(50)'
       col.import = col.import || 'true'
-      col.required = col.required || 'true'
 
       if (col.type === 'text' || col.type === 'image') {
         col.type = 'Nvarchar(50)'
@@ -365,7 +364,7 @@
 
     let _columns = JSON.parse(JSON.stringify(verify.columns))
 
-    let _cols = _columns.map(col => col.Column )
+    let _cols = _columns.map(col => col.Column)
 
     columns.forEach(col => {
       if (col.field && !_cols.includes(col.field)) {
@@ -455,6 +454,13 @@
     const { verify } = this.state
 
     columns = columns.map(col => {
+      col.type = col.type || 'Nvarchar(50)'
+      if (col.type === 'text' || col.type === 'image') {
+        col.type = 'Nvarchar(50)'
+      } else if (col.type === 'number') {
+        col.type = 'Decimal(18,2)'
+      }
+
       if (/^Nvarchar/ig.test(col.type)) {
         col.limit = col.type.match(/\d+/) ? col.type.match(/\d+/)[0] : '20000'
       } else if (/^Decimal/ig.test(col.type)) {
@@ -465,6 +471,9 @@
       } else {
         col.limit = ''
       }
+
+      col.required = col.required || 'true'
+      col.import = col.import || 'true'
 
       return col
     })
@@ -753,13 +762,18 @@
             <Form {...formItemLayout}>
               <Row gutter={24}>
                 <Col span={8}>
-                  <Form.Item label="琛ㄥ悕">
+                  <Form.Item label={
+                    <Tooltip placement="bottomLeft" title="瀵煎叆鏃跺伐浣滆〃鍚嶄笌excel涓繀椤讳竴鑷达紝娉細宸ヤ綔琛ㄥ悕涓篠heet1涓攅xcel涓粎鏈変竴涓伐浣滆〃鏃朵笉杩涜琛ㄥ悕楠岃瘉銆�">
+                      <QuestionCircleOutlined className="mk-form-tip" />
+                      宸ヤ綔琛�
+                    </Tooltip>
+                  }>
                     {getFieldDecorator('sheet', {
                       initialValue: verify.sheet || '',
                       rules: [
                         {
                           required: true,
-                          message: '璇疯緭鍏ヨ〃鍚�!'
+                          message: '璇疯緭鍏ュ伐浣滆〃鍚�!'
                         }
                       ]
                     })(<Input placeholder="" autoComplete="off" />)}
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
index 7e27b64..09adfd9 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -272,7 +272,7 @@
           </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</span></Tooltip>,&nbsp;
+              <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}
               {linefields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'琛ㄥ崟鍙婅鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞惰祴鍊笺��'}>,&nbsp;{linefields}</Tooltip> : null}
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
index 557bf84..0159b4e 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, Tooltip, notification } from 'antd'
+import { Form, Row, Col, Input, Radio, Tooltip, notification, InputNumber } from 'antd'
 import { QuestionCircleOutlined } from '@ant-design/icons'
 
 import Utils from '@/utils/utils.js'
@@ -199,6 +199,13 @@
               </Form.Item>
             </Col> : null}
             {dataType === 'custom' && defaultSql === 'true' ? <Col className="short-label" span={8}>
+              <Form.Item label="涓婚敭">
+                {getFieldDecorator('primaryKey', {
+                  initialValue: setting.primaryKey || 'ID',
+                })(<Input placeholder={''} autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {dataType === 'custom' && defaultSql === 'true' ? <Col className="short-label" span={8}>
               <Form.Item label="鎺掑簭鏂瑰紡">
                 {getFieldDecorator('order', {
                   initialValue: setting.order || '',
@@ -227,6 +234,46 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
+            {btnType !== 'print' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="瀵煎嚭excel涓伐浣滆〃鍚嶇О锛岄粯璁や负Sheet1銆�">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  宸ヤ綔琛�
+                </Tooltip>
+              }>
+                {getFieldDecorator('sheet', {
+                  initialValue: setting.sheet || ''
+                })(<Input placeholder="" autoComplete="off" />)}
+              </Form.Item>
+            </Col> : null}
+            {btnType !== 'print' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="瀵煎嚭excel涓殑琛岄珮銆�">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  琛岄珮
+                </Tooltip>
+              }>
+                {getFieldDecorator('rowHeight', {
+                  initialValue: setting.rowHeight || ''
+                })(<InputNumber min={10} max={200} precision={0} />)}
+              </Form.Item>
+            </Col> : null}
+            {btnType !== 'print' ? <Col span={8}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="璇峰皢闇�瑕佸悎骞剁殑琛ㄥご浣跨敤涓í绾垮垎闅旓紙濡傦細鍟嗗搧-鏁伴噺銆佸晢鍝�-鍗曚环锛夛紝鍓嶉儴鍒嗗皢浣滀负涓昏〃澶达紝鍚庨儴鍒嗗皢浣滀负瀛愯〃澶淬��">
+                  <QuestionCircleOutlined className="mk-form-tip" />
+                  琛ㄥご鍚堝苟
+                </Tooltip>
+              }>
+                {getFieldDecorator('merge', {
+                  initialValue: setting.merge || 'false'
+                })(
+                <Radio.Group>
+                  <Radio value="false">鍚�</Radio>
+                  <Radio value="true">鏄�</Radio>
+                </Radio.Group>)}
+              </Form.Item>
+            </Col> : null}
           </Row>
         </Form>
       </div>
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
index 8f566d2..76e6878 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -785,6 +785,31 @@
       columns.push(cell)
     })
 
+    if (config.subtype === 'dualdatacard') {
+      config.subColumns.forEach(item => {
+        if (fields.includes(item.field) || !item.field) return
+        fields.push(item.field)
+  
+        let cell = {
+          Column: item.field,
+          Text: item.label,
+          Width: 20,
+          abs: 'false',
+          output: 'true',
+          required: 'false',
+          type: 'text',
+          uuid: Utils.getuuid()
+        }
+  
+        if (item.type === 'number') {
+          cell.type = 'number'
+          cell.decimal = item.decimal
+        }
+  
+        columns.push(cell)
+      })
+    }
+
     this.setState({
       verify: {...verify, columns: columns}
     })
@@ -811,22 +836,37 @@
   changeColumns = (columns) => {
     const { verify } = this.state
 
-    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',
-        }
+    columns = columns.map(col => {
+      col.type = col.type || 'text'
+      col.output = col.output || 'true'
+      col.required = col.required || 'false'
 
-        return _cell
-      })
-    }
+      if (!['text', 'image', 'number'].includes(col.type)) {
+        if (/^Decimal/ig.test(col.type)) {
+          col.type = 'number'
+        } else {
+          col.type = 'text'
+        }
+      }
+
+      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}})
   }
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
index 306c80d..6e71f40 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -45,8 +45,8 @@
       _dataresource = ''
     }
     
-    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
-    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
+    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${timestamp}'`)
+    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${timestamp}'`)
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx b/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
index 0e8275c..19c1db3 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
@@ -23,8 +23,8 @@
       _dataresource = ''
     }
     
-    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
-    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
+    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${timestamp}'`)
+    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${timestamp}'`)
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
index f39eecc..d4eb344 100644
--- a/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/editcard/index.jsx
@@ -22,7 +22,9 @@
           _type = 'text'
         }
       } else if (props.type === 'form') {
-        if (_type !== 'number') {
+        if (_type === 'datetime' || _type === 'date') {
+          _type = 'date'
+        } else if (_type !== 'number') {
           _type = 'text'
         }
       }
diff --git a/src/templates/sharecomponent/fieldscomponent/index.jsx b/src/templates/sharecomponent/fieldscomponent/index.jsx
index 41a9a0a..0aa6042 100644
--- a/src/templates/sharecomponent/fieldscomponent/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -169,10 +169,12 @@
 
       this.props.updatefield(items)
     } else if (type === 'form') {
-      let lastItem = config.fields[config.fields.length - 1]
+      let firstItem = config.fields[0]
       let span = this.state.appType === 'mob' ? 24 : 12
-      if (lastItem && lastItem.span) {
-        span = lastItem.span
+      let labelwidth = 33.3
+      if (firstItem && firstItem.span) {
+        span = firstItem.span
+        labelwidth = firstItem.labelwidth || 33.3
       }
       selectCards.forEach(item => { // 寰幆娣诲姞鏂板瀛楁
         let newcard = {
@@ -183,7 +185,7 @@
           type: item.type,
           resourceType: '0',
           span: span,
-          labelwidth: 33.3,
+          labelwidth: labelwidth,
           options: [],
           dataSource: '',
           decimal: item.decimal,
@@ -194,18 +196,21 @@
 
         if (item.type === 'text' && item.length >= 256) {
           newcard.type = 'textarea'
+          newcard.required = 'false'
           newcard.fieldlength = item.length
-          if (lastItem && lastItem.type === newcard.type) {
-            newcard.span = lastItem.span
-            newcard.labelwidth = lastItem.labelwidth
-          } else if (lastItem) {
-            newcard.span = 24
-            if (lastItem.span === 12) {
-              newcard.labelwidth = 16.2
-            } else if (lastItem.span === 8) {
-              newcard.labelwidth = 10.5
-            } else if (lastItem.span === 8) {
-              newcard.labelwidth = 7.7
+          if (firstItem) {
+            if (firstItem.type === newcard.type) {
+              newcard.span = firstItem.span
+              newcard.labelwidth = firstItem.labelwidth
+            } else {
+              newcard.span = 24
+              if (firstItem.span === 12) {
+                newcard.labelwidth = 16.2
+              } else if (firstItem.span === 8) {
+                newcard.labelwidth = 10.5
+              } else if (firstItem.span === 6) {
+                newcard.labelwidth = 7.7
+              }
             }
           } else {
             newcard.span = 24
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
index 9f92dd0..fdd7f52 100644
--- a/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
@@ -139,6 +139,10 @@
   let radio = setting.searchRatio || 6
   let labelwidth = setting.searchLwidth !== undefined ? setting.searchLwidth : 33.3
   let advanceType = setting.advanceType || 'modal'
+  let style = {}
+  if (setting.borderRadius) {
+    style.borderRadius = setting.borderRadius
+  }
 
   return (
     <div ref={drop} className="ant-row">
@@ -170,8 +174,8 @@
             </div>
           } trigger="hover">
             <div className="ant-col ant-form-item-control-wrapper">
-              <Button type="primary">鎼滅储</Button>
-              <Button style={{ marginLeft: 8 }}>閲嶇疆</Button>
+              <Button style={style} type="primary">鎼滅储</Button>
+              <Button style={{ marginLeft: 8, ...style }}>閲嶇疆</Button>
               <div style={{position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}}></div>
             </div>
           </Popover>
diff --git a/src/templates/sharecomponent/searchcomponent/settingform/index.jsx b/src/templates/sharecomponent/searchcomponent/settingform/index.jsx
index a131ad6..1adb220 100644
--- a/src/templates/sharecomponent/searchcomponent/settingform/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/settingform/index.jsx
@@ -140,6 +140,18 @@
               })(<InputNumber min={0} max={100} precision={1} onPressEnter={this.props.inputSubmit}/>)}
             </Form.Item>
           </Col>
+          <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鎼滅储鍜岄噸缃寜閽殑鍦嗚銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鎸夐挳鍦嗚
+              </Tooltip>
+            }>
+              {getFieldDecorator('borderRadius', {
+                initialValue: setting.borderRadius || '',
+              })(<InputNumber min={0} precision={0} onPressEnter={this.props.inputSubmit}/>)}
+            </Form.Item>
+          </Col>
         </Row>
       </Form>
     )
diff --git a/src/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx
index 1912281..c47ca6d 100644
--- a/src/templates/subtableconfig/index.jsx
+++ b/src/templates/subtableconfig/index.jsx
@@ -5,7 +5,7 @@
 import HTML5Backend from 'react-dnd-html5-backend'
 import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip, Col } from 'antd'
 import { QuestionCircleOutlined, RedoOutlined } from '@ant-design/icons'
-import moment from 'moment'
+// import moment from 'moment'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -59,7 +59,6 @@
     delActions: [],          // 鍒犻櫎鎸夐挳鍒楄〃
     copyActions: [],         // 澶嶅埗鎸夐挳缁�
     tabviews: [],            // 鎵�鏈夋爣绛鹃〉
-    thawButtons: [],         // 宸查�夋嫨瑕佽В鍐荤殑鎸夐挳
     activeKey: '0',          // 榛樿灞曞紑鍩烘湰淇℃伅
     chartview: null,         // 褰撳墠瑙嗗浘
     openEdition: '',         // 缂栬緫鐗堟湰鏍囪锛岄槻姝㈠浜烘搷浣�
@@ -285,7 +284,7 @@
    * @description 鏍囩椤典繚瀛�
    */
   submitConfig = () => {
-    const { delActions, thawButtons, openEdition } = this.state
+    const { delActions, openEdition } = this.state
     let _config = fromJS(this.state.config).toJS()
     let copyreg = /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/ig
 
@@ -365,41 +364,41 @@
       return
     }
 
-    let btnParam = {
-      func: 'sPC_Button_AddUpt',
-      Type: 40,
-      ParentID: _config.uuid,
-      MenuNo: _config.tabNo,
-      Template: 'SubTable',
-      PageParam: '',
-      LongParam: '',
-      LText: []
-    }
+    // let btnParam = {
+    //   func: 'sPC_Button_AddUpt',
+    //   Type: 40,
+    //   ParentID: _config.uuid,
+    //   MenuNo: _config.tabNo,
+    //   Template: 'SubTable',
+    //   PageParam: '',
+    //   LongParam: '',
+    //   LText: []
+    // }
 
-    let btntabs = []
+    // let btntabs = []
 
-    _config.action.forEach((item, index) => {
-      if (item.hidden === 'true') return
-      if (item.OpenType === 'popview') {
-        btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
-      }
-      btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
-    })
+    // _config.action.forEach((item, index) => {
+    //   if (item.hidden === 'true') return
+    //   if (item.OpenType === 'popview') {
+    //     btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
+    //   }
+    //   btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
+    // })
 
-    btnParam.LText = btnParam.LText.join(' union all ')
-    btnParam.LText = Utils.formatOptions(btnParam.LText)
-    btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
+    // btnParam.LText = btnParam.LText.join(' union all ')
+    // btnParam.LText = Utils.formatOptions(btnParam.LText)
+    // btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    // btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
 
-    let tabParam = { // 娣诲姞鏍囩鎸夐挳tab椤�
-      func: 'sPC_sMenusTab_AddUpt',
-      MenuID: _config.uuid,
-      LText: btntabs.join(' union all ')
-    }
+    // let tabParam = { // 娣诲姞鏍囩鎸夐挳tab椤�
+    //   func: 'sPC_sMenusTab_AddUpt',
+    //   MenuID: _config.uuid,
+    //   LText: btntabs.join(' union all ')
+    // }
 
-    tabParam.LText = Utils.formatOptions(tabParam.LText)
-    tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
+    // tabParam.LText = Utils.formatOptions(tabParam.LText)
+    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
 
     let param = {
       func: 'sPC_Tab_AddUpt',
@@ -478,26 +477,7 @@
     }).then(resp => {
       if (resp === false) return
 
-      if (thawButtons.length > 0) {
-        let defers = thawButtons.map(item => {
-          return new Promise((resolve) => {
-            Api.getSystemConfig({
-              func: 'sPC_MainMenu_ReDel',
-              MenuID: item
-            }).then(res => {
-              if (res.status) {
-                resolve('')
-              } else {
-                resolve(res.message)
-              }
-            })
-          })
-        })
-
-        return Promise.all(defers)
-      } else {
-        return true
-      }
+      return true
     }).then(res => {
       if (res === true || res === false) return res
 
@@ -510,9 +490,6 @@
         })
         return false
       } else {
-        this.setState({
-          thawButtons: []
-        })
         return true
       }
     }).then(resp => {
@@ -530,8 +507,16 @@
               menuloading: false,
               menucloseloading: false
             })
-            this.submitAction(btnParam, tabParam)
+            notification.success({
+              top: 92,
+              message: '淇濆瓨鎴愬姛',
+              duration: 2
+            })
+            if (this.state.closeVisible) {
+              this.handleViewBack()
+            }
           })
+          this.submitAction()
         } else {
           this.setState({
             menuloading: false,
@@ -550,131 +535,56 @@
   /**
    * @description 淇濆瓨鎴栦慨鏀硅彍鍗曟寜閽�
    */
-  submitAction = (btnParam, tabParam) => {
+  submitAction = () => {
     const { config } = this.state
 
-    new Promise(resolve => {
-      let deffers = []
+    let oriActions = []
+    this.state.originActions.forEach(item => {
+      let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 鏌ョ湅鍒濆鍖栨寜閽槸鍚﹀瓨鍦�
+      if (!curBtn) return
+      if (curBtn.OpenType !== item.prebtn.OpenType) return
+      if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
 
-      if (tabParam.LText) {
-        let defer = new Promise(resolve => {
-          Api.getSystemConfig(tabParam).then(result => {
-            resolve(result)
-          })
-        })
-        deffers.push(defer)
-      }
-
-      if (btnParam.LText) {
-        let defer = new Promise(resolve => {
-          Api.getSystemConfig(btnParam).then(result => {
-            if (result.status) {
-              this.setState({ // 淇濆瓨鎴愬姛鍚庢竻绌哄鍒跺垪琛�
-                copyActions: []
-              })
-            }
-            resolve(result)
-          })
-        })
-        deffers.push(defer)
-      }
-
-      if (deffers.length === 0) {
-        resolve(true)
-      } else {
-        Promise.all(deffers).then(result => {
-          let error = false
-          result.forEach(res => {
-            if (!res.status) {
-              error = res
-            }
-          })
-
-          if (error) {
-            notification.warning({
-              top: 92,
-              message: error.message,
-              duration: 5
-            })
-            resolve(false)
-          } else {
-            resolve(true)
-          }
-        })
-      }
-    }).then(response => {
-      if (response === false) return response
-
-      let oriActions = []
-      this.state.originActions.forEach(item => {
-        let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 鏌ョ湅鍒濆鍖栨寜閽槸鍚﹀瓨鍦�
-        if (!curBtn) return
-        if (curBtn.OpenType !== item.prebtn.OpenType) return
-        if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
-
-        oriActions.push({
-          prebtn: item.prebtn,
-          curBtn: curBtn
-        })
+      oriActions.push({
+        prebtn: item.prebtn,
+        curBtn: curBtn
       })
+    })
 
-      if (oriActions.length === 0) return 'true'
+    if (oriActions.length === 0) return
 
-      oriActions.forEach(action => {
-        Api.getSystemConfig({
-          func: 'sPC_Get_LongParam',
-          MenuID: action.prebtn ? action.prebtn.uuid : ''
-        }).then(result => {
-          if (result.status && result.LongParam) {
-            let _LongParam = ''
-  
-            if (result.LongParam) {
-              try {
-                _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
-              } catch (e) {
-                console.warn('Parse Failure')
-                _LongParam = ''
-              }
-            }
+    oriActions.forEach(action => {
+      Api.getSystemConfig({
+        func: 'sPC_Get_LongParam',
+        MenuID: action.prebtn ? action.prebtn.uuid : ''
+      }).then(result => {
+        if (result.status && result.LongParam) {
+          let _LongParam = ''
 
-            if (_LongParam) {
-              let param = {
-                func: 'sPC_ButtonParam_AddUpt',
-                ParentID: config.uuid,
-                MenuID: action.curBtn.uuid,
-                MenuNo: config.tabNo,
-                Template: _LongParam.type,
-                MenuName: action.curBtn.label,
-                PageParam: JSON.stringify({Template: _LongParam.type}),
-                LongParam: result.LongParam
-              }
-              Api.getSystemConfig(param).then(() => {})
+          if (result.LongParam) {
+            try {
+              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+            } catch (e) {
+              console.warn('Parse Failure')
+              _LongParam = ''
             }
           }
-        })
-      })
-      return 'true'
-    }).then(response => {
-      if (response === 'true') {
-        notification.success({
-          top: 92,
-          message: '淇濆瓨鎴愬姛',
-          duration: 2
-        })
-        if (this.state.closeVisible) {
-          this.handleViewBack()
-        } else {
-          this.setState({
-            menuloading: false,
-            menucloseloading: false
-          })
+
+          if (_LongParam) {
+            let param = {
+              func: 'sPC_ButtonParam_AddUpt',
+              ParentID: config.uuid,
+              MenuID: action.curBtn.uuid,
+              MenuNo: config.tabNo,
+              Template: _LongParam.type,
+              MenuName: action.curBtn.label,
+              PageParam: JSON.stringify({Template: _LongParam.type}),
+              LongParam: result.LongParam
+            }
+            Api.getSystemConfig(param).then(() => {})
+          }
         }
-      } else {
-        this.setState({
-          menuloading: false,
-          menucloseloading: false
-        })
-      }
+      })
     })
   }
 
@@ -901,7 +811,6 @@
    */
   updateConfig = (res) => {
     this.setState({
-      thawButtons: res.thawButtons,
       config: res.config
     })
   }
@@ -1090,7 +999,7 @@
               <div>
                 <Versions MenuId={config.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                 <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
-                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} MenuID={config.uuid} thawButtons={this.state.thawButtons} refresh={this.updateConfig}/>
+                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} refresh={this.updateConfig}/>
                 <Switch className="big" checkedChildren="鍚�" unCheckedChildren="鍋�" checked={config.enabled} onChange={this.onEnabledChange} />
                 <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>淇濆瓨</Button>
                 <Button onClick={this.cancelConfig}>杩斿洖</Button>
diff --git a/src/templates/treepageconfig/index.jsx b/src/templates/treepageconfig/index.jsx
index eab9619..f5c1eba 100644
--- a/src/templates/treepageconfig/index.jsx
+++ b/src/templates/treepageconfig/index.jsx
@@ -283,31 +283,31 @@
       return
     }
 
-    let _sort = 0
-    let btntabs = []
+    // let _sort = 0
+    // let btntabs = []
     
-    let tabParam = { // 娣诲姞鑿滃崟tab椤�
-      func: 'sPC_sMenusTab_AddUpt',
-      MenuID: menu.MenuID
-    }
+    // let tabParam = { // 娣诲姞鑿滃崟tab椤�
+    //   func: 'sPC_sMenusTab_AddUpt',
+    //   MenuID: menu.MenuID
+    // }
 
-    let _LText = []
+    // let _LText = []
 
-    btntabs.forEach(item => {
-      _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
-    })
-    _config.tabgroups.forEach(group => {
-      group.sublist.forEach(item => {
-        _sort++
-        _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
-      })
-    })
+    // btntabs.forEach(item => {
+    //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
+    // })
+    // _config.tabgroups.forEach(group => {
+    //   group.sublist.forEach(item => {
+    //     _sort++
+    //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
+    //   })
+    // })
 
-    _LText = _LText.join(' union all ')
+    // _LText = _LText.join(' union all ')
 
-    tabParam.LText = Utils.formatOptions(_LText)
-    tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
+    // tabParam.LText = Utils.formatOptions(_LText)
+    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
 
     let _funcs = []
     let _tables = []
@@ -414,60 +414,22 @@
           this.setState({
             config: _config,
             openEdition: response.open_edition || '',
-            originMenu: fromJS(_config).toJS()
+            originMenu: fromJS(_config).toJS(),
+            menuloading: false,
+            menucloseloading: false
           })
 
-          // 瀛樺湪鏍囩椤垫椂
-          if (tabParam.LText) {
-            Api.getSystemConfig(tabParam).then(result => {
-              if (result.status) {
-                notification.success({
-                  top: 92,
-                  message: '淇濆瓨鎴愬姛',
-                  duration: 2
-                })
+          notification.success({
+            top: 92,
+            message: '淇濆瓨鎴愬姛',
+            duration: 2
+          })
 
-                this.props.reloadmenu()
-                Api.genericInterface(localParam)
+          this.props.reloadmenu()
+          Api.genericInterface(localParam)
 
-                if (this.state.closeVisible) {
-                  this.props.handleView()
-                } else {
-                  this.setState({
-                    menuloading: false,
-                    menucloseloading: false
-                  })
-                }
-              } else {
-                notification.warning({
-                  top: 92,
-                  message: result.message,
-                  duration: 5
-                })
-                this.setState({
-                  menuloading: false,
-                  menucloseloading: false
-                })
-              }
-            })
-          } else {
-            notification.success({
-              top: 92,
-              message: '淇濆瓨鎴愬姛',
-              duration: 2
-            })
-
-            this.props.reloadmenu()
-            Api.genericInterface(localParam)
-
-            if (this.state.closeVisible) {
-              this.props.handleView()
-            } else {
-              this.setState({
-                menuloading: false,
-                menucloseloading: false
-              })
-            }
+          if (this.state.closeVisible) {
+            this.props.handleView()
           }
         } else {
           this.setState({
diff --git a/src/templates/zshare/codemirror/index.jsx b/src/templates/zshare/codemirror/index.jsx
index 24f6872..aa4698f 100644
--- a/src/templates/zshare/codemirror/index.jsx
+++ b/src/templates/zshare/codemirror/index.jsx
@@ -23,6 +23,7 @@
     value: PropTypes.string, // 鍐呭
     mode: PropTypes.any,     // 鍙�夛紝璇█妯″紡锛岄粯璁や负sql
     theme: PropTypes.any,    // 鍙�夛紝涓婚鏍峰紡
+    func: PropTypes.any,     // 缂栬緫瀛樺偍杩囩▼
     onChange: PropTypes.func // 鍐呭鍙樺寲鏃跺洖璋�
   }
 
@@ -38,6 +39,8 @@
   editor = null
 
   UNSAFE_componentWillMount () {
+    const { func } = this.props
+
     let options = {
       lineNumbers: true,
       lineWrapping: true,
@@ -50,6 +53,7 @@
     }
 
     this.setState({
+      style: func ? {fontSize: '14px', lineHeight: '25px'} : {fontSize: '18px', lineHeight: '32px'},
       value: this.props.value || '',
       defaultVal: this.props.value || '',
       options
@@ -146,7 +150,7 @@
   }
 
   render() {
-    const { mode } = this.props
+    const { mode, func } = this.props
     const { defaultVal, options, fullScreen, style, display } = this.state
     const menu = (
       <Menu>
@@ -190,11 +194,11 @@
     )
 
     return (
-      <div className="code-mirror-wrap" style={fullScreen ? style : null}>
+      <div className="code-mirror-wrap" style={fullScreen || func ? style : null}>
         {!mode && !fullScreen ? <FormatPainterOutlined onClick={this.handleFormat}/> : null}
         {!fullScreen ? <FullscreenOutlined onClick={this.fullScreenChange}/> : null}
         {fullScreen ? <FullscreenExitOutlined onClick={this.fullScreenChange}/> : null}
-        {fullScreen ? <Dropdown overlay={menu} placement="bottomRight">
+        {fullScreen || func ? <Dropdown overlayClassName="mk-mirror-font" overlay={menu} placement="bottomRight">
           <FontSizeOutlined />
         </Dropdown> : null}
         {display ? <CodeMirror
diff --git a/src/templates/zshare/codemirror/index.scss b/src/templates/zshare/codemirror/index.scss
index 6444614..2ee7018 100644
--- a/src/templates/zshare/codemirror/index.scss
+++ b/src/templates/zshare/codemirror/index.scss
@@ -87,4 +87,7 @@
       background: #f5f5f5;
     }
   }
+}
+.mk-mirror-font {
+  z-index: 1200!important;
 }
\ No newline at end of file
diff --git a/src/templates/zshare/editcomponent/index.jsx b/src/templates/zshare/editcomponent/index.jsx
index b5672d0..e1443e4 100644
--- a/src/templates/zshare/editcomponent/index.jsx
+++ b/src/templates/zshare/editcomponent/index.jsx
@@ -1,117 +1,23 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Modal, Spin, notification, Button } from 'antd'
-import { UnlockOutlined, SnippetsOutlined } from '@ant-design/icons'
+import { Modal, notification, Button } from 'antd'
+import { SnippetsOutlined } from '@ant-design/icons'
 
-import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import PasteForm from '@/templates/zshare/pasteform'
-import TransferForm from '@/templates/zshare/basetransferform'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 class editComponent extends Component {
   static propTpyes = {
     options: PropTypes.array,
-    MenuID: PropTypes.any,
     config: PropTypes.object,
-    thawButtons: PropTypes.any,
     refresh: PropTypes.func
   }
 
   state = {
-    thawVisible: false,
-    thawbtnlist: null,
-    pasteVisible: false,
-    targetKeys: []
-  }
-
-  /**
-   * @description 瑙e喕鎸夐挳
-   */
-  handleThaw = () => {
-    const { MenuID } = this.props
-
-    this.setState({
-      thawVisible: true,
-      targetKeys: []
-    })
-
-    Api.getSystemConfig({
-      func: 'sPC_Get_FrozenMenu',
-      ParentID: MenuID,
-      TYPE: 40
-    }).then(res => {
-      if (res.status) {
-        let _list = []
-
-        res.data.forEach(menu => {
-          let _conf = ''
-
-          if (menu.ParentParam) {
-            try {
-              _conf = JSON.parse(window.decodeURIComponent(window.atob(menu.ParentParam)))
-            } catch (e) {
-              console.warn('Parse Failure')
-              _conf = ''
-            }
-          }
-
-          if (_conf) {
-            _list.push({
-              key: menu.MenuID,
-              title: menu.MenuName,
-              btnParam: _conf
-            })
-          }
-        })
-
-        this.setState({
-          thawbtnlist: _list
-        })
-      } else {
-        notification.warning({
-          top: 92,
-          message: res.message,
-          duration: 5
-        })
-      }
-    })
-  }
-
-  /**
-   * @description 瑙e喕鎸夐挳鎻愪氦
-   */
-  thawBtnSubmit = () => {
-    const { thawButtons } = this.props
-    const { thawbtnlist, targetKeys } = this.state
-    let config = fromJS(this.props.config).toJS()
-
-    if (targetKeys.length === 0) {
-      notification.warning({
-        top: 92,
-        message: '璇烽�夋嫨瑙e喕鎸夐挳',
-        duration: 5
-      })
-    } else {
-      thawbtnlist.forEach(item => {
-        if (targetKeys.includes(item.key)) {
-          config.action.push(item.btnParam)
-        }
-      })
-
-      this.props.refresh({
-        type: 'thaw',
-        thawButtons: [...thawButtons, ...targetKeys],
-        config: config
-      })
-
-      this.setState({
-        thawVisible: false,
-        targetKeys: []
-      })
-    }
+    visible: false
   }
 
   pasteSubmit = () => {
@@ -176,6 +82,8 @@
         }
         
         this.props.plusFields([res])
+      } else if (res.copyType === 'forms') {
+        this.props.plusFields(res, 'forms')
       } else {
         notification.warning({
           top: 92,
@@ -185,45 +93,23 @@
         return
       }
       this.setState({
-        pasteVisible: false
+        visible: false
       })
     })
   }
 
-  handleMenuClick = e => {
-    if (e.key === 'thaw') {
-      this.handleThaw()
-    } else if (e.key === 'paste') {
-      this.setState({pasteVisible: true})
-    }
-  }
-
   render() {
-    const { MenuID } = this.props
-
     return (
       <div style={{display: 'inline-block'}}>
-        {MenuID ? <Button className="mk-border-green" onClick={this.handleThaw}><UnlockOutlined /> 瑙e喕鎸夐挳</Button> : null}
-        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={() => this.setState({pasteVisible: true})}><SnippetsOutlined /> 绮樿创</Button>
-        {/* 瑙e喕鎸夐挳妯℃�佹 */}
-        <Modal
-          title="瑙e喕鎸夐挳"
-          visible={this.state.thawVisible}
-          onOk={this.thawBtnSubmit}
-          onCancel={() => {this.setState({thawVisible: false, thawbtnlist: null, targetKeys: []})}}
-          destroyOnClose
-        >
-          {!this.state.thawbtnlist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
-          {this.state.thawbtnlist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawbtnlist}/>}
-        </Modal>
+        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={() => this.setState({visible: true})}><SnippetsOutlined /> 绮樿创</Button>
         {/* 鎸夐挳閰嶇疆淇℃伅绮樿创澶嶅埗 */}
         <Modal
           title="绮樿创"
-          visible={this.state.pasteVisible}
+          visible={this.state.visible}
           width={600}
           maskClosable={false}
           onOk={this.pasteSubmit}
-          onCancel={() => {this.setState({pasteVisible: false})}}
+          onCancel={() => {this.setState({visible: false})}}
           destroyOnClose
         >
           <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index 6626b9b..635f5a6 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -1268,7 +1268,7 @@
       key: 'execSuccess',
       label: '鎴愬姛鍚�',
       initVal: card.execSuccess || 'grid',
-      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺��',
+      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -1287,7 +1287,7 @@
       key: 'execError',
       label: '澶辫触鍚�',
       initVal: card.execError || 'never',
-      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺��',
+      tooltip: '閫夋嫨鍒锋柊琛屾椂锛屽鏋滈�夋嫨澶氭潯鏁版嵁浼氬埛鏂拌〃鏍笺�傚闇�璇煶鎾姤璇蜂互@speak@寮�澶达紝鎾姤鍐呭鎴栨枃浠舵斁缃簬<<>>涓��',
       required: true,
       options: [{
         value: 'never',
@@ -2383,7 +2383,7 @@
 /**
  * @description 鑾峰彇琛ㄥ崟閰嶇疆淇℃伅
  * @param {*} card            // 琛ㄥ崟瀵硅薄
- * @param {*} inputfields     // 鍙叧鑱旇〃鍗�
+ * @param {*} inputfields     // 鍙啓鍏ヨ〃鍗�
  * @param {*} tabfields       // 鍙垏鎹㈣〃鍗�
  * @param {*} linkableFields  // 鍙叧鑱旇〃鍗�
  * @param {*} linksupFields   // 涓婄骇琛ㄥ崟
@@ -2407,6 +2407,44 @@
   } else {
     roleList = []
   }
+
+  let msgTemps = sessionStorage.getItem('msgTemplate')
+
+  if (msgTemps) {
+    try {
+      msgTemps = JSON.parse(msgTemps)
+      msgTemps = msgTemps.map(item => {
+        item.value = item.ID
+        item.label = item.SignName + ' - ' + item.TemplateCode
+        return item
+      })
+    } catch (e) {
+      msgTemps = []
+    }
+  } else {
+    msgTemps = []
+  }
+
+  inputfields = inputfields.map((item, index) => {
+    item.label = `${index + 1}銆�${item.field || ''}锛�${item.label}锛塦
+    return item
+  })
+  tabfields = tabfields.map((item, index) => {
+    item.label = `${index + 1}銆�${item.field || ''}锛�${item.label}锛塦
+    return item
+  })
+
+  tabfields.unshift({field: '', label: '鍘熻〃鍗�'})
+
+  linkableFields = linkableFields.map((item, index) => {
+    item.label = `${index + 1}銆�${item.field || ''}锛�${item.label}锛塦
+    return item
+  })
+
+  linksupFields = linksupFields.map((item, index) => {
+    item.label = `${index + 1}銆�${item.field || ''}锛�${item.label}锛塦
+    return item
+  })
   
   let _openType = [{
     value: 'text',
@@ -2477,6 +2515,9 @@
   }, {
     value: 'formula',
     text: '鍏紡'
+  }, {
+    value: 'vercode',
+    text: '楠岃瘉鐮�'
   }]
 
   let _fieldlength = 50
@@ -2539,6 +2580,9 @@
     }, {
       value: 'formula',
       text: '鍏紡'
+    }, {
+      value: 'vercode',
+      text: '楠岃瘉鐮�'
     }]
   }
 
@@ -3365,6 +3409,20 @@
     },
     {
       type: 'radio',
+      key: 'inputType',
+      label: '鍔犲瘑鏄剧ず',
+      initVal: card.inputType || 'text',
+      required: false,
+      options: [{
+        value: 'text',
+        text: '鍚�'
+      }, {
+        value: 'password',
+        text: '鏄�'
+      }]
+    },
+    {
+      type: 'radio',
       key: 'interception',
       label: '鎴彇绌烘牸',
       initVal: card.interception || 'true',
@@ -3423,11 +3481,20 @@
       }]
     },
     {
+      type: 'text',
+      key: 'splitctrl',
+      label: '鎺у埗瀛楁',
+      initVal: card.splitctrl || '',
+      tooltip: '閫夎涓旇涓搴斿瓧娈靛�间负绌烘椂闅愯棌銆�',
+      required: false,
+      options: columns
+    },
+    {
       type: 'radio',
       key: 'place',
       label: '鎺掑垪',
       initVal: card.place || 'left_right',
-      tooltip: '鎻愮ず鏂囧瓧涓庤緭鍏ユ鐨勪綅缃叧绯汇��',
+      tooltip: '鎻愮ず鏂囧瓧涓庤緭鍏ユ鐨勪綅缃叧绯汇�傛敞锛氶�夋嫨鍣ㄣ�佹棩鏈熻〃鍗曞湪琛ㄥ崟鏍峰紡涓洪槾褰辨椂鏈夋晥',
       forbid: appType !== 'mob',
       options: [{
         value: 'left_right',
@@ -3595,6 +3662,38 @@
         value: 'right',
         text: '鍙虫埅'
       }]
+    },
+    {
+      type: 'radio',
+      key: 'sendType',
+      label: '鍙戦�佹柟寮�',
+      initVal: card.sendType || 'local',
+      tooltip: '鐭俊鍙戦�佹椂鏄惁閫氳繃鍗曠偣绯荤粺銆�',
+      required: false,
+      options: [{
+        value: 'local',
+        text: '鏈湴'
+      }, {
+        value: 'sso',
+        text: '鍗曠偣'
+      }]
+    },
+    {
+      type: 'select',
+      key: 'phoneField',
+      label: '鎵嬫満鍙�',
+      initVal: card.phoneField || '',
+      required: true,
+      options: inputfields
+    },
+    {
+      type: 'select',
+      key: 'smsId',
+      label: '鐭俊妯℃澘',
+      initVal: card.smsId || '',
+      tooltip: '璇烽�夋嫨閫傚綋鐨勭煭淇℃ā鏉裤��',
+      required: true,
+      options: msgTemps
     },
     {
       type: 'number',
@@ -3817,6 +3916,18 @@
     //   forbid: appType !== 'mob'
     // },
     {
+      type: 'radio',
+      key: 'empty',
+      label: '绌哄�奸殣钘�',
+      initVal: card.empty || 'show',
+      tooltip: '褰撻�夐」涓虹┖鏃讹紝闅愯棌璇ヨ〃鍗曘��',
+      required: false,
+      options: [
+        {value: 'show', text: '鍚�'},
+        {value: 'hidden', text: '鏄�'},
+      ]
+    },
+    {
       type: 'multiselect',
       key: 'blacklist',
       label: '榛戝悕鍗�',
diff --git a/src/templates/zshare/modalform/index.jsx b/src/templates/zshare/modalform/index.jsx
index 4a6f1e1..84fd387 100644
--- a/src/templates/zshare/modalform/index.jsx
+++ b/src/templates/zshare/modalform/index.jsx
@@ -19,29 +19,30 @@
 const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
 
 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'],
+  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'encryption', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline', 'placeholder', 'place', 'marginTop', 'marginBottom', 'lenControl', 'inputType'],
   number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline', 'place', 'marginTop', 'marginBottom'],
-  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
+  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
   checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
   radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
   checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'splitline', 'marginTop', 'marginBottom'],
   multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'dropdown'],
-  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkField', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
+  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkField', 'linkSubField', 'span', 'place', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
   fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'miniSet', 'splitline', 'marginTop', 'marginBottom', 'maxSize'],
   switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom'],
-  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
-  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'splitline', 'marginTop', 'marginBottom'],
+  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', 'declareType', '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', 'count', 'placeholder', 'marginTop', 'marginBottom'],
-  cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom', 'separator'],
+  cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'marginTop', 'marginBottom', 'separator'],
   color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'colorType', 'extra', 'marginTop', 'marginBottom'],
   rate: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'splitline', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'allowHalf', 'color', 'rateCount', 'character', 'place'],
   hint: ['label', 'field', 'type', 'blacklist', 'message', 'span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
-  split: ['label', 'type', 'marginTop', 'marginBottom', 'splitline'],
+  split: ['label', 'type', 'marginTop', 'marginBottom', 'splitline', 'splitctrl'],
   formula: ['label', 'type', 'marginTop', 'marginBottom', 'splitline', 'span', 'labelwidth', 'formula', 'eval', 'postfix'],
   brafteditor: ['required', 'hidelabel', 'hidden', 'readin', 'fieldlength', 'readonly', 'span', 'labelwidth', 'tooltip', 'extra', 'encryption', 'marginTop', 'marginBottom'],
   funcvar: ['span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
-  linkMain: ['readonly', 'required', 'hidden','declare', 'span', 'labelwidth', 'tooltip', 'interception', 'extra', 'marginTop', 'marginBottom']
+  linkMain: ['readonly', 'required', 'hidden','declare', 'span', 'labelwidth', 'tooltip', 'interception', 'extra', 'place', 'marginTop', 'marginBottom'],
+  vercode: ['label', 'field', 'type', 'blacklist', 'supField', 'readonly', 'required', 'hidden', 'span', 'labelwidth', 'tooltip', 'marginTop', 'marginBottom', 'placeholder', 'enter', 'smsId', 'phoneField', 'sendType']
 }
 
 class MainSearch extends Component {
@@ -66,7 +67,7 @@
 
       if (item.key === 'linkSubField') {
         item.options.forEach(cell => {
-          transfield[cell.field] = cell.label
+          transfield[cell.field] = cell.label.replace(/^\d+銆�/, '')
         })
       }
     })
@@ -120,7 +121,7 @@
 
     reRequired.field = true
 
-    if (['hint', 'split', 'formula'].includes(type)) {
+    if (['hint', 'split', 'formula', 'vercode'].includes(type)) {
       reRequired.field = false
       shows = fromJS(modalTypeOptions[type]).toJS()
     }
@@ -153,6 +154,10 @@
       }
       if (sessionStorage.getItem('appType') === 'mob') { // 绉诲姩绔彸渚ф墿灞曚俊鎭�
         shows.push('placeholder')
+      }
+    } else if (type === 'vercode') {
+      if (this.record.enter === 'tab' || this.record.enter === 'sub') {
+        shows.push('tabField')
       }
     } else if (type === 'linkMain') {
       if (this.record.declare === 'nvarchar') {
@@ -263,6 +268,12 @@
       }
     }
 
+    if (['multiselect', 'select', 'link', 'radio', 'checkbox', 'checkcard', 'cascader'].includes(type)) {
+      if (this.record.hidden !== 'true') {
+        shows.push('empty')
+      }
+    }
+
     if (type === 'cascader') {
       if (this.record.resourceType === '0') {        // 鑷畾涔夎祫婧�
         shows.push('options', 'topmark', 'linkSubField')
diff --git a/src/templates/zshare/modalform/index.scss b/src/templates/zshare/modalform/index.scss
index f2c7018..ee25254 100644
--- a/src/templates/zshare/modalform/index.scss
+++ b/src/templates/zshare/modalform/index.scss
@@ -47,4 +47,9 @@
     cursor: pointer;
     font-size: 14px;
   }
+  >.ant-row >.ant-col {
+    display: inline-block;
+    vertical-align: top;
+    float: none;
+  }
 }
\ No newline at end of file
diff --git a/src/templates/zshare/modalform/modaleditable/index.jsx b/src/templates/zshare/modalform/modaleditable/index.jsx
index 3e076af..5e84435 100644
--- a/src/templates/zshare/modalform/modaleditable/index.jsx
+++ b/src/templates/zshare/modalform/modaleditable/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Table, Input, Popconfirm, Form, Radio, message } from 'antd'
+import { Table, Input, Popconfirm, Form, message } from 'antd'
 import { ArrowUpOutlined, ArrowDownOutlined, DeleteOutlined, PlusOutlined, SwapOutlined } from '@ant-design/icons'
 
 import { formRule } from '@/utils/option.js'
@@ -140,27 +140,9 @@
     })
   }
 
-  getColumnSearchProps = column => ({
-    filterDropdown: () => (
-      <div style={{ padding: 8 }}>
-        <Radio.Group onChange={(e) => this.changeDatatype(column, e)} value={column.datatype}>
-          <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="string">
-            瀛楃涓�
-          </Radio>
-          <Radio style={{display: 'block', height: '30px', lineHeight: '30px'}} value="number">
-            鏁板瓧
-          </Radio>
-        </Radio.Group>
-      </div>
-    ),
-    filterIcon: () => (
-      <SwapOutlined style={{ color: column.datatype === 'number' ? '#1890ff' : ''}} />
-    )
-  })
-
-  changeDatatype = (column, e) => {
+  changeDatatype = (column) => {
     const { columns, dataSource } = this.state
-    let value = e.target.value
+    let value = column.datatype !== 'number' ? 'number' : 'string'
     let _data = dataSource.map(item => {
       let val = item[column.dataIndex]
       if (value === 'number') {
@@ -185,7 +167,16 @@
         }
 
         if (col.dataIndex !== 'operation') {
-          col = {...col, ...this.getColumnSearchProps(col)}
+          col.title = <div>
+            {col.$title}
+            <Popconfirm
+              title={`纭畾鍒囨崲涓�${col.datatype === 'number' ? '鏂囨湰' : '鏁板��'}鍚楋紵`}
+              overlayClassName="popover-confirm"
+              onConfirm={() => this.changeDatatype(col)
+            }>
+              <SwapOutlined style={{ color: col.datatype === 'number' ? '#1890ff' : ''}} />
+            </Popconfirm>
+          </div>
         }
 
         return col
@@ -318,6 +309,7 @@
       fields = subFields.map(field => {
         return {
           title: transfield[field] || field,
+          $title: transfield[field] || field,
           dataIndex: field,
           editable: true,
           datatype: dataItem && typeof(dataItem[field]) === 'number' ? 'number' : 'string'
@@ -330,12 +322,14 @@
     let columns = [
       {
         title: 'Value',
+        $title: 'Value',
         dataIndex: 'Value',
         editable: true,
         datatype: dataItem && typeof(dataItem.Value) === 'number' ? 'number' : 'string'
       },
       {
         title: 'Text',
+        $title: 'Text',
         dataIndex: 'Text',
         editable: true,
         datatype: dataItem && typeof(dataItem.Text) === 'number' ? 'number' : 'string'
@@ -367,6 +361,7 @@
     if (type === 'link') {
       columns.unshift({
         title: 'ParentID',
+        $title: 'ParentID',
         dataIndex: 'ParentID',
         editable: true,
         datatype: dataItem && typeof(dataItem.ParentID) === 'number' ? 'number' : 'string'
@@ -376,7 +371,16 @@
     return {
       columns: columns.map(col => {
         if (col.dataIndex !== 'operation') {
-          col = {...col, ...this.getColumnSearchProps(col)}
+          col.title = <div>
+            {col.$title}
+            <Popconfirm
+              title={`纭畾鍒囨崲涓�${col.datatype === 'number' ? '鏂囨湰' : '鏁板��'}鍚楋紵`}
+              overlayClassName="popover-confirm"
+              onConfirm={() => this.changeDatatype(col)
+            }>
+              <SwapOutlined style={{ color: col.datatype === 'number' ? '#1890ff' : ''}} />
+            </Popconfirm>
+          </div>
         }
         return col
       }),
diff --git a/src/templates/zshare/modalform/modaleditable/index.scss b/src/templates/zshare/modalform/modaleditable/index.scss
index ab53b8e..7c097fd 100644
--- a/src/templates/zshare/modalform/modaleditable/index.scss
+++ b/src/templates/zshare/modalform/modaleditable/index.scss
@@ -17,6 +17,15 @@
   }
   .ant-table-thead > tr > th {
     padding: 10px 16px;
+    position: relative;
+
+    .anticon-swap {
+      position: absolute;
+      right: 12px;
+      font-size: 14px;
+      // top: 12px;
+      color: #b8b8b8;
+    }
   }
   .ant-table-tbody > tr > td {
     padding: 5px 10px;
diff --git a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
index d2b8119..4fe7e4e 100644
--- a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
+++ b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -146,7 +146,7 @@
         }
 
         param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-        param.LText = param.LText.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${param.timestamp}'`)
+        param.LText = param.LText.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${param.timestamp}'`)
 
         console.info(`/* sql 楠岃瘉 */\n${param.LText.replace(/\n\s{6,20}/ig, '\n')}`)
 
@@ -239,7 +239,7 @@
           </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</span></Tooltip>,&nbsp;
+              <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>,&nbsp;
               <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'绯荤粺鍙橀噺锛岀郴缁熶細瀹氫箟鍙橀噺骞跺湪鍗曞彿鐢熸垚鎴栧垱寤哄嚟璇佹椂浣跨敤銆�'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
               {usefulfields ? <span>, {usefulfields}</span> : ''}
diff --git a/src/templates/zshare/verifycard/customscript/index.jsx b/src/templates/zshare/verifycard/customscript/index.jsx
index 1f172d4..4c4a094 100644
--- a/src/templates/zshare/verifycard/customscript/index.jsx
+++ b/src/templates/zshare/verifycard/customscript/index.jsx
@@ -68,6 +68,10 @@
         values.uuid = editItem ? editItem.uuid : ''
         values.position = values.position || (editItem ? editItem.position : 'front')
 
+        if (type === 'fullscreen' && editItem) {
+          values.status = editItem.status || 'true'
+        }
+
         let _quot = values.sql.match(/'{1}/g)
         let _lparen = values.sql.match(/\({1}/g)
         let _rparen = values.sql.match(/\){1}/g)
@@ -119,10 +123,10 @@
         let _backCustomScript = '' // 榛樿sql鍚庢墽琛岃剼鏈�
 
         this.props.customScripts.forEach(item => {
-          if (item.status === 'false' && values.uuid !== item.uuid) return
-
           let _item = values.uuid === item.uuid ? values : item
 
+          if (_item.status === 'false') return
+
           if (_item.position === 'init') {
             _initCustomScript += `
             /* 鍒濆鍖栬剼鏈� */
diff --git a/src/templates/zshare/verifycard/index.jsx b/src/templates/zshare/verifycard/index.jsx
index ab8d74c..b2be305 100644
--- a/src/templates/zshare/verifycard/index.jsx
+++ b/src/templates/zshare/verifycard/index.jsx
@@ -1154,6 +1154,8 @@
       verify.cbScripts.push(values)
     }
 
+    MKEmitter.emit('editLineId', values.uuid)
+
     this.setState({ verify })
   }
 
diff --git a/src/utils/utils-custom.js b/src/utils/utils-custom.js
index 1eaf2e9..c07d64c 100644
--- a/src/utils/utils-custom.js
+++ b/src/utils/utils-custom.js
@@ -1,3 +1,5 @@
+import md5 from 'md5'
+
 export default class MenuUtils {
   /**
    * @description 鑾峰彇涓嬬骇妯″潡
@@ -394,7 +396,7 @@
    * @description 閲嶇疆鑿滃崟閰嶇疆锛岄〉闈㈡暣浣撳鍒�
    * @return {String}  components 閰嶇疆淇℃伅
    */
-  static resetConfig = (components, uuids = {}, clear = false) => {
+  static resetConfig = (components, commonId, clear = false) => {
     return components.map(item => {
       if (item.type === 'navbar') {
         return item
@@ -404,18 +406,16 @@
         item.type = 'card'
       }
 
-      uuids[item.uuid] = this.getuuid()
-      item.uuid = uuids[item.uuid]
+      item.uuid = md5(commonId + item.uuid)
 
       if (item.type === 'tabs') {
         item.subtabs.forEach(tab => {
-          uuids[tab.uuid] = this.getuuid()
-          tab.uuid = uuids[tab.uuid]
+          tab.uuid = md5(commonId + tab.uuid)
 
-          tab.components = this.resetConfig(tab.components, uuids, clear)
+          tab.components = this.resetConfig(tab.components, commonId, clear)
         })
       } else if (item.type === 'group') {
-        item.components = this.resetConfig(item.components, uuids, clear)
+        item.components = this.resetConfig(item.components, commonId, clear)
       } else if (item.type === 'menubar') {
         item.subMenus = item.subMenus.map(cell => {
           cell.uuid = this.getuuid()
@@ -426,8 +426,20 @@
           return cell
         })
       } else if (['card', 'carousel', 'timeline'].includes(item.type)) {
-        if (item.wrap.datatype === 'public' && uuids[item.wrap.publicId]) {
-          item.wrap.publicId = uuids[item.wrap.publicId]
+        if (item.wrap.datatype === 'public' && item.wrap.publicId) {
+          item.wrap.publicId = md5(commonId + item.wrap.publicId)
+        }
+        if (item.wrap.autoExec) {
+          item.wrap.autoExec = md5(commonId + item.wrap.autoExec)
+        }
+
+        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
+          })
         }
         
         item.subcards.forEach(card => {
@@ -444,13 +456,21 @@
             }
           }
 
+          if (card.setting.click === 'button' && card.setting.linkbtn) {
+            card.setting.linkbtn = md5(commonId + card.setting.linkbtn)
+          }
+
           if (card.elements) {
             card.elements = card.elements.map(cell => {
-              cell.uuid = this.getuuid()
-
-              if (clear && cell.eleType === 'button' && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
-                cell.pageTemplate = ''
-                cell.linkmenu = ''
+              if (cell.eleType === 'button') {
+                cell.uuid = md5(commonId + cell.uuid)
+                if (clear && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
+                  cell.pageTemplate = ''
+                  cell.linkmenu = ''
+                }
+                this.resetBtn(cell, commonId)
+              } else {
+                cell.uuid = this.getuuid()
               }
               
               return cell
@@ -458,11 +478,15 @@
           }
           if (card.backElements) {
             card.backElements = card.backElements.map(cell => {
-              cell.uuid = this.getuuid()
-
-              if (clear && cell.eleType === 'button' && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
-                cell.pageTemplate = ''
-                cell.linkmenu = ''
+              if (cell.eleType === 'button') {
+                cell.uuid = md5(commonId + cell.uuid)
+                if (clear && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
+                  cell.pageTemplate = ''
+                  cell.linkmenu = ''
+                }
+                this.resetBtn(cell, commonId)
+              } else {
+                cell.uuid = this.getuuid()
               }
 
               return cell
@@ -470,16 +494,23 @@
           }
         })
       } else if (item.type === 'balcony') {
-        if (item.wrap.datatype === 'public' && uuids[item.wrap.publicId]) {
-          item.wrap.publicId = uuids[item.wrap.publicId]
+        if (item.wrap.datatype === 'public' && item.wrap.publicId) {
+          item.wrap.publicId = md5(commonId + item.wrap.publicId)
+        }
+        if (item.wrap.linkbtn) {
+          item.wrap.linkbtn = md5(commonId + item.wrap.linkbtn)
         }
         if (item.elements) {
           item.elements = item.elements.map(cell => {
-            cell.uuid = this.getuuid()
-
-            if (clear && cell.eleType === 'button' && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
-              cell.pageTemplate = ''
-              cell.linkmenu = ''
+            if (cell.eleType === 'button') {
+              cell.uuid = md5(commonId + cell.uuid)
+              if (clear && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
+                cell.pageTemplate = ''
+                cell.linkmenu = ''
+              }
+              this.resetBtn(cell, commonId)
+            } else {
+              cell.uuid = this.getuuid()
             }
 
             return cell
@@ -488,7 +519,7 @@
       } else if (item.type === 'table' && item.cols) {
         let loopCol = (col) => {
           col.subcols = col.subcols.map(c => {
-            c.uuid = this.getuuid()
+            c.uuid = md5(commonId + c.uuid)
   
             if (c.type === 'colspan' && c.subcols) {
               c = loopCol(c)
@@ -500,12 +531,14 @@
               })
             } else if (c.type === 'action' && c.elements) {
               c.elements = c.elements.map(cell => {
-                cell.uuid = this.getuuid()
+                cell.uuid = md5(commonId + cell.uuid)
 
                 if (clear && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
                   cell.pageTemplate = ''
                   cell.linkmenu = ''
                 }
+
+                this.resetBtn(cell, commonId)
 
                 return cell
               })
@@ -515,12 +548,9 @@
   
           return col
         }
-        let _uuids = {}
-        item.cols = item.cols.map(col => {
-          let uuid = this.getuuid()
 
-          _uuids[col.uuid] = uuid
-          col.uuid = uuid
+        item.cols = item.cols.map(col => {
+          col.uuid = md5(commonId + col.uuid)
   
           if (col.type === 'colspan' && col.subcols) {
             col = loopCol(col)
@@ -531,7 +561,8 @@
             })
           } else if (col.type === 'action' && col.elements) {
             col.elements = col.elements.map(cell => {
-              cell.uuid = this.getuuid()
+              cell.uuid = md5(commonId + cell.uuid)
+              this.resetBtn(cell, commonId)
               return cell
             })
           }
@@ -540,8 +571,15 @@
 
         if (item.subtype === 'editable') {
           item.cols = item.cols.map(col => {
-            if (col.editable === 'true' && col.enter && _uuids[col.enter]) {
-              col.enter = _uuids[col.enter]
+            if (col.editable === 'true' && col.enter) {
+              col.enter = md5(commonId + col.enter)
+            } else if (col.type === 'colspan' && col.subcols) {
+              col.subcols = col.subcols.map(c => {
+                if (c.editable === 'true' && c.enter) {
+                  c.enter = md5(commonId + c.enter)
+                }
+                return c
+              })
             }
             return col
           })
@@ -555,6 +593,11 @@
     
             return m
           })
+
+          if (cell.subButton) {
+            this.resetBtn(cell.subButton, commonId)
+          }
+
           return cell
         })
       }
@@ -563,18 +606,16 @@
         item.btnlog = null
       }
   
-      let oriUids = {}
       if (item.action) {
         item.action = item.action.map(cell => {
-          let _uuid = this.getuuid()
-
-          oriUids[cell.uuid] = _uuid
-          cell.uuid = _uuid
+          cell.uuid = md5(commonId + cell.uuid)
 
           if (clear && cell.pageTemplate === 'linkpage' && cell.linkmenu) {
             cell.pageTemplate = ''
             cell.linkmenu = ''
           }
+
+          this.resetBtn(cell, commonId)
 
           return cell
         })
@@ -613,27 +654,43 @@
       }
 
       if (item.setting && item.setting.supModule && item.setting.supModule[0] !== 'empty') {
-        let em = false
         item.setting.supModule = item.setting.supModule.map(c => {
-          if (!uuids[c]) {
-            em = true
-          }
-          return uuids[c] || ''
+          return md5(commonId + c)
         })
-        if (em) {
-          item.setting.supModule = ''
-        }
         if (item.wrap && item.wrap.supModule) {
           item.wrap.supModule = item.setting.supModule
         }
       }
 
       if (item.wrap && item.wrap.doubleClick) {
-        item.wrap.doubleClick = oriUids[item.wrap.doubleClick] || ''
+        item.wrap.doubleClick = md5(commonId + item.wrap.doubleClick)
       }
   
       return item
     })
+  }
+
+  /**
+   * @description 鎸夐挳閲嶇疆
+   */
+  static resetBtn (btn, commonId) {
+    if (btn.OpenType === 'pop' || (btn.OpenType === 'funcbutton' && btn.execMode === 'pop')) {
+      if (btn.modal && btn.modal.fields.length > 0) {
+        btn.modal.fields = btn.modal.fields.map(m => {
+          m.uuid = this.getuuid()
+          return m
+        })
+      }
+    }
+    if (btn.switchTab && btn.switchTab.length > 0) {
+      btn.switchTab = btn.switchTab.map(m => md5(commonId + m))
+    }
+    if (btn.anchors && btn.anchors.length > 0) {
+      btn.anchors = btn.anchors.map(m => md5(commonId + m))
+    }
+    if (btn.syncComponent && btn.syncComponent.length > 0) {
+      btn.syncComponent = btn.syncComponent.map(m => md5(commonId + m))
+    }
   }
 
   /**
@@ -652,7 +709,7 @@
   * @description 閲嶇疆缁勪欢閰嶇疆
   * @return {String}  item 缁勪欢淇℃伅
   */
-  static resetComponentConfig = (item, uuids = {}) => {
+  static resetComponentConfig = (item) => {
     if (item.type === 'navbar') {
       return item
     }
@@ -661,11 +718,8 @@
       item.type = 'card'
     }
 
-    let _uuid = this.getuuid()
-
-    uuids[item.uuid] = _uuid
-
-    item.uuid = _uuid
+    item.uuid = this.getuuid()
+    let commonId = this.getuuid()
 
     // 閲嶇疆缁勪欢鍚嶇О
     let sign = this.getSignName()
@@ -686,14 +740,36 @@
         return cell
       })
     } else if (['card', 'carousel', 'timeline'].includes(item.type)) {
+      if (item.wrap.autoExec) {
+        item.wrap.autoExec = md5(commonId + item.wrap.autoExec)
+      }
+      
       item.subcards.forEach(card => {
         card.uuid = this.getuuid()
+
+        if (card.setting.click === 'button' && card.setting.linkbtn) {
+          card.setting.linkbtn = md5(commonId + card.setting.linkbtn)
+        }
+
         if (card.elements) {
           if (sessionStorage.getItem('editMenuType') === 'popview') {
             card.elements = card.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
           }
           card.elements = card.elements.map(cell => {
-            cell.uuid = this.getuuid()
+            if (cell.eleType === 'button') {
+              cell.uuid = md5(commonId + cell.uuid)
+
+              if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+                if (cell.modal && cell.modal.fields.length > 0) {
+                  cell.modal.fields = cell.modal.fields.map(m => {
+                    m.uuid = this.getuuid()
+                    return m
+                  })
+                }
+              }
+            } else {
+              cell.uuid = this.getuuid()
+            }
             return cell
           })
         }
@@ -702,7 +778,19 @@
             card.elements = card.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
           }
           card.backElements = card.backElements.map(cell => {
-            cell.uuid = this.getuuid()
+            if (cell.eleType === 'button') {
+              cell.uuid = md5(commonId + cell.uuid)
+              if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+                if (cell.modal && cell.modal.fields.length > 0) {
+                  cell.modal.fields = cell.modal.fields.map(m => {
+                    m.uuid = this.getuuid()
+                    return m
+                  })
+                }
+              }
+            } else {
+              cell.uuid = this.getuuid()
+            }
             return cell
           })
         }
@@ -712,8 +800,23 @@
         if (sessionStorage.getItem('editMenuType') === 'popview') {
           item.elements = item.elements.filter(b => b.OpenType !== 'popview' && b.OpenType !== 'funcbutton')
         }
+        if (item.wrap.linkbtn) {
+          item.wrap.linkbtn = md5(commonId + item.wrap.linkbtn)
+        }
         item.elements = item.elements.map(cell => {
-          cell.uuid = this.getuuid()
+          if (cell.eleType === 'button') {
+            cell.uuid = md5(commonId + cell.uuid)
+            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+              if (cell.modal && cell.modal.fields.length > 0) {
+                cell.modal.fields = cell.modal.fields.map(m => {
+                  m.uuid = this.getuuid()
+                  return m
+                })
+              }
+            }
+          } else {
+            cell.uuid = this.getuuid()
+          }
           return cell
         })
       }
@@ -736,12 +839,8 @@
         return col
       }
 
-      let _uuids = {}
       item.cols = item.cols.map(col => {
-        let uuid = this.getuuid()
-
-        _uuids[col.uuid] = uuid
-        col.uuid = uuid
+        col.uuid = md5(commonId + col.uuid)
 
         if (col.type === 'colspan' && col.subcols) {
           col = loopCol(col)
@@ -755,7 +854,16 @@
             col.elements = col.elements.filter(c => c.OpenType !== 'popview' && c.OpenType !== 'funcbutton')
           }
           col.elements = col.elements.map(cell => {
-            cell.uuid = this.getuuid()
+            cell.uuid = md5(commonId + cell.uuid)
+            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+              if (cell.modal && cell.modal.fields.length > 0) {
+                cell.modal.fields = cell.modal.fields.map(m => {
+                  m.uuid = this.getuuid()
+                  return m
+                })
+              }
+            }
+
             return cell
           })
         }
@@ -764,8 +872,8 @@
 
       if (item.subtype === 'editable') {
         item.cols = item.cols.map(col => {
-          if (col.editable === 'true' && col.enter && _uuids[col.enter]) {
-            col.enter = _uuids[col.enter]
+          if (col.editable === 'true' && col.enter) {
+            col.enter = md5(commonId + col.enter)
           }
           return col
         })
@@ -785,17 +893,20 @@
 
     delete item.btnlog
 
-    let oriUids = {}
     if (item.action) {
       if (sessionStorage.getItem('editMenuType') === 'popview') {
         item.action = item.action.filter(c => c.OpenType !== 'popview' && c.OpenType !== 'funcbutton')
       }
       item.action = item.action.map(cell => {
-        let _uuid = this.getuuid()
-
-        oriUids[cell.uuid] = _uuid
-
-        cell.uuid = _uuid
+        cell.uuid = md5(commonId + cell.uuid)
+        if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
+          if (cell.modal && cell.modal.fields.length > 0) {
+            cell.modal.fields = cell.modal.fields.map(m => {
+              m.uuid = this.getuuid()
+              return m
+            })
+          }
+        }
 
         return cell
       })
@@ -840,7 +951,7 @@
     }
 
     if (item.wrap && item.wrap.doubleClick) {
-      item.wrap.doubleClick = oriUids[item.wrap.doubleClick] || ''
+      item.wrap.doubleClick = md5(commonId + item.wrap.doubleClick)
     }
 
     return item
diff --git a/src/utils/utils-datamanage.js b/src/utils/utils-datamanage.js
index 14883d2..c081694 100644
--- a/src/utils/utils-datamanage.js
+++ b/src/utils/utils-datamanage.js
@@ -145,8 +145,8 @@
     _customScript = _customScript.replace(/\$sum@/ig, '/*')
     _customScript = _customScript.replace(/@sum\$/ig, '*/')
 
-    _dataresource = _dataresource.replace(/@ID@/ig, `''`)
-    _customScript = _customScript.replace(/@ID@/ig, `''`)
+    // _dataresource = _dataresource.replace(/@ID@/ig, `''`)
+    // _customScript = _customScript.replace(/@ID@/ig, `''`)
     _dataresource = _dataresource.replace(/@BID@/ig, `'${BID || ''}'`)
     _customScript = _customScript.replace(/@BID@/ig, `'${BID || ''}'`)
     _dataresource = _dataresource.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
@@ -157,6 +157,8 @@
     _customScript = _customScript.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
     _dataresource = _dataresource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
     _customScript = _customScript.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    _dataresource = _dataresource.replace(/@typename@/ig, `'admin'`)
+    _customScript = _customScript.replace(/@typename@/ig, `'admin'`)
 
     let regoptions = null
     if (setting.queryType === 'statistics' || _customScript) {
@@ -213,9 +215,17 @@
     let LText = ''
     let DateCount = ''
 
+    if (setting.sub_field) {
+      arrFields = arrFields + ',' + setting.sub_field
+    }
+
     if (_dataresource && setting.laypage && orderBy && !id) {
       LText = `/*system_query*/select top ${pageSize} ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable where rows > ${pageSize * (pageIndex - 1)} order by tmptable.rows `
-      DateCount = `/*system_query*/select count(1) as total from ${_dataresource} ${_search}`
+      if (setting.sub_field) {
+        DateCount = `/*system_query*/select count(1) as total from (select distinct ${setting.primaryKey} from ${_dataresource} ${_search})a`
+      } else {
+        DateCount = `/*system_query*/select count(1) as total from ${_dataresource} ${_search}`
+      }
     } else if (_dataresource && orderBy) {
       LText = `/*system_query*/select ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
     } else if (_dataresource) {
@@ -275,6 +285,13 @@
     // param.parid = 'BID'
     // param.sub_name = 'sub_data'
     // param.sub_field = 'BID,friend_text,icon,Initials'
+
+    if (setting.sub_field) {
+      param.sub_name = setting.subdata
+      param.tabid = setting.primaryKey || ''
+      param.parid = setting.subBID || ''
+      param.sub_field = setting.sub_field
+    }
 
     // exec_type: 'y' 瑙g爜瀛楁锛歀Text銆丩Text1銆丩Text2銆乧ustom_script銆丏ateCount
 
@@ -348,8 +365,8 @@
     _customScript = _customScript.replace(/\$select@/ig, '/*')
     _customScript = _customScript.replace(/@select\$/ig, '*/')
 
-    _dataresource = _dataresource.replace(/@ID@/ig, `''`)
-    _customScript = _customScript.replace(/@ID@/ig, `''`)
+    // _dataresource = _dataresource.replace(/@ID@/ig, `''`)
+    // _customScript = _customScript.replace(/@ID@/ig, `''`)
     _dataresource = _dataresource.replace(/@BID@/ig, `'${BID || ''}'`)
     _customScript = _customScript.replace(/@BID@/ig, `'${BID || ''}'`)
     _dataresource = _dataresource.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
@@ -360,6 +377,8 @@
     _customScript = _customScript.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
     _dataresource = _dataresource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
     _customScript = _customScript.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    _dataresource = _dataresource.replace(/@typename@/ig, `'admin'`)
+    _customScript = _customScript.replace(/@typename@/ig, `'admin'`)
 
     let regoptions = null
     if (setting.queryType === 'statistics' || _customScript) {
@@ -541,6 +560,7 @@
       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.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
@@ -631,6 +651,7 @@
     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.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
       console.info(sql.replace(/\n\s{8}/ig, '\n'))
@@ -848,6 +869,8 @@
     _script = _script.replace(/@UserID@/ig, userId)
     _sql = _sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
     _script = _script.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    _sql = _sql.replace(/@typename@/ig, `'admin'`)
+    _script = _script.replace(/@typename@/ig, `'admin'`)
 
     // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
     if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
diff --git a/src/utils/utils.js b/src/utils/utils.js
index e7c224d..09aede5 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -78,20 +78,6 @@
   }
 
   /**
-   * @description 鏁版嵁婧愬悕绉帮紝鐢ㄤ簬缁熶竴鏌ヨ
-   * @return {String}  name
-   */
-  static getdataName () {
-    let name = []
-    let _options = 'abcdefghigklmnopqrstuvwxyz'
-    for (let i = 0; i < 6; i++) {
-      name.push(_options.substr(Math.floor(Math.random() * 26), 1))
-    }
-    name.splice(3, 0, new Date().getTime())
-    return name.join('')
-  }
-
-  /**
    * @description 鐢熸垚32浣島uid string + 鏃堕棿
    * @return {String}  uuid
    */
@@ -219,6 +205,35 @@
 
     return value
   }
+
+  // /**
+  //  * @description sql瑙e瘑
+  //  * @return {String}   value
+  //  */
+  // static unFormatOptions (value) {
+  //   if (!value) return ''
+
+  //   value = window.atob(value)
+  //   value = value.replace('minKe', '')
+  //   value = window.decodeURIComponent(window.atob(value))
+
+  //   // 澶栬仈鏁版嵁搴撴浛鎹�
+  //   if (window.GLOB.externalDatabase !== null && window.GLOB.externalDatabase) {
+  //     value = value.replace(window.GLOB.externalDatabase, '@db@')
+  //   }
+
+  //   value = value.replace(/ mpercent /ig, '%')
+    
+  //   // 鏇挎崲鍏抽敭瀛�
+  //   formatKeys.forEach(item => {
+  //     let reg = new RegExp('(\\s)?' + item.value.replace(/\s/g, '') + '(\\s)?', 'ig')
+  //     value = value.replace(reg, ' ' + item.key + ' ')
+  //   })
+
+  //   // value = value.replace(/\n/ig, ' \n ')
+
+  //   return value
+  // }
 
   /**
    * @description sPC_TableData_InUpDe sql鍔犲瘑
@@ -2141,6 +2156,7 @@
     _callbacksql = _callbacksql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
     _callbacksql = _callbacksql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
     _callbacksql = _callbacksql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
+    _callbacksql = _callbacksql.replace(/@typename@/ig, `'admin'`)
     
     return {
       sql: _sql,
diff --git a/src/views/appmanage/index.jsx b/src/views/appmanage/index.jsx
index 3b7bf87..a54a3b7 100644
--- a/src/views/appmanage/index.jsx
+++ b/src/views/appmanage/index.jsx
@@ -469,6 +469,7 @@
               cell.sysBgColor = _param.sysBgColor || '#ffffff'
               cell.direction = _param.direction || 'vertical'
               cell.adapter = _param.adapter || ''
+              cell.topHeight = _param.topHeight || ''
               cell.share = _param.share || 'false' // 鍒嗕韩
               cell.share_des = _param.share_des || '' // 鍒嗕韩鎻忚堪
               cell.share_url = _param.share_url || '' // 鍒嗕韩鍥剧墖
@@ -652,7 +653,7 @@
     })
 
     // 瀛愬簲鐢↖D銆乼ypename銆佸簲鐢↖D銆丆loudUserID銆乤ppkey銆乴ogin_types(鏄惁闇�瑕佺櫥褰曪紝宸插純鐢�)銆乴ink_type(鏄惁浣跨敤鐭繛鎺ワ紝宸插純鐢�)銆乺ole_type(鏄惁浣跨敤瑙掕壊绠$悊)銆乴ang銆乧ss(鐨偆)銆乼itle(鏍囬)銆乫avicon(鍥炬爣)銆乽ser_binding(鐢ㄦ埛缁戝畾)銆乻ms_id(鐭俊妯℃澘ID)銆佽嚜瀹氫箟
-    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
     param.LText = param.LText.join(' union all ')
     param.LText = Utils.formatOptions(param.LText)
     
@@ -898,7 +899,7 @@
           return item
         })
 
-        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
         param.LText = param.LText.join(' union all ')
         param.LText = Utils.formatOptions(param.LText)
       }
@@ -991,7 +992,7 @@
         return item
       })
 
-      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
+      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', topHeight: item.topHeight || '', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
       param.LText = param.LText.join(' union all ')
       param.LText = Utils.formatOptions(param.LText)
 
diff --git a/src/views/appmanage/submutilform/index.jsx b/src/views/appmanage/submutilform/index.jsx
index c9b5b5b..20d6daf 100644
--- a/src/views/appmanage/submutilform/index.jsx
+++ b/src/views/appmanage/submutilform/index.jsx
@@ -309,6 +309,18 @@
               )}
             </Form.Item>
           </Col> : null}
+          {typename === 'pad' && adapters.includes('app') ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鍦ㄦ槑绉戜簯APP涓紝鐘舵�佹爮鐨勬渶澶ч珮搴︼紝绌哄�兼椂浣跨敤APP鑾峰彇鍒扮殑鐘舵�佹爮楂樺害銆�">
+                <QuestionCircleOutlined className="mk-form-tip" />
+                鐘舵�佹爮楂樺害
+              </Tooltip>
+            }>
+              {getFieldDecorator('topHeight', {
+                initialValue: card ? card.topHeight || '' : ''
+              })(<InputNumber min={0} max={5000} precision={0} onPressEnter={this.handleSubmit}/>)}
+            </Form.Item>
+          </Col> : null}
           <Col span={12}>
             <Form.Item className="sys-bgcolor" label={
               <Tooltip placement="topLeft" title="瀛愬簲鐢ㄩ�氱敤鐨勮儗鏅壊锛屽瓙搴旂敤椤甸潰鍒涘缓鏃朵細榛樿娣诲姞姝よ儗鏅壊銆�">
diff --git a/src/views/billprint/index.jsx b/src/views/billprint/index.jsx
index 1b0e280..b616463 100644
--- a/src/views/billprint/index.jsx
+++ b/src/views/billprint/index.jsx
@@ -21,6 +21,7 @@
 const AntvScatter = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-scatter'))
 const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
 const PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
+const DoubleDataCard = asyncComponent(() => import('@/tabviews/custom/components/card/double-data-card'))
 const TableCard = asyncComponent(() => import('@/tabviews/custom/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/tabviews/custom/components/table/normal-table'))
 const SandBox = asyncComponent(() => import('@/tabviews/custom/components/code/sand-box'))
@@ -398,7 +399,7 @@
           // floor    缁勪欢鐨勫眰绾�
           // pageable 鏄惁鍒嗛〉锛岀粍浠跺睘鎬э紝涓嶅垎椤电殑缁勪欢鎵嶅彲浠ョ粺涓�鏌ヨ
           if (component.setting.sync === 'true') {
-            component.dataName = Utils.getdataName()
+            component.dataName = 'mk' + component.uuid.slice(-18)
             let param = this.getDefaultParam(component)
             _pars.push(param)
           } else {
@@ -837,6 +838,12 @@
             <PropCard config={item} initdata={item.data} mainSearch={[]} />
           </Col>
         )
+      } else if (item.type === 'card' && item.subtype === 'dualdatacard') {
+        return (
+          <Col span={item.width} style={style} key={item.uuid}>
+            <DoubleDataCard config={item} mainSearch={[]}/>
+          </Col>
+        )
       } else if (item.type === 'card' && item.subtype === 'tablecard') {
         return (
           <Col span={item.width} style={style} key={item.uuid}>
@@ -886,7 +893,7 @@
       <div className="bill-print-wrap" >
         {loadingview && <Spin size="large" />}
         {pages ? <div id="bill-print">
-          {pages.map((components, index) => (<div className={'print-page' + (auto ? ' auto' : '')} key={index} style={{...config.style, overflow: 'hidden', boxSizing: 'border-box'}}><Row>{this.getComponents(components)}</Row></div>))}
+          {pages.map((components, index) => (<div className={'print-page' + (auto ? ' auto' : '')} key={index} style={{...config.style, overflow: 'hidden', boxSizing: 'border-box'}}><Row className="component-wrap">{this.getComponents(components)}</Row></div>))}
         </div> : null}
         {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
         {config && window.GLOB.breakpoint ? <DebugTable /> : null}
diff --git a/src/views/design/header/index.jsx b/src/views/design/header/index.jsx
index eb9e26a..39078cd 100644
--- a/src/views/design/header/index.jsx
+++ b/src/views/design/header/index.jsx
@@ -335,6 +335,41 @@
       }
     })
   }
+
+  getSmStemp = () => {
+    if (!sessionStorage.getItem('msgTemplate')) {
+      let _sql = `select聽ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a 
+        inner join (select openid from sapp where id='${window.GLOB.appkey}') b 
+        on a.openid=b.openid`
+  
+      _sql = Utils.formatOptions(_sql)
+  
+      let param = {
+        func: 'sPC_Get_SelectedList',
+        LText: _sql,
+        obj_name: 'data',
+        arr_field: 'ID,TemplateCode,SignName'
+      }
+      
+      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 浜戠鏁版嵁楠岃瘉
+      
+      Api.getSystemConfig(param).then(res => {
+        let msgs = []
+        if (!res.status) {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+        } else if (res.data) {
+          msgs = res.data
+        }
+        sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
+      })
+    }
+  }
   
   UNSAFE_componentWillMount () {
     sessionStorage.setItem('isEditState', 'true')
@@ -390,7 +425,8 @@
 
       setTimeout(() => {
         this.setSystemFuncs()
-      }, 200)
+        this.getSmStemp()
+      }, 500)
     }
   }
 
diff --git a/src/views/design/index.jsx b/src/views/design/index.jsx
index 9c1ea4c..5cd309f 100644
--- a/src/views/design/index.jsx
+++ b/src/views/design/index.jsx
@@ -23,7 +23,7 @@
   
   render () {
     return (
-      <div className="mk-main-view">
+      <div className={'mk-main-view ' + (window.GLOB.systemType || '')}>
         <ConfigProvider locale={_locale}>
           <Sidemenu key="sidemenu"/>
           <Header key="header"/>
diff --git a/src/views/design/index.scss b/src/views/design/index.scss
index 2dd743a..1445283 100644
--- a/src/views/design/index.scss
+++ b/src/views/design/index.scss
@@ -3,6 +3,11 @@
     background: #ffffff!important;
   }
 }
+.mk-main-view.production {
+  .edit-check {
+    display: none;
+  }
+}
 .mk-popover-control-wrap {
   .anticon-plus {
     color: #26C281;
diff --git a/src/views/design/sidemenu/index.jsx b/src/views/design/sidemenu/index.jsx
index ffef40e..8729535 100644
--- a/src/views/design/sidemenu/index.jsx
+++ b/src/views/design/sidemenu/index.jsx
@@ -109,6 +109,8 @@
   }
 
   editmenu = (cell) => {
+    if (window.GLOB.systemType === 'production') return
+    
     if (cell.type === 'CustomPage') {
       let _param = {
         MenuType: 'custom',
diff --git a/src/views/design/sidemenu/thdmenuplus/index.jsx b/src/views/design/sidemenu/thdmenuplus/index.jsx
index cbacb44..ad47ac4 100644
--- a/src/views/design/sidemenu/thdmenuplus/index.jsx
+++ b/src/views/design/sidemenu/thdmenuplus/index.jsx
@@ -3,6 +3,7 @@
 import { Modal, notification, Col, Card, Tabs, Row, Input, Button } from 'antd'
 import { PlusOutlined } from '@ant-design/icons'
 import moment from 'moment'
+import md5 from 'md5'
 
 import Api from '@/api'
 import { sysTemps } from '@/utils/option.js'
@@ -123,6 +124,7 @@
     let sysMenu = {
       MenuID: Utils.getuuid(),
       MenuName: template.title,
+      MenuNo: template.MenuNo ? template.MenuNo + '_01' : '',
       Template: template.type,
       fstMenuId: mainMenu.MenuID,
       ParentId: supMenu.MenuID,
@@ -234,16 +236,15 @@
           config.MenuNo = param.MenuNo
           config.easyCode = ''
 
-          let uuids = {} // 閲嶇疆鍏叡鏁版嵁婧�
+          let commonId = Utils.getuuid()
           if (config.interfaces && config.interfaces.length > 0) {
             config.interfaces = config.interfaces.map(inter => {
-              uuids[inter.uuid] = this.getuuid()
-              inter.uuid = uuids[inter.uuid]
+              inter.uuid = md5(commonId + inter.uuid)
               return inter
             })
           }
 
-          config.components = MenuUtils.resetConfig(config.components, uuids)
+          config.components = MenuUtils.resetConfig(config.components, commonId)
           config.enabled = false
 
           param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index 2c94022..2edd976 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -5,6 +5,7 @@
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js' 
+import MKEmitter from '@/utils/events.js'
 import options, { styles } from '@/store/options.js'
 import zhCN from '@/locales/zh-CN/login.js'
 import enUS from '@/locales/en-US/login.js'
@@ -13,7 +14,7 @@
 import './index.scss'
 
 const LoginForm = asyncLoadComponent(() => import('./loginform'))
-const Resetpwd = asyncLoadComponent(() => import('@/components/header/resetpwd'))
+const Resetpwd = asyncLoadComponent(() => import('@/components/resetPassword'))
 const LoginCloudForm = asyncComponent(() => import('./logincloudform'))
 const LoginCodeForm = asyncComponent(() => import('./logincodeform'))
 const iszhCN = sessionStorage.getItem('lang') !== 'en-US'
@@ -39,8 +40,6 @@
     loginWays: null,
     touristLogin: false,
     syncing: false,
-    visible: false,
-    resetLoading: false
   }
 
   UNSAFE_componentWillMount() {
@@ -160,8 +159,14 @@
         if (visible) {
           message.warning(tip)
           this.setState({
-            isDisabled: false,
-            visible: true
+            isDisabled: false
+          })
+          
+          MKEmitter.emit('resetpassword', () => {
+            const input = document.getElementById('password')
+            if (input) {
+              input.select()
+            }
           })
           return
         }
@@ -561,6 +566,13 @@
             authError: res.message
           })
         }
+      }, () => {
+        if (index === -1 || index > 10) {
+          this.setState({
+            auth: false,
+            authError: '缃戠粶閿欒瀵艰嚧绯荤粺鎺堟潈澶辫触锛岃鑱旂郴绠$悊鍛樸��'
+          })
+        }
       })
     }
 
@@ -673,7 +685,11 @@
                 login_ways.push({
                   type: item.way_no,
                   smsId: item.sms_id
-                }) 
+                })
+
+                if (item.way_no === 'sms_vcode' && item.sms_id) {
+                  sessionStorage.setItem('mk_sms_id', item.sms_id)
+                }
               })
             } else {
               login_ways.push({
@@ -720,7 +736,7 @@
 
             // positecgroup
             if (res.users_upt === 'true' && window.GLOB.systemType === 'production') {
-              Api.genericInterface ({
+              Api.genericInterface({
                 func: 's_Get_local_u_deleted',
                 users_upt_date: res.users_upt_date,
                 userid: result.UserID,
@@ -736,7 +752,7 @@
                   LoginUID: result.LoginUID
                 }).then(ssores => {
                   if (!ssores.status) return
-                  Api.genericInterface ({
+                  Api.genericInterface({
                     func: 's_get_local_u_create',
                     user_ids_local: ssores.user_ids_local,
                     userid: result.UserID,
@@ -914,48 +930,6 @@
     }, () => {})
   }
 
-  resetPwdSubmit = () => {
-    this.formRef.handleConfirm().then(res => {
-      this.setState({
-        resetLoading: true
-      })
-
-      let _param = {
-        func: 's_PwdUpt',
-        LText: `select '${res.originpwd}','${res.password}'`
-      }
-      
-      _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')          // 鏃堕棿鎴�
-      _param.LText = Utils.formatOptions(_param.LText)                   // 鍏抽敭瀛楃鏇挎崲锛宐ase64鍔犲瘑
-      _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)   // md5瀵嗛挜
-  
-      Api.getSystemConfig(_param).then(result => {
-        this.setState({
-          visible: !result.status,
-          resetLoading: false
-        })
-
-        if (result.status) {
-          notification.success({
-            top: 92,
-            message: '淇敼鎴愬姛锛岃閲嶆柊鐧诲綍銆�',
-            duration: 2
-          })
-          const input = document.getElementById('password')
-          if (input) {
-            input.select()
-          }
-        } else {
-          notification.warning({
-            top: 92,
-            message: result.message,
-            duration: 5
-          })
-        }
-      })
-    }, () => {})
-  }
-
   /**
    * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
    */
@@ -1014,19 +988,7 @@
           <LoginCloudForm handleSubmit={() => this.syncSubmit()} wrappedComponentRef={(inst) => this.logincloudRef = inst}/>
         </Modal>
         {/* 淇敼瀵嗙爜 */}
-        <Modal
-          title="淇敼瀵嗙爜"
-          okText={this.state.dict['login.ok']}
-          cancelText={this.state.dict['login.cancel']}
-          visible={this.state.visible}
-          onOk={this.resetPwdSubmit}
-          maskClosable={false}
-          confirmLoading={this.state.resetLoading}
-          onCancel={() => this.setState({visible: false, resetLoading: false})}
-          destroyOnClose
-        >
-          <Resetpwd wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
-        </Modal>
+        <Resetpwd />
         {/* 浜屾楠岃瘉 */}
         <Modal
           title="浜屾楠岃瘉"
diff --git a/src/views/login/index.scss b/src/views/login/index.scss
index 57acf3a..10f9671 100644
--- a/src/views/login/index.scss
+++ b/src/views/login/index.scss
@@ -35,7 +35,7 @@
     background-size: contain;
     background-repeat: no-repeat;
     background-position: center center;
-    border-bottom: 2px solid var(--mk-sys-color);
+    // border-bottom: 2px solid var(--mk-sys-color);
 
     .login-form-button {
       background-color: var(--mk-sys-color);
diff --git a/src/views/login/loginform.jsx b/src/views/login/loginform.jsx
index 566b3d5..38e3d44 100644
--- a/src/views/login/loginform.jsx
+++ b/src/views/login/loginform.jsx
@@ -353,7 +353,7 @@
               <Input
                 addonAfter={
                   <Button type="link" className="vercode" size="small" disabled={verdisabled} onClick={this.getvercode}>
-                    {delay ? this.props.dict['login.vercode.queryagain'].replace('@', delay) : this.props.dict['login.vercode.query']}
+                    {delay ? `${delay}s鍚庨噸鏂拌幏鍙朻 : '鑾峰彇楠岃瘉鐮�'}
                   </Button>
                 }
                 placeholder={this.props.dict['login.vercode']}
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 67ee9a7..ce3e6e5 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -37,6 +37,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const Versions = asyncComponent(() => import('@/menu/versions'))
 const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
@@ -875,7 +876,7 @@
               } else {
                 resolve(result)
               }
-            })
+            }, this.netError)
           })
         } else {
           resolve({status: true})
@@ -908,7 +909,7 @@
           }
           return Api.getSystemConfig(_param)
         }
-      }).then(res => { // 椤甸潰鎸夐挳鍏崇郴淇濆瓨
+      }, this.netError).then(res => { // 椤甸潰鎸夐挳鍏崇郴淇濆瓨
         if (!res || !res.status) return res
 
         this.setState({
@@ -922,7 +923,7 @@
             status: true
           }
         }
-      }).then(res => {
+      }, this.netError).then(res => {
         this.setState({
           menuloading: false
         })
@@ -943,8 +944,21 @@
             duration: 5
           })
         }
-      })
+      }, this.netError)
     }, 300 + (+sessionStorage.getItem('mkDelay')))
+  }
+
+  netError = (error) => {
+    this.setState({
+      menuloading: false
+    })
+    if (!error) {
+      notification.warning({
+        top: 92,
+        message: '淇濆瓨澶辫触锛岃妫�鏌ョ綉缁滄槸鍚︽甯搞��',
+        duration: 5
+      })
+    }
   }
 
   getRoleFields = () => {
@@ -1151,6 +1165,7 @@
                     {/* 琛ㄥ悕娣诲姞 */}
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" key="component">
diff --git a/src/views/menudesign/index.scss b/src/views/menudesign/index.scss
index 6368ca8..2916916 100644
--- a/src/views/menudesign/index.scss
+++ b/src/views/menudesign/index.scss
@@ -1,6 +1,12 @@
 body {
   overflow-x: hidden;
   overflow-y: hidden;
+  --mk-sys-color: #1890ff;
+  --mk-sys-color1: #e6f7ff;
+  --mk-sys-color2: #bae7ff;
+  --mk-sys-color3: #91d5ff;
+  --mk-sys-color4: #69c0ff;
+  --mk-sys-color5: #40a9ff;
 }
 .pc-menu-view {
   background: #000;
@@ -46,6 +52,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -56,6 +63,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/menudesign/popview/index.scss b/src/views/menudesign/popview/index.scss
index 2d06a62..2ea36fa 100644
--- a/src/views/menudesign/popview/index.scss
+++ b/src/views/menudesign/popview/index.scss
@@ -21,6 +21,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -31,6 +32,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/menudesign/printmenuform/index.jsx b/src/views/menudesign/printmenuform/index.jsx
index 9f9c9bb..be3c97d 100644
--- a/src/views/menudesign/printmenuform/index.jsx
+++ b/src/views/menudesign/printmenuform/index.jsx
@@ -119,6 +119,20 @@
       <Form {...formItemLayout}>
         <Row>
           <Col span={24}>
+            <Form.Item label="鑿滃崟鍚嶇О">
+              <span style={{display: 'inline-block', wordBreak: 'break-all', lineHeight: 1.5}}>
+                {config.MenuName}
+              </span>
+            </Form.Item>
+          </Col>
+          <Col span={24}>
+            <Form.Item label="鑿滃崟鍙傛暟">
+              <span style={{display: 'inline-block', wordBreak: 'break-all', lineHeight: 1.5}}>
+                {config.MenuNo}
+              </span>
+            </Form.Item>
+          </Col>
+          <Col span={24}>
             <Form.Item label="鎵撳嵃灏哄">
               {getFieldDecorator('pageSize', {
                 initialValue: config.pageSize || 'A4',
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index 1091b21..7e740f5 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -34,6 +34,7 @@
 const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
 const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent'))
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
@@ -147,7 +148,6 @@
     MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
     setTimeout(() => {
       this.getAppPictures()
-      this.getSmStemp()
       this.getRoleFields()
       setGLOBFuncs()
     }, 1000)
@@ -336,41 +336,6 @@
       return false
     }
     return true
-  }
-
-  getSmStemp = () => {
-    if (!sessionStorage.getItem('msgTemplate')) {
-      let _sql = `select聽ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a 
-        inner join (select openid from sapp where id='${window.GLOB.appkey}') b 
-        on a.openid=b.openid`
-  
-      _sql = Utils.formatOptions(_sql)
-  
-      let param = {
-        func: 'sPC_Get_SelectedList',
-        LText: _sql,
-        obj_name: 'data',
-        arr_field: 'ID,TemplateCode,SignName'
-      }
-      
-      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 浜戠鏁版嵁楠岃瘉
-      
-      Api.getSystemConfig(param).then(res => {
-        let msgs = []
-        if (!res.status) {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-        } else if (res.data) {
-          msgs = res.data
-        }
-        sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
-      })
-    }
   }
 
   changeEditMenu = (menu) => {
@@ -841,16 +806,15 @@
           }
         }
       } else {
-        let uuids = {} // 閲嶇疆鍏叡鏁版嵁婧�
+        let commonId = Utils.getuuid()
         if (config.interfaces && config.interfaces.length > 0) {
           config.interfaces = config.interfaces.map(inter => {
-            uuids[inter.uuid] = this.getuuid()
-            inter.uuid = uuids[inter.uuid]
+            inter.uuid = md5(commonId + inter.uuid)
             return inter
           })
         }
 
-        config.components = MenuUtils.resetConfig(config.components, uuids, urlParam.clearMenu)
+        config.components = MenuUtils.resetConfig(config.components, commonId, urlParam.clearMenu)
 
         if (config.version !== 2.0) {
           config.components = this.collectTB(config.components)
@@ -1060,6 +1024,17 @@
           })
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
+              if (cell.eleType !== 'button' || cell.hidden === 'true') return
+
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
+            })
+
+            if (item.subtype !== 'dualdatacard') return
+            
+            card.backElements && card.backElements.forEach(cell => {
               if (cell.eleType !== 'button' || cell.hidden === 'true') return
 
               m.children.push({
@@ -1595,14 +1570,14 @@
                     }
 
                     resolve(result)
-                  })
+                  }, this.netError)
                 } else {
                   resolve(res)
                 }
               } else {
                 resolve(res)
               }
-            })
+            }, this.netError)
           }
         }
       }).then(res => { // 椤甸潰淇濆瓨
@@ -1640,8 +1615,21 @@
             duration: 5
           })
         }
-      })
+      }, this.netError)
     }, 300 + (+sessionStorage.getItem('mkDelay')))
+  }
+
+  netError = (error) => {
+    this.setState({
+      menuloading: false
+    })
+    if (!error) {
+      notification.warning({
+        top: 92,
+        message: '淇濆瓨澶辫触锛岃妫�鏌ョ綉缁滄槸鍚︽甯搞��',
+        duration: 5
+      })
+    }
   }
 
   getRoleFields = () => {
@@ -2026,6 +2014,7 @@
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
                     {config ? <Paragraph style={{padding: '10px 0px 0px 18px'}} copyable={{ text:  `${window.GLOB.baseurl}mob/index.html#/index/${sessionStorage.getItem('kei_no')}/${sessionStorage.getItem('typename')}/${sessionStorage.getItem('lang')}/${MenuId}/@BID@` }}>鑿滃崟閾炬帴</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" className="component" key="component">
@@ -2034,7 +2023,7 @@
                   <Panel header="鍏冪礌" key="element">
                     <Modulecell />
                   </Panel>
-                  <Panel header={'椤甸潰鏍峰紡'} key="background">
+                  <Panel header="椤甸潰鏍峰紡" key="background">
                     {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                   </Panel>
                 </Collapse>
diff --git a/src/views/mobdesign/index.scss b/src/views/mobdesign/index.scss
index 1e12390..2ef712e 100644
--- a/src/views/mobdesign/index.scss
+++ b/src/views/mobdesign/index.scss
@@ -1,3 +1,11 @@
+body {
+  --mk-sys-color: #1890ff;
+  --mk-sys-color1: #e6f7ff;
+  --mk-sys-color2: #bae7ff;
+  --mk-sys-color3: #91d5ff;
+  --mk-sys-color4: #69c0ff;
+  --mk-sys-color5: #40a9ff;
+}
 .mk-mob-view {
   min-height: 100vh;
 
@@ -30,6 +38,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -40,6 +49,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
diff --git a/src/views/mobdesign/popview/index.jsx b/src/views/mobdesign/popview/index.jsx
index 7cb6973..316deca 100644
--- a/src/views/mobdesign/popview/index.jsx
+++ b/src/views/mobdesign/popview/index.jsx
@@ -272,8 +272,8 @@
               <Panel header="鍏冪礌" key="element">
                 <Modulecell />
               </Panel>
-              <Panel header={'椤甸潰鏍峰紡'} key="background">
-                <BgController config={config} updateConfig={this.updateConfig} />
+              <Panel header="椤甸潰鏍峰紡" key="background">
+                <BgController config={config} type="mob_popview" updateConfig={this.updateConfig} />
               </Panel>
             </Collapse>
           </div>
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index 15ac6d8..c524734 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -39,6 +39,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const NormalCss = asyncComponent(() => import('@/menu/normalCss'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
@@ -132,7 +133,6 @@
 
     setTimeout(() => {
       this.getAppPictures()
-      this.getSmStemp()
       this.getRoleFields()
       setGLOBFuncs()
     }, 1000)
@@ -312,83 +312,6 @@
         this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view'}))))
       }
     })
-  }
-
-  getSmStemp = () => {
-    if (!sessionStorage.getItem('msgTemplate')) {
-      let _sql = `select聽ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a 
-        inner join (select openid from sapp where id='${window.GLOB.appkey}') b 
-        on a.openid=b.openid`
-  
-      _sql = Utils.formatOptions(_sql)
-  
-      let param = {
-        func: 'sPC_Get_SelectedList',
-        LText: _sql,
-        obj_name: 'data',
-        arr_field: 'ID,TemplateCode,SignName'
-      }
-      
-      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 浜戠鏁版嵁楠岃瘉
-      
-      Api.getSystemConfig(param).then(res => {
-        let msgs = []
-        if (!res.status) {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-        } else if (res.data) {
-          msgs = res.data
-          sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
-        }
-      })
-    }
-
-    if (!sessionStorage.getItem('printTemps')) {
-      let _sql = `select ID,Images,PrintTempNO+PrintTempName as PN from sPrintTemplate 
-      where appkey= @appkey@ and Deleted=0 and typechartwo='web_print'
-      union select ID,Images,a.PrintTempNO+PrintTempName as PN 
-      from (select * from sPrintTemplate where appkey= '' and Deleted=0 and typechartwo='web_print') a 
-      left join (select PrintTempNO from sPrintTemplate where appkey= @appkey@ and Deleted=0 ) b 
-      on a.PrintTempNO=b.PrintTempNO 
-      left join (select Srcid from sPrintTemplate_Log where appkey='' and apicode= @appkey@ and Deleted=0 ) c 
-      on a.ID=c.Srcid where b.PrintTempNO is null and c.Srcid is null`
-  
-      let param = {
-        func: 'sPC_Get_SelectedList',
-        LText: Utils.formatOptions(_sql),
-        obj_name: 'data',
-        arr_field: 'PN,ID,Images'
-      }
-  
-      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
-  
-      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 浜戠鏁版嵁楠岃瘉
-  
-      Api.getSystemConfig(param).then(res => {
-        if (res.status) {
-          let temps = res.data.map(temp => {
-            return {
-              value: temp.ID,
-              text: temp.PN
-            }
-          })
-  
-          sessionStorage.setItem('printTemps', JSON.stringify(temps))
-        } else {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-        }
-      })
-    }
   }
 
   getAppPictures = () => {
@@ -775,15 +698,14 @@
           }
         }
       } else {
-        let uuids = {} // 閲嶇疆鍏叡鏁版嵁婧�
+        let commonId = Utils.getuuid()
         if (config.interfaces && config.interfaces.length > 0) {
           config.interfaces = config.interfaces.map(inter => {
-            uuids[inter.uuid] = this.getuuid()
-            inter.uuid = uuids[inter.uuid]
+            inter.uuid = md5(commonId + inter.uuid)
             return inter
           })
         }
-        config.components = MenuUtils.resetConfig(config.components, uuids, urlParam.clearMenu)
+        config.components = MenuUtils.resetConfig(config.components, commonId, urlParam.clearMenu)
 
         if (config.version !== 2.0) {
           config.components = this.collectTB(config.components)
@@ -1373,14 +1295,14 @@
                     }
 
                     resolve(result)
-                  })
+                  }, this.netError)
                 } else {
                   resolve(res)
                 }
               } else {
                 resolve(res)
               }
-            })
+            }, this.netError)
           }
         }
       }).then(res => { // 椤甸潰淇濆瓨
@@ -1418,8 +1340,21 @@
             duration: 5
           })
         }
-      })
+      }, this.netError)
     }, 300 + (+sessionStorage.getItem('mkDelay')))
+  }
+
+  netError = (error) => {
+    this.setState({
+      menuloading: false
+    })
+    if (!error) {
+      notification.warning({
+        top: 92,
+        message: '淇濆瓨澶辫触锛岃妫�鏌ョ綉缁滄槸鍚︽甯搞��',
+        duration: 5
+      })
+    }
   }
 
   getRoleFields = () => {
@@ -1707,6 +1642,7 @@
                     {/* 琛ㄥ悕娣诲姞 */}
                     {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                     {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>鑿滃崟ID</Paragraph> : null}
+                    {config ? <NormalCss config={config} updateConfig={this.updateConfig}/> : null}
                   </Panel>
                   {/* 缁勪欢娣诲姞 */}
                   <Panel header="缁勪欢" key="component">
@@ -1715,7 +1651,7 @@
                   <Panel header="鍏冪礌" key="element">
                     <Modulecell />
                   </Panel>
-                  <Panel header={'椤甸潰鏍峰紡'} key="background">
+                  <Panel header="椤甸潰鏍峰紡" key="background">
                     {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                   </Panel>
                 </Collapse>
diff --git a/src/views/pcdesign/index.scss b/src/views/pcdesign/index.scss
index d5f059d..bb683f2 100644
--- a/src/views/pcdesign/index.scss
+++ b/src/views/pcdesign/index.scss
@@ -1,5 +1,11 @@
 body {
   overflow-x: hidden;
+  --mk-sys-color: #1890ff;
+  --mk-sys-color1: #e6f7ff;
+  --mk-sys-color2: #bae7ff;
+  --mk-sys-color3: #91d5ff;
+  --mk-sys-color4: #69c0ff;
+  --mk-sys-color5: #40a9ff;
 }
 .mk-pc-view {
   background: #000;
@@ -34,6 +40,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -44,6 +51,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {
@@ -259,6 +267,9 @@
     background: rgba(0, 0, 0, 0);
   }
 }
+.mk-pc-view + .modal-form-board {
+  padding-top: 0px;
+}
 
 body {
   overflow-y: hidden;
diff --git a/src/views/systemfunc/sidemenu/config.jsx b/src/views/systemfunc/sidemenu/config.jsx
index c49b74a..9adbd43 100644
--- a/src/views/systemfunc/sidemenu/config.jsx
+++ b/src/views/systemfunc/sidemenu/config.jsx
@@ -5,8 +5,8 @@
   PageParam: {Icon: 'folder'},
   children: [{
     src: '',
-    PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
-    type: 'CommonTable',
+    PageParam: {OpenType: 'newtab', Template: 'CustomPage'},
+    type: 'CustomPage',
     MenuID: '1581067625930haged11ieaivpavv77k',
     MenuNo: 'sDatasM',
     MenuName: '鏁版嵁瀛楀吀',
@@ -77,13 +77,13 @@
     MenuNo: 's_custom_scriptM',
     MenuName: '鑷畾涔夊嚱鏁�',
   }, {
-    src: '',
-    PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
-    type: 'CommonTable',
-    MenuID: '1590458676585agbbr63t6ihighg2i1g',
-    MenuNo: 'LdropdownmenuNewM',
-    MenuName: '閫氱敤涓嬫媺鑿滃崟',
-  }, {
+  //   src: '',
+  //   PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
+  //   type: 'CommonTable',
+  //   MenuID: '1590458676585agbbr63t6ihighg2i1g',
+  //   MenuNo: 'LdropdownmenuNewM',
+  //   MenuName: '閫氱敤涓嬫媺鑿滃崟',
+  // }, {
     src: '',
     PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
     type: 'CommonTable',
diff --git a/src/views/systemfunc/sidemenu/index.jsx b/src/views/systemfunc/sidemenu/index.jsx
index b1ea702..21bd103 100644
--- a/src/views/systemfunc/sidemenu/index.jsx
+++ b/src/views/systemfunc/sidemenu/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import { Menu } from 'antd'
+import { fromJS } from 'immutable'
 import { FolderOutlined } from '@ant-design/icons'
 
 import { SySMenuList } from './config'
@@ -39,10 +40,19 @@
       menulist = menulist.filter(menu => menu.children.length > 0)
     }
 
+    let tb =  sessionStorage.getItem('mk-table-node')
+
     this.setState({
       subMenulist: menulist,
       rootSubmenuKeys: menulist.map(item => item.MenuID),
       openKeys: [menulist[0].MenuID]
+    }, () => {
+      if (tb && menulist[0] && menulist[0].children[0] && menulist[0].children[0].MenuNo === 'sDatasM') {
+        setTimeout(() => {
+          MKEmitter.emit('modifyTabs', fromJS(menulist[0].children[0]).toJS())
+        }, 500)
+      }
+      sessionStorage.removeItem('mk-table-node')
     })
   }
 
diff --git a/src/views/systemproc/proc/index.jsx b/src/views/systemproc/proc/index.jsx
index 6f13864..cad4d02 100644
--- a/src/views/systemproc/proc/index.jsx
+++ b/src/views/systemproc/proc/index.jsx
@@ -376,7 +376,7 @@
             </div>
           </div>
           <div className="edit-wrap">
-            <CodeMirror value={content} onChange={(val) => this.setState({content: val})}/>
+            <CodeMirror value={content} func={true} onChange={(val) => this.setState({content: val})}/>
           </div>
         </div>
         <Modal
diff --git a/src/views/systemproc/proc/index.scss b/src/views/systemproc/proc/index.scss
index 653bc5c..e0a327c 100644
--- a/src/views/systemproc/proc/index.scss
+++ b/src/views/systemproc/proc/index.scss
@@ -109,6 +109,10 @@
       background-color: #ffffff;
     }
   }
+
+  .code-mirror-wrap .anticon-font-size {
+    position: absolute;
+  }
 }
 
 .mk-create-func {
diff --git a/src/views/tabledesign/index.jsx b/src/views/tabledesign/index.jsx
index d368f6b..0689387 100644
--- a/src/views/tabledesign/index.jsx
+++ b/src/views/tabledesign/index.jsx
@@ -386,6 +386,20 @@
             style: { backgroundColor: '#ffffff', paddingTop: '16px', paddingBottom: '80px', paddingLeft: '16px', paddingRight: '16px'},
           }
         } else {
+          if (config.Template === 'CommonTable' && !config.components) {
+            let urlparam = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
+            urlparam.type = 'CommonTable'
+            if (urlparam.PageParam) {
+              urlparam.PageParam.Template = 'CommonTable'
+            }
+            urlparam = window.btoa(window.encodeURIComponent(JSON.stringify(urlparam)))
+
+            let url = `#/basedesign/${urlparam}`
+            
+            window.history.replaceState(null, null, window.location.href.split('#')[0] + url)
+            window.location.reload()
+            return
+          }
           config.uuid = MenuId
           config.MenuID = MenuId
           config.Template = 'BaseTable'
@@ -581,7 +595,7 @@
       new Promise(resolve => {
         Api.getSystemConfig(param).then(res => {
           resolve(res)
-        })
+        }, this.netError)
       }).then(res => {
         if (!res || !res.status) return res
 
@@ -615,10 +629,23 @@
             duration: 5
           })
         }
-      })
+      }, this.netError)
     }, 300 + (+sessionStorage.getItem('mkDelay')))
   }
 
+  netError = (error) => {
+    this.setState({
+      menuloading: false
+    })
+    if (!error) {
+      notification.warning({
+        top: 92,
+        message: '淇濆瓨澶辫触锛岃妫�鏌ョ綉缁滄槸鍚︽甯搞��',
+        duration: 5
+      })
+    }
+  }
+
   getRoleFields = () => {
     if (sessionStorage.getItem('sysRoles')) return
     Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => {
diff --git a/src/views/tabledesign/index.scss b/src/views/tabledesign/index.scss
index 2fe5621..9a2c961 100644
--- a/src/views/tabledesign/index.scss
+++ b/src/views/tabledesign/index.scss
@@ -1,6 +1,12 @@
 body {
   overflow-x: hidden;
   overflow-y: hidden;
+  --mk-sys-color: #1890ff;
+  --mk-sys-color1: #e6f7ff;
+  --mk-sys-color2: #bae7ff;
+  --mk-sys-color3: #91d5ff;
+  --mk-sys-color4: #69c0ff;
+  --mk-sys-color5: #40a9ff;
 }
 .mk-source-wrap {
   .ant-radio-button-wrapper:last-child {
diff --git a/src/views/tabledesign/popview/index.scss b/src/views/tabledesign/popview/index.scss
index 2d06a62..2ea36fa 100644
--- a/src/views/tabledesign/popview/index.scss
+++ b/src/views/tabledesign/popview/index.scss
@@ -21,6 +21,7 @@
     bottom: 0;
     background: rgba(255, 255, 255, 0.9);
     border: 1px solid #1890ff;
+    overflow: hidden;
     .center {
       position: absolute;
       font-size: 16px;
@@ -31,6 +32,7 @@
       max-width: 70%;
       .title {
         text-align: center;
+        white-space: nowrap;
       }
     }
     .error {

--
Gitblit v1.8.0