From 137fb8ea6af2789b3238b22bac31d80bced41dfe Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期三, 28 七月 2021 11:39:39 +0800
Subject: [PATCH] 2021-07-28

---
 src/menu/components/form/formaction/index.scss                                     |    5 
 src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx                     |   77 
 src/tabviews/custom/components/chart/antv-scatter/index.scss                       |   70 
 src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.scss         |   11 
 src/mob/mobshell/index.jsx                                                         |   65 
 src/tabviews/scriptmanage/config.jsx                                               |    2 
 src/views/menudesign/printmenuform/index.jsx                                       |  100 
 src/locales/zh-CN/model.js                                                         |    2 
 src/tabviews/home/index.jsx                                                        |   33 
 src/templates/zshare/editTable/index.scss                                          |    4 
 src/tabviews/zshare/actionList/changeuserbutton/index.jsx                          |   40 
 src/menu/datasource/verifycard/index.jsx                                           |  109 
 src/assets/css/main.scss                                                           |   27 
 src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx                      |   81 
 src/templates/formtabconfig/settingform/index.jsx                                  |    4 
 src/menu/components/card/cardcellcomponent/index.jsx                               |  114 
 src/mob/searchconfig/searchdragelement/card.jsx                                    |  132 
 src/menu/components/card/cardcomponent/index.jsx                                   |   42 
 src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.jsx                    |    0 
 src/views/menudesign/index.scss                                                    |    2 
 src/menu/components/card/prop-card/index.jsx                                       |   44 
 src/templates/zshare/customscript/index.jsx                                        |   11 
 src/mob/components/navbar/normal-navbar/menusetting/index.jsx                      |   63 
 package-lock.json                                                                  |  706 
 src/assets/css/viewstyle.scss                                                      |   17 
 src/menu/components/card/cardcomponent/settingform/index.jsx                       |   32 
 src/tabviews/zshare/topSearch/index.jsx                                            |  765 
 src/assets/mobimg/navtop-mob.png                                                   |    0 
 src/api/index.js                                                                   |   90 
 src/mob/components/formdragelement/index.scss                                      |  245 
 config/webpack.config.js                                                           |   11 
 src/mob/searchconfig/groupform/index.jsx                                           |   90 
 src/templates/sharecomponent/actioncomponent/index.scss                            |    2 
 src/menu/components/chart/antv-dashboard/index.scss                                |   50 
 src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.scss       |   11 
 src/menu/components/chart/antv-dashboard/chartcompile/index.scss                   |   44 
 src/mob/components/menubar/normal-menubar/wrapsetting/index.scss                   |    7 
 src/mob/mobshell/card.jsx                                                          |   62 
 src/mob/mobshell/index.scss                                                        |   30 
 src/tabviews/custom/components/card/prop-card/index.scss                           |   22 
 src/tabviews/zshare/mutilform/mkNumberInput/index.scss                             |   27 
 src/menu/components/share/styleInput/index.scss                                    |   11 
 src/pc/bgcontroller/index.jsx                                                      |   71 
 src/views/pcdesign/index.jsx                                                       |  540 
 src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.scss     |   25 
 src/mob/components/formdragelement/index.jsx                                       |  132 
 src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx                  |    7 
 src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx           |   23 
 src/views/appmanage/transform/index.jsx                                            |   89 
 src/views/appmanage/header/index.jsx                                               |   31 
 src/pc/modulesource/option.jsx                                                     |   15 
 src/templates/zshare/editTable/index.jsx                                           |   61 
 src/tabviews/zshare/normalTable/index.jsx                                          |   55 
 src/menu/components/form/normal-form/groupform/index.jsx                           |   25 
 src/views/menudesign/homeform/index.jsx                                            |   69 
 src/components/mkIcon/index.scss                                                   |   53 
 src/menu/datasource/index.jsx                                                      |  164 
 src/menu/components/chart/antv-bar/index.scss                                      |   11 
 src/menu/components/tree/antd-tree/index.jsx                                       |  188 
 src/menu/components/carousel/cardcomponent/index.jsx                               |    3 
 src/tabviews/zshare/actionList/normalbutton/index.jsx                              |  279 
 src/tabviews/custom/components/table/normal-table/index.scss                       |   28 
 src/menu/modulesource/option.jsx                                                   |   13 
 src/pc/transfer/index.scss                                                         |    0 
 src/views/appmanage/index.scss                                                     |  132 
 src/menu/components/card/balcony/wrapsetting/settingform/index.scss                |   36 
 src/views/appmanage/transform/index.scss                                           |    4 
 src/templates/sharecomponent/actioncomponent/actionform/index.jsx                  |   37 
 src/menu/pastecontroller/index.jsx                                                 |   26 
 src/views/interface/workspace/editTable/index.scss                                 |   85 
 src/views/interface/workspace/index.scss                                           |   52 
 src/mob/searchconfig/settingform/index.jsx                                         |  222 
 src/mob/header/index.scss                                                          |    8 
 src/tabviews/zshare/topSearch/mkSelect/index.scss                                  |    0 
 src/menu/components/share/searchcomponent/dragsearch/index.scss                    |    6 
 src/tabviews/zshare/mutilform/mkRadio/index.scss                                   |    0 
 src/menu/datasource/verifycard/settingform/index.scss                              |    8 
 src/mob/searchconfig/searchdragelement/index.jsx                                   |  123 
 src/tabviews/zshare/mutilform/mkInput/index.scss                                   |   27 
 src/views/printTemplate/option.js                                                  |    8 
 src/menu/components/share/sourcecomponent/inputform/index.jsx                      |   20 
 src/components/header/index.jsx                                                    |  113 
 src/views/pcdesign/menuform/index.jsx                                              |    4 
 src/templates/formtabconfig/index.jsx                                              |    8 
 src/templates/zshare/verifycard/callbackcustomscript/index.jsx                     |    7 
 src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss          |    8 
 src/views/appmanage/scriptform/index.jsx                                           |  242 
 src/templates/sharecomponent/fieldscomponent/index.jsx                             |   13 
 src/menu/components/code/sandbox/index.jsx                                         |    6 
 src/views/billprint/index.scss                                                     |    6 
 src/menu/components/tabs/tabcomponents/index.scss                                  |    5 
 src/views/appmanage/header/index.scss                                              |   57 
 src/menu/components/table/normal-table/columns/index.scss                          |   30 
 src/components/paste/index.jsx                                                     |   72 
 src/menu/bgcontroller/index.jsx                                                    |   50 
 src/tabviews/custom/components/share/normalheader/index.jsx                        |    2 
 src/templates/sharecomponent/settingcomponent/settingform/utils.jsx                |   28 
 src/tabviews/zshare/mutilform/mkDatePicker/index.scss                              |    0 
 src/templates/sharecomponent/settingcomponent/settingform/datasource/index.scss    |    3 
 src/views/menudesign/printmenuform/index.scss                                      |    5 
 src/menu/components/chart/antv-pie/chartcompile/index.jsx                          |    8 
 src/templates/zshare/verifycard/index.jsx                                          |   47 
 src/menu/components/share/sourcecomponent/index.jsx                                |   15 
 src/mob/components/navbar/normal-navbar/index.scss                                 |  111 
 src/pc/createview/index.scss                                                       |    0 
 src/tabviews/zshare/topSearch/dategroup/yearpicker/index.scss                      |    0 
 config/webpackDevServer.config.js                                                  |    2 
 src/tabviews/zshare/actionList/printbutton/index.jsx                               |  119 
 src/tabviews/tabmanage/index.jsx                                                   |    6 
 package.json                                                                       |    7 
 src/tabviews/zshare/topSearch/advanceform/index.jsx                                |  112 
 src/menu/replaceField/settingform/index.scss                                       |    0 
 src/menu/components/chart/antv-bar/chartcompile/index.jsx                          |  181 
 src/tabviews/zshare/topSearch/mkDatePicker/index.scss                              |    0 
 src/mob/header/index.jsx                                                           |   16 
 src/mob/searchconfig/index.jsx                                                     |  574 
 config/modules.js                                                                  |    2 
 src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx            |  198 
 src/menu/components/share/markcomponent/index.jsx                                  |   40 
 src/tabviews/custom/components/form/normal-form/index.scss                         |    4 
 src/menu/components/card/cardcellcomponent/dragaction/action.jsx                   |   22 
 src/menu/components/card/cardcellcomponent/elementform/index.jsx                   |    2 
 src/tabviews/zshare/mutilform/mkSelect/index.scss                                  |    0 
 src/menu/components/tabs/antv-tabs/index.scss                                      |   79 
 src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.scss         |   11 
 public/admin.html                                                                  |    6 
 src/templates/menuconfig/editthdmenu/index.jsx                                     |   21 
 src/tabviews/zshare/actionList/newpagebutton/index.jsx                             |   51 
 src/tabviews/commontable/index.jsx                                                 |  105 
 src/templates/sharecomponent/settingcalcomponent/verifycard/settingform/index.jsx  |   18 
 src/menu/components/share/normalheader/index.scss                                  |   20 
 src/tabviews/custom/components/card/cardcellList/index.jsx                         |  200 
 src/components/editor/index.jsx                                                    |   16 
 src/tabviews/custom/components/table/normal-table/index.jsx                        |  181 
 src/menu/components/group/groupsetting/settingform/index.jsx                       |   11 
 src/mob/modulesource/index.jsx                                                     |    1 
 src/components/mkIcon/index.jsx                                                    |   70 
 src/menu/components/group/groupcomponents/card.jsx                                 |   21 
 src/tabviews/zshare/mutilform/index.jsx                                            | 1605 -
 src/assets/img/rolemanage.jpg                                                      |    0 
 src/menu/components/share/actioncomponent/actionform/index.jsx                     |   90 
 src/mob/components/menubar/normal-menubar/index.scss                               |   62 
 src/menu/components/table/normal-table/columns/index.jsx                           |   84 
 src/menu/popview/index.jsx                                                         |  105 
 src/tabviews/zshare/mutilform/mkDatePicker/index.jsx                               |   71 
 src/tabviews/treepage/index.jsx                                                    |   20 
 src/menu/components/share/logcomponent/index.jsx                                   |    7 
 src/pc/components/navbar/normal-navbar/index.jsx                                   |   18 
 src/components/paste/index.scss                                                    |    0 
 src/tabviews/custom/components/chart/antv-scatter/index.jsx                        |  432 
 src/menu/components/chart/antv-dashboard/chartcompile/index.jsx                    |  333 
 src/views/printTemplate/index.jsx                                                  |    6 
 src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx             |  222 
 src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.scss                   |    0 
 src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx                 |  174 
 src/menu/components/card/balcony/index.scss                                        |   77 
 config/pnpTs.js                                                                    |    2 
 src/tabviews/subtable/index.jsx                                                    |   97 
 src/menu/components/group/normal-group/index.scss                                  |    2 
 src/tabviews/custom/components/card/table-card/index.jsx                           |   61 
 src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx                     |  342 
 src/menu/components/share/actioncomponent/index.scss                               |    7 
 src/menu/components/chart/antv-scatter/index.scss                                  |   72 
 src/templates/comtableconfig/source.jsx                                            |   12 
 src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx              |   26 
 src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx              |    8 
 src/tabviews/zshare/mutilform/mkTextArea/index.scss                                |    0 
 src/menu/components/form/wrapsetting/settingform/index.scss                        |    3 
 src/menu/components/card/cardcomponent/pastecomponent/index.jsx                    |   77 
 src/mob/components/topbar/normal-navbar/index.jsx                                  |  195 
 src/views/login/index.scss                                                         |  109 
 src/tabviews/zshare/topSearch/mkDatePicker/index.jsx                               |   93 
 src/pc/components/login/wrapsetting/index.jsx                                      |   81 
 src/pc/components/login/normal-login/index.scss                                    |  138 
 src/mob/searchconfig/groupdragelement/card.jsx                                     |   61 
 src/tabviews/custom/components/code/sand-box/index.jsx                             |   18 
 src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx   |   12 
 src/menu/components/card/table-card/index.jsx                                      |   64 
 src/templates/modalconfig/settingform/index.scss                                   |    5 
 src/pc/createview/settingform/index.scss                                           |   11 
 src/menu/components/tree/antd-tree/wrapsetting/settingform/index.jsx               |  262 
 src/mob/modulesource/option.jsx                                                    |   21 
 src/tabviews/custom/components/share/normalTable/index.scss                        |   34 
 src/templates/modalconfig/checkCard/index.scss                                     |   14 
 src/tabviews/zshare/actionList/excelInbutton/index.jsx                             |   44 
 public/options.json                                                                |   10 
 src/templates/modalconfig/checkCard/index.jsx                                      |   34 
 src/views/pcdesign/index.scss                                                      |    2 
 src/templates/calendarconfig/source.jsx                                            |    6 
 src/views/mobdesign/index.jsx                                                      |  706 
 src/mob/searchconfig/groupdragelement/index.jsx                                    |   64 
 src/mob/searchconfig/searchdragelement/index.scss                                  |  149 
 src/mob/components/menubar/normal-menubar/wrapsetting/index.jsx                    |   83 
 src/mob/colorsketch/index.jsx                                                      |   17 
 src/templates/zshare/modalform/datatable/index.jsx                                 |   44 
 src/menu/components/share/actioncomponent/formconfig.jsx                           |  115 
 src/tabviews/custom/components/group/normal-group/index.jsx                        |  211 
 src/templates/menuconfig/editfirstmenu/index.jsx                                   |   14 
 src/tabviews/custom/components/carousel/prop-card/index.jsx                        |   29 
 src/templates/zshare/modalform/datatable/index.scss                                |    6 
 src/templates/sharecomponent/searchcomponent/searchform/index.jsx                  |  296 
 src/mob/components/topbar/normal-navbar/wrapsetting/index.scss                     |    7 
 src/tabviews/custom/components/card/balcony/index.scss                             |   65 
 src/views/mobdesign/menuform/index.jsx                                             |    4 
 src/menu/components/card/balcony/wrapsetting/index.scss                            |    7 
 src/templates/sharecomponent/searchcomponent/index.jsx                             |   32 
 src/menu/components/tree/antd-tree/wrapsetting/index.scss                          |    7 
 src/menu/components/share/mobPagination/index.jsx                                  |   20 
 src/menu/components/card/table-card/cardcomponent/index.jsx                        |   13 
 src/tabviews/custom/components/share/normalheader/index.scss                       |    7 
 src/views/mobdesign/index.scss                                                     |   83 
 src/utils/utils.js                                                                 |  406 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx              |   73 
 src/index.js                                                                       |    4 
 src/menu/components/search/main-search/dragsearch/index.jsx                        |   20 
 src/views/appmanage/scriptform/index.scss                                          |   12 
 src/views/interface/workspace/request/index.scss                                   |  162 
 src/tabviews/custom/components/share/tabtransfer/index.jsx                         |  208 
 src/menu/components/tabs/tablabelform/index.jsx                                    |   28 
 src/menu/replaceField/index.jsx                                                    |  381 
 src/mob/modalconfig/controller.jsx                                                 |   64 
 src/menu/modalconfig/index.scss                                                    |   15 
 src/menu/modalconfig/index.jsx                                                     |   51 
 src/tabviews/custom/components/card/balcony/index.jsx                              |  301 
 src/views/rolemanage/header/index.scss                                             |   58 
 src/tabviews/zshare/imgScale/index.jsx                                             |   65 
 src/utils/option.js                                                                |  164 
 src/templates/zshare/modalform/index.jsx                                           |  105 
 src/menu/components/table/normal-table/wrapsetting/index.jsx                       |    2 
 src/mob/components/topbar/normal-navbar/index.scss                                 |   82 
 src/assets/mobimg/ratioboard.png                                                   |    0 
 src/tabviews/custom/components/editor/braft-editor/index.jsx                       |   18 
 src/menu/components/chart/antv-bar/chartcompile/index.scss                         |    3 
 src/menu/components/share/styleInput/index.jsx                                     |  140 
 src/menu/components/chart/antv-scatter/chartcompile/index.jsx                      |  271 
 src/templates/zshare/verifycard/customscript/index.jsx                             |    7 
 src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx          |  118 
 src/menu/components/chart/antv-scatter/index.jsx                                   |  404 
 src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx  |    6 
 src/views/interface/workspace/index.jsx                                            |  123 
 src/tabviews/zshare/mutilform/mkInput/index.jsx                                    |   84 
 src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx               |  233 
 src/tabviews/zshare/mutilform/mkNumberInput/index.jsx                              |   67 
 src/pc/components/login/wrapsetting/settingform/index.jsx                          |  270 
 src/menu/components/card/cardcomponent/pastecomponent/index.scss                   |    0 
 src/mob/searchconfig/groupdragelement/index.scss                                   |   27 
 src/views/interface/header/index.jsx                                               |   45 
 src/tabviews/zshare/mutilform/mkCheckCard/index.scss                               |   98 
 src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx          |  130 
 src/templates/sharecomponent/settingcomponent/settingform/datasource/index.jsx     |   20 
 src/pc/menushell/card.jsx                                                          |   46 
 src/menu/components/carousel/prop-card/index.jsx                                   |   29 
 src/menu/components/search/main-search/dragsearch/card.jsx                         |   66 
 src/menu/components/chart/antv-pie/index.jsx                                       |  384 
 src/menu/components/share/mobPagination/index.scss                                 |   14 
 src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx           |   62 
 src/tabviews/zshare/mutilform/mkCheckbox/index.scss                                |    0 
 src/menu/components/table/normal-table/wrapsetting/settingform/index.jsx           |   66 
 src/menu/components/tabs/tabcomponents/card.jsx                                    |   15 
 src/tabviews/zshare/fileupload/index.scss                                          |   15 
 src/templates/sharecomponent/treesettingcomponent/index.jsx                        |   11 
 src/templates/zshare/modalform/modaleditable/index.jsx                             |    5 
 src/assets/mobimg/scatter.png                                                      |    0 
 src/menu/modalconfig/controller.jsx                                                |    6 
 src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx              |   14 
 src/menu/datasource/verifycard/utils.jsx                                           |   32 
 src/mob/searchconfig/groupform/index.scss                                          |   18 
 src/tabviews/custom/components/chart/antv-bar-line/index.jsx                       | 1061 +
 src/tabviews/custom/components/chart/antv-dashboard/index.jsx                      |  618 
 src/views/login/loginform.jsx                                                      |   78 
 src/menu/components/card/balcony/wrapsetting/settingform/index.jsx                 |  415 
 src/tabviews/formtab/formgroup/index.jsx                                           |   55 
 src/menu/components/share/actioncomponent/dragaction/card.jsx                      |    8 
 src/templates/comtableconfig/index.jsx                                             |    2 
 src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx                   |   54 
 src/mob/searchconfig/pastecomponent/index.jsx                                      |   57 
 src/menu/components/tabs/antv-tabs/dragabletabs.jsx                                |   16 
 src/views/printTemplate/print.js                                                   |   10 
 src/tabviews/zshare/topSearch/index.scss                                           |   33 
 src/pc/transfer/settingform/index.jsx                                              |   69 
 src/menu/sysinterface/settingform/baseform/index.jsx                               |    4 
 src/views/interface/workspace/request/index.jsx                                    |  310 
 src/menu/components/group/groupcomponents/index.scss                               |    5 
 src/menu/datasource/verifycard/settingform/index.jsx                               |   39 
 src/menu/components/share/actioncomponent/index.jsx                                |   52 
 src/mob/searchconfig/source.jsx                                                    |   33 
 src/menu/picturecontroller/editform/index.jsx                                      |   63 
 src/menu/popview/index.scss                                                        |  162 
 src/tabviews/zshare/mutilform/mkCheckbox/index.jsx                                 |   39 
 src/pc/createview/settingform/index.jsx                                            |  107 
 src/tabviews/zshare/imgScale/index.scss                                            |   20 
 src/menu/stylecombcontrolbutton/index.scss                                         |   10 
 src/tabviews/custom/components/tree/antd-tree/index.jsx                            |  452 
 src/tabviews/zshare/actionList/popupbutton/index.jsx                               |   60 
 src/tabviews/custom/components/tabs/antv-tabs/index.jsx                            |    4 
 src/menu/components/share/searchcomponent/index.jsx                                |    2 
 src/views/interface/index.scss                                                     |    6 
 src/templates/treepageconfig/index.jsx                                             |    3 
 src/menu/components/form/formaction/index.jsx                                      |   23 
 src/tabviews/custom/index.scss                                                     |    6 
 src/views/billprint/index.jsx                                                      |   40 
 src/tabviews/subtabtable/index.jsx                                                 |   93 
 src/menu/replaceField/index.scss                                                   |    9 
 src/views/menudesign/index.jsx                                                     |  113 
 src/tabviews/custom/components/card/data-card/index.jsx                            |  144 
 src/menu/replaceField/settingform/index.jsx                                        |   78 
 src/pc/components/navbar/normal-navbar/linksetting/linkform/index.jsx              |   22 
 src/tabviews/verupmanage/config.jsx                                                |    6 
 src/tabviews/zshare/mutilform/checkCard/index.jsx                                  |   29 
 src/router/index.js                                                                |   39 
 src/menu/components/card/cardcomponent/settingform/index.scss                      |    5 
 src/menu/components/card/data-card/index.jsx                                       |  116 
 src/menu/components/chart/antv-dashboard/index.jsx                                 |  538 
 src/views/appmanage/index.jsx                                                      |  913 +
 src/menu/components/tabs/antv-tabs/index.jsx                                       |   86 
 src/templates/sharecomponent/searchcomponent/index.scss                            |   10 
 src/menu/modulesource/index.jsx                                                    |    1 
 src/templates/sharecomponent/settingcomponent/index.jsx                            |   33 
 src/views/design/index.jsx                                                         |    5 
 src/mob/components/menubar/normal-menubar/menucomponent/index.scss                 |    0 
 src/templates/subtableconfig/source.jsx                                            |   12 
 src/menu/components/tree/antd-tree/index.scss                                      |   36 
 src/tabviews/custom/components/chart/antv-bar-line/index.scss                      |   48 
 src/views/interface/api/index.js                                                   |  175 
 src/mob/modalconfig/source.jsx                                                     |  104 
 src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx             |  105 
 src/tabviews/calendar/index.jsx                                                    |   69 
 src/pc/quotecomponent/index.jsx                                                    |    2 
 src/templates/zshare/editcomponent/index.jsx                                       |   82 
 src/views/rolemanage/index.jsx                                                     |  813 +
 src/tabviews/custom/components/carousel/data-card/index.jsx                        |   28 
 src/tabviews/zshare/mutilform/mkSelect/index.jsx                                   |  179 
 src/templates/zshare/verifycard/customform/index.jsx                               |    7 
 src/tabviews/custom/components/tree/antd-tree/index.scss                           |   97 
 src/mob/modalconfig/pastecomponent/index.jsx                                       |   76 
 src/templates/sharecomponent/settingcalcomponent/index.jsx                         |   11 
 src/views/interface/header/index.scss                                              |   63 
 src/menu/components/card/balcony/index.jsx                                         |  237 
 src/menu/components/tree/antd-tree/wrapsetting/settingform/index.scss              |   15 
 src/tabviews/zshare/actionList/tabbutton/index.jsx                                 |   49 
 src/menu/stylecontroller/index.jsx                                                 |   83 
 src/views/rolemanage/index.scss                                                    |   90 
 src/menu/components/card/cardcellcomponent/formconfig.jsx                          |   72 
 src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.jsx      |  302 
 src/pc/components/login/wrapsetting/index.scss                                     |    7 
 src/menu/stylecombcontrolbutton/index.jsx                                          |    8 
 src/tabviews/zshare/fileupload/index.jsx                                           |  208 
 src/tabviews/zshare/topSearch/dategroup/index.scss                                 |    0 
 src/menu/components/card/cardcellcomponent/index.scss                              |    7 
 src/mob/components/navbar/normal-navbar/menusetting/menuform/index.scss            |   10 
 src/templates/modalconfig/index.jsx                                                |   11 
 src/templates/sharecomponent/searchcomponent/searchform/index.scss                 |   15 
 src/templates/sharecomponent/tablecomponent/index.jsx                              |    1 
 src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx              |   23 
 src/mob/modalconfig/index.jsx                                                      |  466 
 src/mob/modalconfig/index.scss                                                     |  321 
 src/views/interface/index.jsx                                                      |   28 
 src/menu/components/form/formaction/formconfig.jsx                                 |   10 
 src/tabviews/custom/components/card/prop-card/index.jsx                            |   55 
 src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx                      |   81 
 src/menu/components/tree/antd-tree/wrapsetting/index.jsx                           |   83 
 src/mob/components/menubar/normal-menubar/index.jsx                                |  265 
 src/templates/sharecomponent/treesettingcomponent/settingform/datasource/index.jsx |    4 
 src/views/interface/history/index.scss                                             |  113 
 src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx   |   22 
 src/menu/components/chart/antv-pie/index.scss                                      |    4 
 src/tabviews/zshare/topSearch/dategroup/yearpicker/index.jsx                       |    0 
 src/tabviews/custom/components/chart/antv-pie/index.jsx                            |  525 
 src/templates/subtableconfig/index.jsx                                             |    2 
 src/tabviews/zshare/mutilform/checkCard/index.scss                                 |   64 
 src/tabviews/zshare/topSearch/dategroup/index.jsx                                  |  138 
 src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx            |   12 
 src/menu/components/card/table-card/cardcomponent/settingform/index.jsx            |    1 
 src/templates/zshare/modalform/index.scss                                          |    8 
 src/tabviews/custom/index.jsx                                                      |  366 
 src/tabviews/zshare/mutilform/mkTextArea/index.jsx                                 |   92 
 src/menu/components/card/data-card/wrapsetting/settingform/index.jsx               |   58 
 src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx            |    8 
 src/mob/searchconfig/pastecomponent/index.scss                                     |    0 
 src/views/appmanage/submutilform/index.jsx                                         |  144 
 src/tabviews/custom/components/chart/antv-dashboard/index.scss                     |  110 
 src/views/design/header/index.jsx                                                  |    7 
 src/assets/mobimg/login.png                                                        |    0 
 src/menu/components/group/groupcomponents/index.jsx                                |   55 
 src/templates/zshare/basetransferform/index.jsx                                    |    4 
 src/menu/components/form/formaction/actionform/index.jsx                           |    4 
 src/assets/mobimg/dashboard.png                                                    |    0 
 src/tabviews/custom/components/carousel/data-card/index.scss                       |    1 
 src/menu/components/card/cardcellcomponent/dragaction/index.jsx                    |    7 
 src/menu/components/form/normal-form/index.jsx                                     |  138 
 src/pc/menushell/index.jsx                                                         |   16 
 src/tabviews/zshare/actionList/exceloutbutton/index.jsx                            |  195 
 src/menu/components/card/cardcellcomponent/dragaction/card.jsx                     |   28 
 src/menu/components/chart/antv-bar/index.jsx                                       |  658 
 src/pc/modulesource/index.jsx                                                      |    1 
 src/views/appmanage/submutilform/index.scss                                        |    6 
 src/assets/mobimg/tree.png                                                         |    0 
 src/views/rolemanage/header/index.jsx                                              |   32 
 src/menu/components/card/data-card/wrapsetting/index.jsx                           |    4 
 src/menu/components/carousel/data-card/index.jsx                                   |   29 
 src/mob/components/navbar/normal-navbar/menusetting/index.scss                     |   11 
 src/mob/components/menubar/normal-menubar/menucomponent/index.jsx                  |  218 
 src/tabviews/zshare/mutilform/mkCheckCard/index.jsx                                |  140 
 src/menu/components/share/normalheader/index.jsx                                   |   16 
 src/templates/modalconfig/settingform/index.jsx                                    |   90 
 src/pc/components/login/normal-login/loginform.jsx                                 |  139 
 src/menu/components/search/main-search/index.jsx                                   |   43 
 src/tabviews/scriptmanage/index.jsx                                                |   70 
 src/assets/mobimg/menubar.png                                                      |    0 
 src/menu/components/tabs/tabsetting/settingform/index.jsx                          |   22 
 src/mob/searchconfig/controller.jsx                                                |   62 
 src/views/login/index.jsx                                                          |   12 
 src/pc/transfer/index.jsx                                                          |  132 
 src/tabviews/zshare/mutilform/mkRadio/index.jsx                                    |   40 
 src/mob/components/navbar/normal-navbar/index.jsx                                  |  187 
 src/utils/utils-datamanage.js                                                      |  179 
 src/menu/components/search/main-search/wrapsetting/settingform/index.jsx           |   24 
 src/utils/utils-custom.js                                                          |  177 
 src/views/interface/workspace/editTable/index.jsx                                  |  249 
 src/views/printTemplate/mutilform/index.scss                                       |   14 
 config/env.js                                                                      |    2 
 src/menu/components/share/searchcomponent/dragsearch/card.jsx                      |    2 
 src/tabviews/custom/components/carousel/prop-card/index.scss                       |    1 
 src/menu/components/tabs/tabcomponents/index.jsx                                   |   12 
 src/menu/components/table/normal-table/columns/editColumn/index.jsx                |   63 
 src/menu/components/card/data-card/index.scss                                      |   19 
 src/menu/menushell/card.jsx                                                        |   12 
 src/mob/searchconfig/settingform/index.scss                                        |   23 
 src/templates/sharecomponent/settingcomponent/settingform/index.jsx                |   48 
 src/menu/components/chart/antv-scatter/chartcompile/index.scss                     |   41 
 src/templates/modalconfig/dragelement/card.jsx                                     |    4 
 src/views/interface/history/index.jsx                                              |  290 
 src/tabviews/zshare/mutilform/mkColor/index.scss                                   |   41 
 src/mob/components/navbar/normal-navbar/menusetting/menutable/index.scss           |   23 
 src/mob/modalconfig/pastecomponent/index.scss                                      |    0 
 src/api/cacheutils.js                                                              |   31 
 src/views/printTemplate/mutilform/index.jsx                                        |   83 
 src/views/design/sidemenu/config.jsx                                               |   20 
 src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.jsx        |  155 
 src/menu/components/card/balcony/wrapsetting/index.jsx                             |   83 
 src/mob/colorsketch/index.scss                                                     |   18 
 src/tabviews/zshare/topSearch/advanceform/index.scss                               |   41 
 src/menu/components/table/normal-table/index.jsx                                   |   31 
 src/menu/components/group/normal-group/index.jsx                                   |   10 
 src/tabviews/zshare/actionList/asyncButtonComponent.jsx                            |   18 
 src/mob/components/navbar/normal-navbar/wrapsetting/index.scss                     |    7 
 src/components/tabview/index.jsx                                                   |    2 
 src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx           |   72 
 src/views/design/header/index.scss                                                 |    7 
 src/tabviews/zshare/mutilform/mkSwitch/index.jsx                                   |   43 
 src/menu/datasource/verifycard/customscript/index.jsx                              |   10 
 src/pc/transfer/settingform/index.scss                                             |   11 
 src/mob/searchconfig/index.scss                                                    |  365 
 src/pc/components/login/wrapsetting/settingform/index.scss                         |   11 
 src/tabviews/custom/components/chart/antv-pie/index.scss                           |    5 
 src/tabviews/zshare/topSearch/mkSelect/index.jsx                                   |  121 
 config/paths.js                                                                    |    2 
 src/tabviews/zshare/mutilform/mkColor/index.jsx                                    |   60 
 src/tabviews/custom/components/share/normalTable/index.jsx                         |   30 
 src/templates/modalconfig/dragelement/index.jsx                                    |    3 
 src/tabviews/custom/components/card/data-card/index.scss                           |   22 
 src/menu/components/search/main-search/index.scss                                  |   44 
 src/menu/components/share/usercomponent/index.jsx                                  |    1 
 src/assets/mobimg/nest.png                                                         |    0 
 src/menu/components/form/wrapsetting/settingform/index.jsx                         |   17 
 src/menu/components/share/pastecomponent/index.jsx                                 |   51 
 src/templates/zshare/formconfig.jsx                                                |  717 
 src/tabviews/zshare/mutilform/mkSwitch/index.scss                                  |    0 
 src/pc/createview/index.jsx                                                        |  201 
 src/tabviews/custom/components/form/normal-form/index.jsx                          |  140 
 src/mob/components/formdragelement/card.jsx                                        |  200 
 src/pc/components/login/normal-login/index.jsx                                     |  170 
 src/tabviews/custom/components/chart/antv-scatter/asyncButtonComponent.jsx         |   34 
 /dev/null                                                                          |   88 
 src/templates/menuconfig/editsecmenu/index.jsx                                     |   32 
 src/tabviews/custom/components/card/cardcellList/index.scss                        |   23 
 src/menu/menushell/index.jsx                                                       |   13 
 src/templates/sharecomponent/columncomponent/columnform/index.jsx                  |    3 
 478 files changed, 32,754 insertions(+), 7,141 deletions(-)

diff --git a/config/env.js b/config/env.js
index b0344c5..f8c5326 100644
--- a/config/env.js
+++ b/config/env.js
@@ -1,4 +1,4 @@
-'use strict';
+// 'use strict';
 
 const fs = require('fs');
 const path = require('path');
diff --git a/config/modules.js b/config/modules.js
index 46d9c9e..10c4374 100644
--- a/config/modules.js
+++ b/config/modules.js
@@ -1,4 +1,4 @@
-'use strict';
+// 'use strict';
 
 const fs = require('fs');
 const path = require('path');
diff --git a/config/paths.js b/config/paths.js
index f23c121..68fc8d7 100644
--- a/config/paths.js
+++ b/config/paths.js
@@ -1,4 +1,4 @@
-'use strict';
+// 'use strict';
 
 const path = require('path');
 const fs = require('fs');
diff --git a/config/pnpTs.js b/config/pnpTs.js
index d1b0539..6a3b546 100644
--- a/config/pnpTs.js
+++ b/config/pnpTs.js
@@ -1,4 +1,4 @@
-'use strict';
+// 'use strict';
 
 const { resolveModuleName } = require('ts-pnp');
 
diff --git a/config/webpack.config.js b/config/webpack.config.js
index 54b9961..a793358 100644
--- a/config/webpack.config.js
+++ b/config/webpack.config.js
@@ -173,14 +173,16 @@
       pathinfo: isEnvDevelopment,
       // There will be one main bundle, and one file per asynchronous chunk.
       // In development, it does not produce real files.
+      // contenthash => hash
       filename: isEnvProduction
-        ? 'static/js/[name].[contenthash:8].js'
+        ? 'static/js/[name].[hash:8].js'
         : isEnvDevelopment && 'static/js/bundle.js',
       // TODO: remove this when upgrading to webpack 5
       futureEmitAssets: true,
       // There are also additional JS chunk files if you use code splitting.
+      // contenthash => hash
       chunkFilename: isEnvProduction
-        ? 'static/js/[name].[contenthash:8].chunk.js'
+        ? 'static/js/[name].[hash:8].chunk.js'
         : isEnvDevelopment && 'static/js/[name].chunk.js',
       // We inferred the "public path" (such as / or /my-project) from homepage.
       // We use "/" in development.
@@ -565,8 +567,9 @@
         new MiniCssExtractPlugin({
           // Options similar to the same options in webpackOptions.output
           // both options are optional
-          filename: 'static/css/[name].[contenthash:8].css',
-          chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
+          // contenthash => hash
+          filename: 'static/css/[name].[hash:8].css',
+          chunkFilename: 'static/css/[name].[hash:8].chunk.css',
         }),
       // Generate a manifest file which contains a mapping of all asset filenames
       // to their corresponding output file so that tools can pick it up without
diff --git a/config/webpackDevServer.config.js b/config/webpackDevServer.config.js
index 33ab8d3..a90fc24 100644
--- a/config/webpackDevServer.config.js
+++ b/config/webpackDevServer.config.js
@@ -1,4 +1,4 @@
-'use strict';
+// 'use strict';
 
 const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
 const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
diff --git a/package-lock.json b/package-lock.json
index fd8ff65..2a72c49 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -60,47 +60,74 @@
       }
     },
     "@antv/color-util": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.5.tgz",
-      "integrity": "sha512-eQktA9YDnWCj03rfjpg0ajvCfRkHXzBzsZa9z94pY6Jb7e3XtPUp7vDpB8KhaKm9GjPtGzQDneh+gnqkEK8mtQ==",
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/@antv/color-util/-/color-util-2.0.6.tgz",
+      "integrity": "sha512-KnPEaAH+XNJMjax9U35W67nzPI+QQ2x27pYlzmSIWrbj4/k8PGrARXfzDTjwoozHJY8qG62Z+Ww6Alhu2FctXQ==",
       "requires": {
         "@antv/util": "^2.0.9",
-        "tslib": "^1.10.0"
+        "tslib": "^2.0.3"
       },
       "dependencies": {
         "@antv/util": {
-          "version": "2.0.9",
-          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.9.tgz",
-          "integrity": "sha512-JblWzne7msAPDdxkUhEk8zAz0Wd6igKwqymGbvIeyOydGrhBhGjA3nEayFj4IlG+XixCvGFKsCB4yuFS4glRIA==",
+          "version": "2.0.13",
+          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.13.tgz",
+          "integrity": "sha512-mfYL7K8XJIeDmal33K+6abr8Yb526YXKg5XQlddNo+X1Doll+gun6HxnbdySoLv21vW4bLkcbVPjqxWl7ZJAFA==",
           "requires": {
-            "tslib": "^1.10.0"
+            "tslib": "^2.0.3"
           }
+        },
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
         }
       }
     },
     "@antv/component": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.2.tgz",
-      "integrity": "sha512-aU65T9jD85H+3WhhmgPz8kiuqxJGPuHFgRiBYmR+vQUnAA2nOW2bCafiNx/bSEAqmVgsr+8e+9IDQZ6PowIgtQ==",
+      "version": "0.8.11",
+      "resolved": "https://registry.npmjs.org/@antv/component/-/component-0.8.11.tgz",
+      "integrity": "sha512-7hl7IPPF/QmE25lrZhppEW8BYJzU3SE6IGq4/NhrvcDk79Xhm1L4KOcAAcZ0zYBRaOwQL3yMcraIL+/Z1UhLjw==",
       "requires": {
         "@antv/dom-util": "~2.0.1",
-        "@antv/g-base": "~0.5.0",
+        "@antv/g-base": "0.5.6",
         "@antv/matrix-util": "^3.1.0-beta.1",
         "@antv/path-util": "~2.0.7",
         "@antv/scale": "~0.3.1",
         "@antv/util": "~2.0.0",
         "fecha": "~4.2.0",
-        "tslib": "^1.10.0"
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/coord": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.0.tgz",
-      "integrity": "sha512-lm5Ct+r62mFVqhziKoDFN3PQjnkNBMOoOG+kBsPq3M3GqlQt5Jc7euOHMFcYSZM9HJmsKkGcih6EWDVVliMEZg==",
+      "version": "0.3.1",
+      "resolved": "https://registry.npmjs.org/@antv/coord/-/coord-0.3.1.tgz",
+      "integrity": "sha512-rFE94C8Xzbx4xmZnHh2AnlB3Qm1n5x0VT3OROy257IH6Rm4cuzv1+tZaUBATviwZd99S+rOY9telw/+6C9GbRw==",
       "requires": {
         "@antv/matrix-util": "^3.1.0-beta.2",
-        "@antv/util": "~2.0.3",
-        "tslib": "^1.10.0"
+        "@antv/util": "~2.0.12",
+        "tslib": "^2.1.0"
+      },
+      "dependencies": {
+        "@antv/util": {
+          "version": "2.0.13",
+          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.13.tgz",
+          "integrity": "sha512-mfYL7K8XJIeDmal33K+6abr8Yb526YXKg5XQlddNo+X1Doll+gun6HxnbdySoLv21vW4bLkcbVPjqxWl7ZJAFA==",
+          "requires": {
+            "tslib": "^2.0.3"
+          }
+        },
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/data-set": {
@@ -127,11 +154,18 @@
       }
     },
     "@antv/dom-util": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.2.tgz",
-      "integrity": "sha512-i/rh385casRd6OA4rbpbA2jyiwY/w7PtkA+74mH43PiBzOcLpDg1jEWR9dMO0tIqUzHQWWqKNNjmXVubl4GS6g==",
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/@antv/dom-util/-/dom-util-2.0.3.tgz",
+      "integrity": "sha512-dUHsUT4U9X1T1/Y9bH3jRMe0MzvWJk2jSQm1vm3w9NX+Ra0ftq5VUBiGTNbthm3nFwG0fFFjip904rYjl50g4A==",
       "requires": {
-        "tslib": "^1.10.0"
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/event-emitter": {
@@ -140,81 +174,105 @@
       "integrity": "sha512-6C6NJOdoNVptCr5y9BVOhKkCgW7LFs/SpcRyAExUeSjAm0zJqcqNkSIRGsXYhj4PJI+CZICHzGwwiSnIsE68Ug=="
     },
     "@antv/g-base": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.1.tgz",
-      "integrity": "sha512-gbv+uz/SvzM4/p3PLjAiEZUp6kdzKkCbVWTCdBXB1cvNMttlEzWEB8MOFbEkcIAy7TtjQJJRv8ThI/ngFzU+fg==",
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/@antv/g-base/-/g-base-0.5.6.tgz",
+      "integrity": "sha512-szxqFQ/xdCnfaeSEEC2kVjXdKxJnvKKJNT0MvaOG3UXOfsjPDLgb3IKLr+bU3sLvTAQfPhsbtYh7mWb03+mGjA==",
       "requires": {
         "@antv/event-emitter": "^0.1.1",
-        "@antv/g-math": "^0.1.5",
+        "@antv/g-math": "^0.1.6",
         "@antv/matrix-util": "^3.1.0-beta.1",
         "@antv/path-util": "~2.0.5",
         "@antv/util": "~2.0.0",
-        "@types/d3-timer": "^1.0.9",
+        "@types/d3-timer": "^2.0.0",
         "d3-ease": "^1.0.5",
         "d3-interpolate": "^1.3.2",
         "d3-timer": "^1.0.9",
-        "detect-browser": "^5.1.0"
+        "detect-browser": "^5.1.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/g-canvas": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.3.tgz",
-      "integrity": "sha512-80k1BbiY05heHKUm4o6IL6KVRZS+uAgzdIF2OaC9grQc6KxrJoK2dCxKpmna3NBHTU9Sm+/rsiGcL7lp7S+ecQ==",
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/@antv/g-canvas/-/g-canvas-0.5.6.tgz",
+      "integrity": "sha512-r6f6KqYuNZWunf2Vnf1ACopn8aic6TBFhaN3XuckenhQNqR+/PI/4Mft7z14zo7WH58X2Xs2Npq9awJXBEUzaw==",
       "requires": {
-        "@antv/g-base": "^0.5.1",
-        "@antv/g-math": "^0.1.5",
+        "@antv/g-base": "^0.5.3",
+        "@antv/g-math": "^0.1.6",
         "@antv/matrix-util": "^3.1.0-beta.1",
         "@antv/path-util": "~2.0.5",
         "@antv/util": "~2.0.0",
-        "gl-matrix": "^3.0.0"
+        "gl-matrix": "^3.0.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/g-math": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.5.tgz",
-      "integrity": "sha512-29B3p33jzUPIyx1xYfNCexbp7jvahD6bD8FKKyWqfYZHQbvrFfV8ZNUu66RJLfDrl0KaKT6C5whfKs/WrVaflQ==",
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/@antv/g-math/-/g-math-0.1.7.tgz",
+      "integrity": "sha512-xGyXaloD1ynfp7gS4VuV+MjSptZIwHvLHr8ekXJSFAeWPYLu84yOW2wOZHDdp1bzDAIuRv6xDBW58YGHrWsFcA==",
       "requires": {
         "@antv/util": "~2.0.0",
         "gl-matrix": "^3.0.0"
       }
     },
     "@antv/g-svg": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.2.tgz",
-      "integrity": "sha512-T0PYjIM+WX6zv3yUgSkyRcHFq4hlio0MeRGoJR60P5U5MNSdkZnblcu79cpU2i42Z7wBr404Kv1dplCGxC38PA==",
+      "version": "0.5.6",
+      "resolved": "https://registry.npmjs.org/@antv/g-svg/-/g-svg-0.5.6.tgz",
+      "integrity": "sha512-Xve1EUGk4HMbl2nq4ozR4QLh6GyoZ8Xw/+9kHYI4B5P2lIUQU95MuRsaLFfW5NNpZDx85ZeH97tqEmC9L96E7A==",
       "requires": {
-        "@antv/g-base": "^0.5.1",
-        "@antv/g-math": "^0.1.5",
+        "@antv/g-base": "^0.5.3",
+        "@antv/g-math": "^0.1.6",
         "@antv/util": "~2.0.0",
-        "detect-browser": "^5.0.0"
+        "detect-browser": "^5.0.0",
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@antv/g2": {
-      "version": "4.1.0-beta.18",
-      "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.1.0-beta.18.tgz",
-      "integrity": "sha512-RW3e95V2aUtys36guS7PNHbfgyYZgigu18OLSYPkgyRLF0pPABcSrIot+xnVGQ4Cx0ZDmhJVTvpXjU4QMa96kw==",
+      "version": "4.1.14",
+      "resolved": "https://registry.npmjs.org/@antv/g2/-/g2-4.1.14.tgz",
+      "integrity": "sha512-JdU+0suxkDqjTZNyG915zQ7eM+bdT2fHV48VGc1LvCroUHzCncCnbx5HZ19aZhvuij2hM6eh52vb8mwIXIzMBw==",
       "requires": {
         "@antv/adjust": "^0.2.1",
         "@antv/attr": "^0.3.1",
         "@antv/color-util": "^2.0.2",
-        "@antv/component": "^0.8.0",
+        "@antv/component": "^0.8.7",
         "@antv/coord": "^0.3.0",
         "@antv/dom-util": "^2.0.2",
         "@antv/event-emitter": "~0.1.0",
-        "@antv/g-base": "^0.5.0",
-        "@antv/g-canvas": "^0.5.0",
-        "@antv/g-svg": "^0.5.0",
+        "@antv/g-base": "0.5.6",
+        "@antv/g-canvas": "0.5.6",
+        "@antv/g-svg": "0.5.6",
         "@antv/matrix-util": "^3.1.0-beta.1",
         "@antv/path-util": "^2.0.3",
-        "@antv/scale": "^0.3.1",
+        "@antv/scale": "^0.3.7",
         "@antv/util": "~2.0.5",
         "tslib": "^2.0.0"
       },
       "dependencies": {
         "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
         }
       }
     },
@@ -237,38 +295,50 @@
       },
       "dependencies": {
         "@antv/util": {
-          "version": "2.0.9",
-          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.9.tgz",
-          "integrity": "sha512-JblWzne7msAPDdxkUhEk8zAz0Wd6igKwqymGbvIeyOydGrhBhGjA3nEayFj4IlG+XixCvGFKsCB4yuFS4glRIA==",
+          "version": "2.0.13",
+          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.13.tgz",
+          "integrity": "sha512-mfYL7K8XJIeDmal33K+6abr8Yb526YXKg5XQlddNo+X1Doll+gun6HxnbdySoLv21vW4bLkcbVPjqxWl7ZJAFA==",
           "requires": {
-            "tslib": "^1.10.0"
+            "tslib": "^2.0.3"
+          },
+          "dependencies": {
+            "tslib": {
+              "version": "2.2.0",
+              "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+              "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+            }
           }
         }
       }
     },
     "@antv/path-util": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.8.tgz",
-      "integrity": "sha512-g5gt12MY1oEzh/j5XfLNRCfJU7E+Us+2yM5Hqc0y8xeWhb5l013XG5BPV37KmOf6WAys9KNxklNniHCZ6SqCKw==",
+      "version": "2.0.9",
+      "resolved": "https://registry.npmjs.org/@antv/path-util/-/path-util-2.0.9.tgz",
+      "integrity": "sha512-kunEz4dNheQMVn4rVFsoBDx+n9Knfi3uRLvDk9SojZAqpninsjFhdoiYtbExwJGz1FYGtiV10Y6N1tp73kZFcg==",
       "requires": {
         "@antv/util": "^2.0.9",
-        "tslib": "^1.10.0"
+        "tslib": "^2.0.3"
       },
       "dependencies": {
         "@antv/util": {
-          "version": "2.0.9",
-          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.9.tgz",
-          "integrity": "sha512-JblWzne7msAPDdxkUhEk8zAz0Wd6igKwqymGbvIeyOydGrhBhGjA3nEayFj4IlG+XixCvGFKsCB4yuFS4glRIA==",
+          "version": "2.0.13",
+          "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.13.tgz",
+          "integrity": "sha512-mfYL7K8XJIeDmal33K+6abr8Yb526YXKg5XQlddNo+X1Doll+gun6HxnbdySoLv21vW4bLkcbVPjqxWl7ZJAFA==",
           "requires": {
-            "tslib": "^1.10.0"
+            "tslib": "^2.0.3"
           }
+        },
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
         }
       }
     },
     "@antv/scale": {
-      "version": "0.3.4",
-      "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.4.tgz",
-      "integrity": "sha512-mZaf3MtMoQJtd+KAgTANVbvKpaXVpzLAFbKO/wSKaLFpnWO0bwMVDYzrs+5DZhfEfMbZpP/A7qUZ2/DLh0T3Tg==",
+      "version": "0.3.9",
+      "resolved": "https://registry.npmjs.org/@antv/scale/-/scale-0.3.9.tgz",
+      "integrity": "sha512-m56Rs4Zta7XnuF+aNbJXMsgBqATO1M4kvu+dEmhzLYsPK5D3dHpJTOGh/Zy55eirekb9F7jiu29SJqPNnhxq+g==",
       "requires": {
         "@antv/util": "~2.0.3",
         "fecha": "~4.2.0",
@@ -276,18 +346,25 @@
       },
       "dependencies": {
         "tslib": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.0.3.tgz",
-          "integrity": "sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ=="
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
         }
       }
     },
     "@antv/util": {
-      "version": "2.0.8",
-      "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.8.tgz",
-      "integrity": "sha512-G9QRygQJ8UNGMi8L1dfMIa4SofbEO+jkXwvRY4ek/MLd04Q01UN0U28JeMFzw6FCKJdxiFu+2uwT/zjoFr3QoQ==",
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/@antv/util/-/util-2.0.13.tgz",
+      "integrity": "sha512-mfYL7K8XJIeDmal33K+6abr8Yb526YXKg5XQlddNo+X1Doll+gun6HxnbdySoLv21vW4bLkcbVPjqxWl7ZJAFA==",
       "requires": {
-        "tslib": "^1.10.0"
+        "tslib": "^2.0.3"
+      },
+      "dependencies": {
+        "tslib": {
+          "version": "2.2.0",
+          "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
+          "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+        }
       }
     },
     "@babel/code-frame": {
@@ -1464,6 +1541,33 @@
       "resolved": "https://registry.npmjs.org/@csstools/normalize.css/-/normalize.css-9.0.1.tgz",
       "integrity": "sha512-6It2EVfGskxZCQhuykrfnALg7oVeiI6KclWSmGDqB0AiInVrTGB9Jp9i4/Ad21u9Jde/voVQz6eFX/eSg/UsPA=="
     },
+    "@fast-csv/format": {
+      "version": "4.3.5",
+      "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz",
+      "integrity": "sha512-8iRn6QF3I8Ak78lNAa+Gdl5MJJBM5vRHivFtMRUWINdevNo00K7OXxS2PshawLKTejVwieIlPmK5YlLu6w4u8A==",
+      "requires": {
+        "@types/node": "^14.0.1",
+        "lodash.escaperegexp": "^4.1.2",
+        "lodash.isboolean": "^3.0.3",
+        "lodash.isequal": "^4.5.0",
+        "lodash.isfunction": "^3.0.9",
+        "lodash.isnil": "^4.0.0"
+      }
+    },
+    "@fast-csv/parse": {
+      "version": "4.3.6",
+      "resolved": "https://registry.npmjs.org/@fast-csv/parse/-/parse-4.3.6.tgz",
+      "integrity": "sha512-uRsLYksqpbDmWaSmzvJcuApSEe38+6NQZBUsuAyMZKqHxH0g1wcJgsKUvN3WC8tewaqFjBMMGrkHmC+T7k8LvA==",
+      "requires": {
+        "@types/node": "^14.0.1",
+        "lodash.escaperegexp": "^4.1.2",
+        "lodash.groupby": "^4.6.0",
+        "lodash.isfunction": "^3.0.9",
+        "lodash.isnil": "^4.0.0",
+        "lodash.isundefined": "^3.0.1",
+        "lodash.uniq": "^4.5.0"
+      }
+    },
     "@hapi/address": {
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/@hapi/address/-/address-2.1.1.tgz",
@@ -2376,9 +2480,9 @@
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
     },
     "@types/d3-timer": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.10.tgz",
-      "integrity": "sha512-ZnAbquVqy+4ZjdW0cY6URp+qF/AzTVNda2jYyOzpR2cPT35FTXl78s15Bomph9+ckOiI1TtkljnWkwbIGAb6rg=="
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-2.0.0.tgz",
+      "integrity": "sha512-l6stHr1VD1BWlW6u3pxrjLtJfpPZq9I3XmKIQtq7zHM/s6fwEtI1Yn6Sr5/jQTrUDCC5jkS6gWqlFGCDArDqNg=="
     },
     "@types/eslint-visitor-keys": {
       "version": "1.0.0",
@@ -2425,6 +2529,11 @@
       "version": "7.0.3",
       "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.3.tgz",
       "integrity": "sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A=="
+    },
+    "@types/node": {
+      "version": "14.14.44",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.44.tgz",
+      "integrity": "sha512-+gaugz6Oce6ZInfI/tK4Pq5wIIkJMEJUu92RB3Eu93mtj4wjjjz9EB5mLp5s1pSsLXdC/CPut/xF20ZzAQJbTA=="
     },
     "@types/prop-types": {
       "version": "15.7.2",
@@ -3151,6 +3260,61 @@
       "version": "1.2.0",
       "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
       "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
+    },
+    "archiver": {
+      "version": "5.3.0",
+      "resolved": "https://registry.npmjs.org/archiver/-/archiver-5.3.0.tgz",
+      "integrity": "sha512-iUw+oDwK0fgNpvveEsdQ0Ase6IIKztBJU2U0E9MzszMfmVVUyv1QJhS2ITW9ZCqx8dktAxVAjWWkKehuZE8OPg==",
+      "requires": {
+        "archiver-utils": "^2.1.0",
+        "async": "^3.2.0",
+        "buffer-crc32": "^0.2.1",
+        "readable-stream": "^3.6.0",
+        "readdir-glob": "^1.0.0",
+        "tar-stream": "^2.2.0",
+        "zip-stream": "^4.1.0"
+      },
+      "dependencies": {
+        "async": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
+          "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
+    "archiver-utils": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz",
+      "integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
+      "requires": {
+        "glob": "^7.1.4",
+        "graceful-fs": "^4.2.0",
+        "lazystream": "^1.0.0",
+        "lodash.defaults": "^4.2.0",
+        "lodash.difference": "^4.5.0",
+        "lodash.flatten": "^4.4.0",
+        "lodash.isplainobject": "^4.0.6",
+        "lodash.union": "^4.6.0",
+        "normalize-path": "^3.0.0",
+        "readable-stream": "^2.0.0"
+      },
+      "dependencies": {
+        "normalize-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+        }
+      }
     },
     "are-we-there-yet": {
       "version": "1.1.5",
@@ -4033,10 +4197,50 @@
       "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
       "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
     },
+    "binary": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz",
+      "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=",
+      "requires": {
+        "buffers": "~0.1.1",
+        "chainsaw": "~0.1.0"
+      }
+    },
     "binary-extensions": {
       "version": "1.13.1",
       "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
       "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw=="
+    },
+    "bl": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz",
+      "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==",
+      "requires": {
+        "buffer": "^5.5.0",
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      },
+      "dependencies": {
+        "buffer": {
+          "version": "5.7.1",
+          "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz",
+          "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==",
+          "requires": {
+            "base64-js": "^1.3.1",
+            "ieee754": "^1.1.13"
+          }
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
     },
     "block-stream": {
       "version": "0.0.9",
@@ -4373,10 +4577,20 @@
       "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz",
       "integrity": "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
     },
+    "buffer-indexof-polyfill": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz",
+      "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A=="
+    },
     "buffer-xor": {
       "version": "1.0.3",
       "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
       "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
+    },
+    "buffers": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz",
+      "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s="
     },
     "builtin-status-codes": {
       "version": "3.0.0",
@@ -4550,6 +4764,21 @@
         "commander": "^2.16.0",
         "crc-32": "~1.2.0",
         "printj": "~1.1.2"
+      }
+    },
+    "chainsaw": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz",
+      "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=",
+      "requires": {
+        "traverse": ">=0.3.0 <0.4"
+      },
+      "dependencies": {
+        "traverse": {
+          "version": "0.3.9",
+          "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz",
+          "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk="
+        }
       }
     },
     "chalk": {
@@ -4875,6 +5104,34 @@
         "arity-n": "^1.0.4"
       }
     },
+    "compress-commons": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.0.tgz",
+      "integrity": "sha512-ofaaLqfraD1YRTkrRKPCrGJ1pFeDG/MVCkVVV2FNGeWquSlqw5wOrwOfPQ1xF2u+blpeWASie5EubHz+vsNIgA==",
+      "requires": {
+        "buffer-crc32": "^0.2.13",
+        "crc32-stream": "^4.0.1",
+        "normalize-path": "^3.0.0",
+        "readable-stream": "^3.6.0"
+      },
+      "dependencies": {
+        "normalize-path": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+          "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
     "compressible": {
       "version": "2.0.17",
       "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
@@ -5088,6 +5345,27 @@
       "requires": {
         "exit-on-epipe": "~1.0.1",
         "printj": "~1.1.0"
+      }
+    },
+    "crc32-stream": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz",
+      "integrity": "sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==",
+      "requires": {
+        "crc-32": "^1.2.0",
+        "readable-stream": "^3.4.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
       }
     },
     "create-ecdh": {
@@ -7166,6 +7444,14 @@
       "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
       "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E="
     },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "requires": {
+        "readable-stream": "^2.0.2"
+      }
+    },
     "duplexify": {
       "version": "3.7.1",
       "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz",
@@ -7966,6 +8252,63 @@
         "safe-buffer": "^5.1.1"
       }
     },
+    "exceljs": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/exceljs/-/exceljs-4.2.1.tgz",
+      "integrity": "sha512-EogoTdXH1X1PxqD9sV8caYd1RIfXN3PVlCV+mA/87CgdO2h4X5xAEbr7CaiP8tffz7L4aBFwsdMbjfMXi29NjA==",
+      "requires": {
+        "archiver": "^5.0.0",
+        "dayjs": "^1.8.34",
+        "fast-csv": "^4.3.1",
+        "jszip": "^3.5.0",
+        "readable-stream": "^3.6.0",
+        "saxes": "^5.0.1",
+        "tmp": "^0.2.0",
+        "unzipper": "^0.10.11",
+        "uuid": "^8.3.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "rimraf": {
+          "version": "3.0.2",
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+          "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+          "requires": {
+            "glob": "^7.1.3"
+          }
+        },
+        "saxes": {
+          "version": "5.0.1",
+          "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+          "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
+          "requires": {
+            "xmlchars": "^2.2.0"
+          }
+        },
+        "tmp": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+          "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+          "requires": {
+            "rimraf": "^3.0.0"
+          }
+        },
+        "uuid": {
+          "version": "8.3.2",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+          "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+        }
+      }
+    },
     "exec-sh": {
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz",
@@ -8301,6 +8644,15 @@
         "time-stamp": "^1.0.0"
       }
     },
+    "fast-csv": {
+      "version": "4.3.6",
+      "resolved": "https://registry.npmjs.org/fast-csv/-/fast-csv-4.3.6.tgz",
+      "integrity": "sha512-2RNSpuwwsJGP0frGsOmTb9oUF+VkFSM4SyLTDgwf2ciHWTarN0lQTC+F2f/t5J9QjW+c65VFIAAu85GsvMIusw==",
+      "requires": {
+        "@fast-csv/format": "4.3.5",
+        "@fast-csv/parse": "4.3.6"
+      }
+    },
     "fast-deep-equal": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
@@ -8435,9 +8787,9 @@
       }
     },
     "fecha": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz",
-      "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg=="
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz",
+      "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q=="
     },
     "figgy-pudding": {
       "version": "3.5.1",
@@ -8700,6 +9052,11 @@
         "inherits": "^2.0.1",
         "readable-stream": "^2.0.0"
       }
+    },
+    "fs-constants": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
+      "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
     },
     "fs-extra": {
       "version": "7.0.1",
@@ -9940,6 +10297,11 @@
       "version": "0.6.3",
       "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.6.3.tgz",
       "integrity": "sha512-47xSUiQioGaB96nqtp5/q55m0aBQSQdyIloMOc/x+QVTDZLNmXE892IIDrJ0hM1A5vcNUDD5tDffkSP5lCaIIA=="
+    },
+    "immediate": {
+      "version": "3.0.6",
+      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
+      "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
     },
     "immer": {
       "version": "1.10.0",
@@ -11421,6 +11783,11 @@
       "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz",
       "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="
     },
+    "js-table2excel": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/js-table2excel/-/js-table2excel-1.0.3.tgz",
+      "integrity": "sha512-ivzOdgYqOD3zqzJZfW0Nm35P9BWffxD0Unwr+2QBeEawV7hhRY9RHBVNcvO6A9PhGkMyqPVL/u4/NeufaTTTXw=="
+    },
     "js-tokens": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -11587,6 +11954,17 @@
         "object.assign": "^4.1.0"
       }
     },
+    "jszip": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz",
+      "integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==",
+      "requires": {
+        "lie": "~3.3.0",
+        "pako": "~1.0.2",
+        "readable-stream": "~2.3.6",
+        "set-immediate-shim": "~1.0.1"
+      }
+    },
     "killable": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
@@ -11634,6 +12012,14 @@
       "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
       "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4="
     },
+    "lazystream": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz",
+      "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=",
+      "requires": {
+        "readable-stream": "^2.0.5"
+      }
+    },
     "lcid": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
@@ -11660,6 +12046,19 @@
         "prelude-ls": "~1.1.2",
         "type-check": "~0.3.2"
       }
+    },
+    "lie": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
+      "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
+      "requires": {
+        "immediate": "~3.0.5"
+      }
+    },
+    "listenercount": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz",
+      "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc="
     },
     "load-json-file": {
       "version": "1.1.0",
@@ -11773,6 +12172,31 @@
       "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
       "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
     },
+    "lodash.defaults": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+      "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+    },
+    "lodash.difference": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
+      "integrity": "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw="
+    },
+    "lodash.escaperegexp": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
+      "integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c="
+    },
+    "lodash.flatten": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+      "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
+    },
+    "lodash.groupby": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz",
+      "integrity": "sha1-Cwih3PaDl8OXhVwyOXg4Mt90A9E="
+    },
     "lodash.isarguments": {
       "version": "3.1.0",
       "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
@@ -11782,6 +12206,36 @@
       "version": "3.0.4",
       "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
       "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U="
+    },
+    "lodash.isboolean": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
+      "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
+    },
+    "lodash.isequal": {
+      "version": "4.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
+      "integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
+    },
+    "lodash.isfunction": {
+      "version": "3.0.9",
+      "resolved": "https://registry.npmjs.org/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz",
+      "integrity": "sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw=="
+    },
+    "lodash.isnil": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isnil/-/lodash.isnil-4.0.0.tgz",
+      "integrity": "sha1-SeKM1VkBNFjIFMVHnTxmOiG/qmw="
+    },
+    "lodash.isplainobject": {
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
+      "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+    },
+    "lodash.isundefined": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/lodash.isundefined/-/lodash.isundefined-3.0.1.tgz",
+      "integrity": "sha1-I+89lTVWUgOmbO/VuDD4SJEa+0g="
     },
     "lodash.keys": {
       "version": "3.1.2",
@@ -11829,6 +12283,11 @@
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
       "integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw="
+    },
+    "lodash.union": {
+      "version": "4.6.0",
+      "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
+      "integrity": "sha1-SLtQiECfFvGCFmZkHETdGqrjzYg="
     },
     "lodash.uniq": {
       "version": "4.5.0",
@@ -17057,6 +17516,14 @@
         }
       }
     },
+    "readdir-glob": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.1.tgz",
+      "integrity": "sha512-91/k1EzZwDx6HbERR+zucygRFfiPl2zkIYZtv3Jjr6Mn7SkKcVct8aVO+sSRiGMc6fLf72du3d92/uY63YPdEA==",
+      "requires": {
+        "minimatch": "^3.0.4"
+      }
+    },
     "readdirp": {
       "version": "2.2.1",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
@@ -17991,6 +18458,11 @@
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
       "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+    },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
     },
     "set-value": {
       "version": "2.0.1",
@@ -19022,6 +19494,30 @@
         "inherits": "2"
       }
     },
+    "tar-stream": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
+      "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==",
+      "requires": {
+        "bl": "^4.0.3",
+        "end-of-stream": "^1.4.1",
+        "fs-constants": "^1.0.0",
+        "inherits": "^2.0.3",
+        "readable-stream": "^3.1.1"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
     "temp": {
       "version": "0.8.3",
       "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz",
@@ -19778,6 +20274,30 @@
           "version": "1.0.0",
           "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
           "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+        }
+      }
+    },
+    "unzipper": {
+      "version": "0.10.11",
+      "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz",
+      "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==",
+      "requires": {
+        "big-integer": "^1.6.17",
+        "binary": "~0.3.0",
+        "bluebird": "~3.4.1",
+        "buffer-indexof-polyfill": "~1.0.0",
+        "duplexer2": "~0.1.4",
+        "fstream": "^1.0.12",
+        "graceful-fs": "^4.2.2",
+        "listenercount": "~1.0.1",
+        "readable-stream": "~2.3.6",
+        "setimmediate": "~1.0.4"
+      },
+      "dependencies": {
+        "bluebird": {
+          "version": "3.4.7",
+          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz",
+          "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM="
         }
       }
     },
@@ -20736,6 +21256,28 @@
         }
       }
     },
+    "zip-stream": {
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz",
+      "integrity": "sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==",
+      "requires": {
+        "archiver-utils": "^2.1.0",
+        "compress-commons": "^4.1.0",
+        "readable-stream": "^3.6.0"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        }
+      }
+    },
     "zrender": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/zrender/-/zrender-4.1.2.tgz",
diff --git a/package.json b/package.json
index 5ca8645..aaef24f 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,8 @@
   "private": true,
   "dependencies": {
     "@antv/data-set": "^0.11.4",
-    "@antv/g2": "^4.1.0-beta.18",
+    "@antv/g2": "^4.1.14",
+    "@antv/util": "^2.0.13",
     "@babel/core": "7.5.5",
     "@svgr/webpack": "4.3.2",
     "@typescript-eslint/eslint-plugin": "1.13.0",
@@ -39,6 +40,7 @@
     "eslint-plugin-jsx-a11y": "6.2.3",
     "eslint-plugin-react": "7.14.3",
     "eslint-plugin-react-hooks": "^1.6.1",
+    "exceljs": "^4.2.1",
     "file-loader": "3.0.1",
     "fs-extra": "7.0.1",
     "html-webpack-plugin": "4.0.0-beta.5",
@@ -52,6 +54,7 @@
     "jest-environment-jsdom-fourteen": "0.1.0",
     "jest-resolve": "24.8.0",
     "jest-watch-typeahead": "0.3.1",
+    "js-table2excel": "^1.0.3",
     "jsbarcode": "^3.11.3",
     "jssha": "^3.2.0",
     "md5": "^2.2.1",
@@ -189,7 +192,7 @@
       ]
     ]
   },
-  "homepage": "./build",
+  "homepage": ".",
   "devDependencies": {
     "typescript": "^4.0.2"
   }
diff --git a/public/admin.html b/public/admin.html
index 1c43083..41254bc 100644
--- a/public/admin.html
+++ b/public/admin.html
@@ -24,10 +24,8 @@
               var appPort = 'admin/index.html'
               if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) {
                 appPort = 'mob/index.html'
-              } else {
-                if (config.defaultApp) {
-                  appPort = 'pc/'
-                }
+              } else if (config.defaultApp) {
+                appPort = 'pc/index.html'
               }
               window.location.replace(url + appPort)
             }
diff --git a/public/options.json b/public/options.json
index 9e7abbb..e213888 100644
--- a/public/options.json
+++ b/public/options.json
@@ -1,13 +1,15 @@
 {
   "appId": "20201221213901540C6BC419CE41E47FABA62",
   "appkey": "2020122121373692319E639E61B0E46A6BC2C",
-  "mainSystemApi": "http://cloud.positecgroup.com:8080/webapi/dostar",
+  "mainSystemApi": "https://cloud.positecgroup.com/webapi/dostars",
   "systemType": "",
-  "externalDatabase": "false",
+  "externalDatabase": "mkdata_kress_test",
   "lineColor": "",
   "filter": "false",
   "defaultApp": "",
   "defaultLang": "zh-CN",
-  "host": "http://qingqiumarket.cn",
-  "service": "mkwms/"
+  "WXAppID": "",
+  "debugger": false,
+  "host": "http://bms-test.kresstools.cn",
+  "service": "oc/"
 }
\ No newline at end of file
diff --git a/src/api/cacheutils.js b/src/api/cacheutils.js
index 2aa5642..aa742fc 100644
--- a/src/api/cacheutils.js
+++ b/src/api/cacheutils.js
@@ -5,7 +5,7 @@
   /**
    * @description 鎵撳紑websql
    */
-  static openWebSql () {
+  static openWebSql (sysType) {
     let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
     try {
       window.GLOB.WebSql = openDatabase(`mkdb${service}`, '1', 'mk-pc-database', 50 * 1024 * 1024)
@@ -22,6 +22,15 @@
           // eslint-disable-next-line
           throw 'CREATE TABLE ERROR'
         })
+
+        if (sysType === 'local' && window.GLOB.systemType === '') {
+          tx.executeSql('CREATE TABLE IF NOT EXISTS FUNCS (func_code varchar(50), key_sql text, CDefine1 varchar(50), CDefine2 varchar(50), CDefine3 varchar(50))', [], () => {
+
+          }, () => {
+            // eslint-disable-next-line
+            throw 'CREATE TABLE ERROR'
+          })
+        }
       })
       // window.GLOB.WebSql.transaction(tx => {
       //   tx.executeSql('DROP TABLE VERSIONS')
@@ -42,16 +51,13 @@
     }
     return new Promise((resolve, reject) => {
       window.GLOB.WebSql.transaction(tx => {
-        tx.executeSql('SELECT * FROM VERSIONS', [], (tx, results) => {
+        tx.executeSql("SELECT * FROM VERSIONS where CDefine1='LongParam'", [], (tx, results) => {
           if (results.rows.length === 0) {
-            tx.executeSql('DELETE FROM CONFIGS')
-            resolve({version: '', createDate: ''})
-          } else if (results.rows.length === 1) {
-            resolve(results.rows[0])
-          } else if (results.rows.length > 1) {
             tx.executeSql('DELETE FROM VERSIONS')
             tx.executeSql('DELETE FROM CONFIGS')
             resolve({version: '', createDate: ''})
+          } else {
+            resolve(results.rows[0])
           }
         }, (tx, results) => {
           window.GLOB.WebSql = null
@@ -107,7 +113,7 @@
   static updateWebSqlTime (curTime) {
     if (!window.GLOB.WebSql || !curTime) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql(`UPDATE VERSIONS SET createDate='${curTime}'`, [], () => {}, () => {
+      tx.executeSql(`UPDATE VERSIONS SET createDate='${curTime}' where CDefine1='LongParam'`, [], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -119,7 +125,7 @@
   static updateWebSqlversion (version, curTime) {
     if (!window.GLOB.WebSql || !curTime || !version) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql(`UPDATE VERSIONS SET version='${version}', createDate='${curTime}'`, [], () => {}, () => {
+      tx.executeSql(`UPDATE VERSIONS SET version='${version}', createDate='${curTime}' where CDefine1='LongParam'`, [], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -131,7 +137,7 @@
   static createWebSqlversion (version, curTime) {
     if (!window.GLOB.WebSql || !curTime || !version) return
     window.GLOB.WebSql.transaction(tx => {
-      tx.executeSql('INSERT INTO VERSIONS (version, createDate) VALUES (?, ?)', [version, curTime], () => {}, () => {
+      tx.executeSql('INSERT INTO VERSIONS (version, createDate, CDefine1) VALUES (?, ?, ?)', [version, curTime, 'LongParam'], () => {}, () => {
         window.GLOB.WebSql = null
       })
     })
@@ -182,7 +188,7 @@
   /**
    * @description 鎵撳紑IndexedDB
    */
-  static openIndexDB () {
+  static openIndexDB (sysType) {
     let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
     try {
       let request = window.indexedDB.open(`mkdb${service}`, 1)
@@ -202,6 +208,9 @@
           objectStore.createIndex('menuid', 'menuid', { unique: false })
           objectStore.createIndex('userid', 'userid', { unique: false })
         }
+        if (window.GLOB.systemType === '' && sysType === 'local' && !window.GLOB.IndexDB.objectStoreNames.contains('funcs')) {
+          window.GLOB.IndexDB.createObjectStore('funcs', { keyPath: 'id' })
+        }
       }
     } catch (e) {
       console.warn('IndexedDB 鍒濆鍖栧け璐ワ紒')
diff --git a/src/api/index.js b/src/api/index.js
index ad91d61..c5f65d9 100644
--- a/src/api/index.js
+++ b/src/api/index.js
@@ -17,9 +17,9 @@
   1578479100252lfbp29v1kafk4s4q4ig,1577971621421tg4v0i1ur8873k7e0ob,1577929944419lgc5h3hepum765e2k7u,1588493493409k9guqp067d31lu7blsv`
 
 if (window.openDatabase) {
-  CacheUtils.openWebSql()
+  CacheUtils.openWebSql(options.sysType)
 } else if (window.indexedDB) {
-  CacheUtils.openIndexDB()
+  CacheUtils.openIndexDB(options.sysType)
 }
 
 axios.defaults.crossDomain = true
@@ -255,15 +255,31 @@
       login_id_address: ipAddress
     }
 
+    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+
+    let sys_datetime = sessionStorage.getItem('sys_datetime')
+    let app_datetime = sessionStorage.getItem('app_datetime')
+    if (sys_datetime && app_datetime) {
+      let seconds = Math.floor((new Date().getTime() - app_datetime) / 1000)
+      param.timestamp = moment(sys_datetime, 'YYYY-MM-DD HH:mm:ss').add(seconds, 'seconds').format('YYYY-MM-DD HH:mm:ss')
+    }
+    
     // Type: 'S' 鏃�
     let shaObj = new jsSHA('SHA-1', 'TEXT')
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
     shaObj.update(password)
     param.Password = shaObj.getHash('HEX').toUpperCase()
     param.Password = md5(username + param.Password + param.timestamp)
 
+    // Type: 'mk_' 鏃�
+    // param.Type = '鍏挜'
+    // let shaObj = new jsSHA('SHA-1', 'TEXT')
+    // shaObj.update(password)
+    // param.Password = shaObj.getHash('HEX').toUpperCase()
+    // param.Password = md5('绉侀挜' + username + param.Password + param.timestamp)
+    
     // Type: 'X' 鏃�
     // param.Password = Utils.formatOptions(password)
+
     param.appkey = window.GLOB.appkey || ''
     let url = '/webapi/dologon'
 
@@ -297,14 +313,26 @@
       return Promise.reject()
     }
 
+    let curTime = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+    let sys_datetime = sessionStorage.getItem('sys_datetime')
+    let app_datetime = sessionStorage.getItem('app_datetime')
+    if (sys_datetime && app_datetime) {
+      let seconds = Math.floor((new Date().getTime() - app_datetime) / 1000)
+      curTime = moment(sys_datetime, 'YYYY-MM-DD HH:mm:ss').add(seconds, 'seconds').format('YYYY-MM-DD HH:mm:ss') + '.000'
+    }
+
     if (window.GLOB.WebSql) {
       return new Promise((resolve, reject) => {
         CacheUtils.getWebSqlVersion().then(msg => {
           appVersion.oldVersion = msg.version || ''
-          let curTime = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+          let modifydate = msg.createDate || curTime
+          if (modifydate.indexOf('Invalid date') > -1) {
+            modifydate = curTime
+          }
+
           let param = {
             func: 's_get_app_version',
-            modifydate: msg.createDate || curTime,
+            modifydate
           }
   
           this.getSystemConfig(param).then(res => {
@@ -348,10 +376,13 @@
       return new Promise((resolve, reject) => {
         CacheUtils.getIndexDBVersion().then(msg => {
           appVersion.oldVersion = msg.version || ''
-          let curTime = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
+          let modifydate = msg.createDate || curTime
+          if (modifydate.indexOf('Invalid date') > -1) {
+            modifydate = curTime
+          }
           let param = {
             func: 's_get_app_version',
-            modifydate: msg.createDate || curTime,
+            modifydate
           }
 
           this.getSystemConfig(param).then(res => {
@@ -437,6 +468,30 @@
 
     return axios({
       url,
+      method: 'post',
+      data: param
+    })
+  }
+
+  /**
+   * @description 鑾峰彇鎴栦慨鏀圭郴缁熼厤缃紝澧炲姞appkey
+   */
+  getSystemFuncs (time) {
+    let param = {
+      func: 's_get_func_base_sso',
+      update_date: time,
+      userid: sessionStorage.getItem('UserID') || '',
+      lang: sessionStorage.getItem('lang') || '',
+      SessionUid: localStorage.getItem('SessionUid') || '',
+      LoginUID: sessionStorage.getItem('LoginUID') || '',
+      appkey: window.GLOB.appkey
+    }
+
+    let url = window.GLOB.mainSystemApi
+    param = this.encryptParam(param)
+
+    return axios({
+      url: `${url}/${param.func}`,
       method: 'post',
       data: param
     })
@@ -785,22 +840,17 @@
 
     param = this.encryptParam(param)
 
+    let url = '/webapi/SaveBase64Image'
     if (param.rduri) {
-      let url = param.rduri.replace(/webapi(.*)$/, 'webapi/SaveBase64Image')
+      url = param.rduri.replace(/webapi(.*)$/, 'webapi/SaveBase64Image')
       delete param.rduri
-
-      return axios({
-        url,
-        method: 'post',
-        data: param
-      })
-    } else {
-      return axios({
-        url: '/webapi/SaveBase64Image',
-        method: 'post',
-        data: param
-      })
     }
+
+    return axios({
+      url,
+      method: 'post',
+      data: param
+    })
   }
 
   /**
diff --git a/src/assets/css/main.scss b/src/assets/css/main.scss
index 3d90a6e..9c1486d 100644
--- a/src/assets/css/main.scss
+++ b/src/assets/css/main.scss
@@ -135,15 +135,15 @@
   background: rgba(0, 0, 0, 0);
 }
 // 閲嶇疆妯℃�佹婊氬姩鏉�
-.ant-modal-wrap::-webkit-scrollbar {
+.ant-modal-wrap::-webkit-scrollbar, .ant-drawer-wrapper-body::-webkit-scrollbar {
   width: 7px;
 }
-.ant-modal-wrap::-webkit-scrollbar-thumb {
+.ant-modal-wrap::-webkit-scrollbar-thumb, .ant-drawer-wrapper-body::-webkit-scrollbar-thumb {
   border-radius: 5px;
-  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-  background: rgba(0, 0, 0, 0.13);
+  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.1);
+  background: rgba(0, 0, 0, 0.1);
 }
-.ant-modal-wrap::-webkit-scrollbar-track {
+.ant-modal-wrap::-webkit-scrollbar-track, .ant-drawer-wrapper-body::-webkit-scrollbar-track {
   box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
   border-radius: 3px;
   border: 1px solid rgba(0, 0, 0, 0.07);
@@ -386,4 +386,21 @@
       padding: 5px 20px;
     }
   }
+}
+
+.ant-input[disabled] {
+  background-color: #fafafa!important;
+}
+.ant-btn[disabled] {
+  background-color: transparent!important;
+  border-color: rgba(0, 0, 0, 0.35)!important;
+  color: rgba(0, 0, 0, 0.35)!important;
+}
+.ant-btn.ant-btn-link {
+  border-width: 0;
+}
+.button-list {
+  .ant-btn.ant-btn-link {
+    border-width: 1px;
+  }
 }
\ No newline at end of file
diff --git a/src/assets/css/viewstyle.scss b/src/assets/css/viewstyle.scss
index d1ca60c..e1f8bcc 100644
--- a/src/assets/css/viewstyle.scss
+++ b/src/assets/css/viewstyle.scss
@@ -33,11 +33,8 @@
       button.vercode {
         color: $color6;
       }
-      .ant-tabs {
-        .ant-tabs-tab.ant-tabs-tab-active {
-          color: $color6;
-        }
-        .ant-tabs-tab:hover {
+      .login-way-wrap {
+        .login-way.active, .login-way:hover {
           color: $color6;
         }
       }
@@ -208,7 +205,7 @@
   .top-search {
     >.ant-row {
       .ant-col.search-button {
-        .ant-btn:not(.ant-btn-primary):active, .ant-btn:not(.ant-btn-primary).active, .ant-btn:not(.ant-btn-primary):hover, .ant-btn:not(.ant-btn-primary):focus {
+        .ant-btn:not(.ant-btn-primary):not(.ant-btn-link):active, .ant-btn:not(.ant-btn-primary):not(.ant-btn-link).active, .ant-btn:not(.ant-btn-primary):not(.ant-btn-link):hover, .ant-btn:not(.ant-btn-primary):not(.ant-btn-link):focus {
           color: $color7;
           border-color: $color7;
         }
@@ -216,6 +213,14 @@
           background-color: $color6;
           border-color: $color6;
         }
+        .ant-btn-link {
+          color: $color6;
+        }
+      }
+    }
+    .advanced-list {
+      .advance-value {
+        color: $color6;
       }
     }
   }
diff --git a/src/assets/img/rolemanage.jpg b/src/assets/img/rolemanage.jpg
index 1b6c346..8fe80c3 100644
--- a/src/assets/img/rolemanage.jpg
+++ b/src/assets/img/rolemanage.jpg
Binary files differ
diff --git a/src/assets/mobimg/dashboard.png b/src/assets/mobimg/dashboard.png
new file mode 100644
index 0000000..9769128
--- /dev/null
+++ b/src/assets/mobimg/dashboard.png
Binary files differ
diff --git a/src/assets/mobimg/login.png b/src/assets/mobimg/login.png
new file mode 100644
index 0000000..13c10ee
--- /dev/null
+++ b/src/assets/mobimg/login.png
Binary files differ
diff --git a/src/assets/mobimg/menubar.png b/src/assets/mobimg/menubar.png
new file mode 100644
index 0000000..2766d21
--- /dev/null
+++ b/src/assets/mobimg/menubar.png
Binary files differ
diff --git a/src/assets/mobimg/navtop-mob.png b/src/assets/mobimg/navtop-mob.png
new file mode 100644
index 0000000..829cd6b
--- /dev/null
+++ b/src/assets/mobimg/navtop-mob.png
Binary files differ
diff --git a/src/assets/mobimg/nest.png b/src/assets/mobimg/nest.png
new file mode 100644
index 0000000..16c2158
--- /dev/null
+++ b/src/assets/mobimg/nest.png
Binary files differ
diff --git a/src/assets/mobimg/ratioboard.png b/src/assets/mobimg/ratioboard.png
new file mode 100644
index 0000000..53498da
--- /dev/null
+++ b/src/assets/mobimg/ratioboard.png
Binary files differ
diff --git a/src/assets/mobimg/scatter.png b/src/assets/mobimg/scatter.png
new file mode 100644
index 0000000..dfeb28a
--- /dev/null
+++ b/src/assets/mobimg/scatter.png
Binary files differ
diff --git a/src/assets/mobimg/tree.png b/src/assets/mobimg/tree.png
new file mode 100644
index 0000000..b26f993
--- /dev/null
+++ b/src/assets/mobimg/tree.png
Binary files differ
diff --git a/src/components/editor/index.jsx b/src/components/editor/index.jsx
index a94d12e..3cfc203 100644
--- a/src/components/editor/index.jsx
+++ b/src/components/editor/index.jsx
@@ -23,8 +23,8 @@
 
 class NormalEditor extends Component {
   static propTpyes = {
-    Item: PropTypes.object,     // 琛ㄥ崟鍏冪礌
-    onChange: PropTypes.func,   // 琛ㄥ崟鏇存柊
+    config: PropTypes.object,
+    onChange: PropTypes.func
   }
 
   state = {
@@ -33,16 +33,17 @@
   }
 
   UNSAFE_componentWillMount () {
+    const { config, defaultValue } = this.props
     let initVal = null
     let encryption = 'false'
 
-    if (this.props['data-__meta']) {
-      initVal = this.props['data-__meta'].initialValue || null
-    } else if (this.props.defaultValue) {
-      initVal = this.props.defaultValue || null
+    if (config && config.initval) {
+      initVal = config.initval
+    } else if (defaultValue) {
+      initVal = defaultValue
     }
 
-    if (this.props.Item && this.props.Item.encryption === 'true') {
+    if (config && config.encryption === 'true') {
       encryption = 'true'
       if (initVal) {
         try {
@@ -92,6 +93,7 @@
     form.append('fileExt', params.file.fileType)
     form.append('shardingCnt', _param.chunks)
     form.append('shardingNo', _param.chunk)
+    form.append('LoginUID', sessionStorage.getItem('LoginUID') || '')
 
     Api.getLargeFileUpload(form).then(res => {
       if (res.status) {
diff --git a/src/components/header/index.jsx b/src/components/header/index.jsx
index aa7b4d2..0fab405 100644
--- a/src/components/header/index.jsx
+++ b/src/components/header/index.jsx
@@ -143,7 +143,7 @@
         edition_type: 'A',
         pro_sys: window.GLOB.systemType === 'production' ? 'Y' : ''
       }).then(result => {
-        let _permAction = {} // 鎸夐挳鏉冮檺
+        let _permAction = {loaded: true} // 鎸夐挳鏉冮檺
 
         if (result && result.status) {
           if (result.UserRoles_Menu) {
@@ -214,7 +214,7 @@
 
         this.props.modifyMenuTree(menulist)
         this.props.modifyMainMenu(mainMenu)
-        this.props.initMenuPermission(thdMenuList)
+        this.props.initMenuPermission([...thdMenuList, {MenuID: 'home_page_id', EasyCode: '', MenuName: 'home', type: 'CustomPage'}])
 
         resolve(_menu)
       })
@@ -371,7 +371,7 @@
     // 淇敼缂栬緫鐘舵��
     let UserID = sessionStorage.getItem('CloudUserID')
     let LoginUID = sessionStorage.getItem('CloudLoginUID')
-
+    
     if (!UserID || !LoginUID) {
       this.setState({
         loginVisible: true
@@ -408,12 +408,18 @@
           sessionStorage.setItem('dataM', res.dataM ? 'true' : '')
           sessionStorage.setItem('isEditState', 'true')
 
+          this.setSystemFuncs()
+
           this.props.modifyMenuTree([])
           this.props.modifyMainMenu(null)
           this.props.modifyTabview([])
 
           this.props.history.replace('/design')
         } else {
+          if (res.message.indexOf('瀵嗙爜閿欒') > -1) {
+            const input = document.getElementById('password')
+            input && input.select()
+          }
           this.setState({
             loginLoading: false
           })
@@ -427,6 +433,107 @@
     })
   }
 
+  setSystemFuncs = () => {
+    if (!window.GLOB.WebSql && !window.GLOB.IndexDB) {
+      return
+    }
+    this.getfuncTime().then(res => {
+      Api.getSystemFuncs(res.createDate).then(result => {
+        if (!result.status) {
+          notification.error({
+            top: 92,
+            message: result.message,
+            duration: 10
+          })
+          return
+        } else if (result.func_detail && result.func_detail.length > 0) {
+          this.writeFuncs(result.func_detail)
+        }
+      })
+    })
+  }
+
+  writeFuncs = (funcs) => {
+    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+
+    let sys_datetime = sessionStorage.getItem('sys_datetime')
+    let app_datetime = sessionStorage.getItem('app_datetime')
+    if (sys_datetime && app_datetime) {
+      let seconds = Math.floor((new Date().getTime() - app_datetime) / 1000)
+      timestamp = moment(sys_datetime, 'YYYY-MM-DD HH:mm:ss').add(seconds, 'seconds').format('YYYY-MM-DD HH:mm:ss')
+    }
+
+    if (window.GLOB.WebSql) {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql('DELETE FROM FUNCS')
+
+        funcs.forEach(item => {
+          if (!item.key_sql) return
+          tx.executeSql('INSERT INTO FUNCS (func_code, key_sql) VALUES (?, ?)', [item.func_code, item.key_sql])
+        })
+        tx.executeSql(`UPDATE VERSIONS SET createDate='${timestamp}' where CDefine1='funcs'`)
+      })
+    } else {
+      let objectStore = window.GLOB.IndexDB.transaction(['funcs'], 'readwrite').objectStore('funcs')
+
+      objectStore.clear()
+
+      funcs.forEach(item => {
+        if (!item.key_sql) return
+        item.id = item.func_code
+        objectStore.add(item)
+      })
+
+      let funcStore = window.GLOB.IndexDB.transaction(['version'], 'readwrite').objectStore('version')
+      funcStore.put({id: 'funcs', version: '1.0', createDate: timestamp})
+    }
+  }
+
+  getfuncTime = () => {
+    return new Promise((resolve, reject) => {
+      if (window.GLOB.WebSql) {
+        window.GLOB.WebSql.transaction(tx => {
+          tx.executeSql("SELECT * FROM VERSIONS where CDefine1='funcs'", [], (tx, results) => {
+            let rows = results.rows
+            if (rows.length === 0) {
+              tx.executeSql('DELETE FROM FUNCS')
+              tx.executeSql('INSERT INTO VERSIONS (version, createDate, CDefine1) VALUES (?, ?, ?)', ['1.0', '1970-01-01 14:59:09.000', 'funcs'])
+              resolve({createDate: '1970-01-01 14:59:09.000'})
+            } else {
+              resolve(rows[0])
+            }
+          }, (tx, results) => {
+            reject()
+            console.warn(results)
+          })
+        })
+      } else {
+        let objectStore = window.GLOB.IndexDB.transaction(['version'], 'readwrite').objectStore('version')
+        let request = objectStore.get('funcs')
+
+        request.onerror = (event) => {
+          console.warn(event)
+          reject()
+        }
+
+        request.onsuccess = () => {
+          if (request.result) {
+            resolve(request.result)
+          } else {
+            let add = objectStore.add({id: 'funcs', version: '1.0', createDate: '1970-01-01 14:59:09.000'})
+    
+            add.onerror = () => {
+              reject()
+            }
+            add.onsuccess = () => {
+              resolve({id: 'funcs', version: '1.0', createDate: '1970-01-01 14:59:09.000'})
+            }
+          }
+        }
+      }
+    })
+  }
+
   changeSystem = (system) => {
     let url = system.LinkUrl1
 
diff --git a/src/components/mkIcon/index.jsx b/src/components/mkIcon/index.jsx
new file mode 100644
index 0000000..583e170
--- /dev/null
+++ b/src/components/mkIcon/index.jsx
@@ -0,0 +1,70 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, Icon, Row, Col, Button } from 'antd'
+
+import { minkeIconSystem } from '@/utils/option.js'
+import './index.scss'
+
+class MkIcon extends Component {
+  static propTpyes = {
+    onChange: PropTypes.func
+  }
+
+  state = {
+    selectIcon: '',
+    allowClear: false,
+    icons: [...minkeIconSystem.direction, ...minkeIconSystem.edit, ...minkeIconSystem.normal, ...minkeIconSystem.trademark, ...minkeIconSystem.data, ...minkeIconSystem.hint],
+    visible: false
+  }
+
+  UNSAFE_componentWillMount () {
+    let val = ''
+    if (this.props['data-__meta']) {
+      val = this.props['data-__meta'].initialValue || ''
+    }
+
+    this.setState({selectIcon: val, allowClear: this.props.allowClear === true})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  checkIcon = (val) => {
+    this.setState({selectIcon: val, visible: false})
+    this.props.onChange(val)
+  }
+
+  render() {
+    const { selectIcon, visible, icons, allowClear } = this.state
+
+    return (
+      <div className="mk-icon-box">
+        {selectIcon ? <Icon type={selectIcon}/> : <Icon style={{opacity: 0}} type="plus"/>}
+        <Icon className="trigger" onClick={() => this.setState({visible: true})} type="swap"/>
+        {allowClear ? <Icon className="close" onClick={() => this.checkIcon('')} type="close"/> : null}
+        <Modal
+          wrapClassName="popview-modal mk-icon-wrap"
+          title={'鍥炬爣閫夋嫨'}
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          onCancel={() => { this.setState({ visible: false }) }}
+          footer={[
+            <Button key="close" onClick={() => { this.setState({ visible: false }) }}>鍏抽棴</Button>
+          ]}
+          destroyOnClose
+        >
+          <Row>
+            {icons.map(icon => <Col className={icon === selectIcon ? 'active' : ''} key={icon} span={4}>
+              <Icon onClick={() => this.checkIcon(icon)} type={icon} />
+            </Col>)}
+          </Row>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default MkIcon
\ No newline at end of file
diff --git a/src/components/mkIcon/index.scss b/src/components/mkIcon/index.scss
new file mode 100644
index 0000000..4ba05ef
--- /dev/null
+++ b/src/components/mkIcon/index.scss
@@ -0,0 +1,53 @@
+.mk-icon-box {
+  display: block;
+  height: 32px;
+  border: 1px solid #d9d9d9;
+  border-radius: 4px;
+  line-height: 32px;
+  padding: 0px 0px 0px 10px;
+
+  .anticon.trigger {
+    float: right;
+    line-height: 32px;
+    padding: 0 10px;
+    border-left: 1px solid #d9d9d9;
+  }
+  .close.anticon {
+    float: right;
+    margin-top: 6px;
+    margin-right: 5px;
+    background: #efefef;
+    border-radius: 50%;
+    color: #757575;
+    padding: 3px;
+    font-size: 10px;
+    opacity: 0;
+    transition: opacity 0.3s;
+  }
+}
+.mk-icon-box:hover {
+  border-color: #1890ff;
+  .close.anticon {
+    opacity: 1;
+  }
+}
+.mk-icon-box::after {
+  content: ' ';
+  display: block;
+  clear: both;
+}
+.mk-icon-wrap {
+  .ant-col {
+    text-align: center;
+    line-height: 55px;
+    .anticon {
+      font-size: 30px;
+      cursor: pointer;
+    }
+  }
+  .active.ant-col {
+    .anticon {
+      color: #1890ff;
+    }
+  }
+}
diff --git a/src/components/paste/index.jsx b/src/components/paste/index.jsx
new file mode 100644
index 0000000..4760c22
--- /dev/null
+++ b/src/components/paste/index.jsx
@@ -0,0 +1,72 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Icon, Modal, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
+
+class PasteController extends Component {
+  static propTpyes = {
+    options: PropTypes.array,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false
+  }
+
+  handleMenuClick = () => {
+    this.setState({visible: true})
+  }
+
+  pasteSubmit = () => {
+    const { options } = this.props
+    this.pasteFormRef.handleConfirm().then(res => {
+      if (!options.includes(res.copyType)) {
+        notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
+        return
+      }
+      this.props.updateConfig(res, (result) => {
+        if (result.status) {
+          notification.success({
+            top: 92,
+            message: '绮樿创鎴愬姛锛�',
+            duration: 2
+          })
+          this.setState({visible: false})
+        } else {
+          notification.success({
+            top: 92,
+            message: result.message,
+            duration: 2
+          })
+        }
+      })
+    })
+  }
+
+  render() {
+    const { visible } = this.state
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Icon type="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} />
+        <Modal
+          title="绮樿创"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.pasteSubmit}
+          onCancel={() => {this.setState({visible: false})}}
+          destroyOnClose
+        >
+          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default PasteController
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/components/paste/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/components/paste/index.scss
diff --git a/src/components/tabview/index.jsx b/src/components/tabview/index.jsx
index 980b810..a9ebd63 100644
--- a/src/components/tabview/index.jsx
+++ b/src/components/tabview/index.jsx
@@ -137,6 +137,8 @@
       return (<TabManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'RolePermission') {
       return (<RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
+    } else if (view.type === 'appRolePermission') {
+      return (<RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
     } else if (view.type === 'FormTab') {
       return (<FormTab MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
     } else if (view.type === 'iframe') {
diff --git a/src/index.js b/src/index.js
index 5e8a1c2..5c7b909 100644
--- a/src/index.js
+++ b/src/index.js
@@ -69,9 +69,9 @@
 sessionStorage.setItem('role_id', sessionStorage.getItem('localRole_id') || '')
 sessionStorage.setItem('dataM', sessionStorage.getItem('localDataM') || '')
 
-// 鏂扮郴缁熸枃浠剁疆浜巃dmin涓� ../options.json
+// 鏂扮郴缁熸枃浠剁疆浜巃dmin涓� ../options.json , { cache: 'no-cache'}
 
-fetch('./options.json')
+fetch('../options.json')
   .then(response => response.json())
   .catch(() => {
     document.getElementById('root').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh;">绯荤粺閰嶇疆淇℃伅鑾峰彇澶辫触锛岃鑱旂郴绠$悊鍛橈紒</div>'
diff --git a/src/locales/zh-CN/model.js b/src/locales/zh-CN/model.js
index c50cd3a..5a3a4cd 100644
--- a/src/locales/zh-CN/model.js
+++ b/src/locales/zh-CN/model.js
@@ -125,7 +125,7 @@
   'model.form.link': '鑱斿姩鑿滃崟',
   'model.form.linkform': '鍏宠仈琛ㄥ崟',
   'model.form.dateday': '鏃ユ湡锛堝ぉ锛�',
-  'model.form.datetime': '鏃ユ湡锛堢锛�',
+  'model.form.datetime': '鏃ユ湡锛堝垎/绉掞級',
   'model.form.dateweek': '鏃ユ湡锛堝懆锛�',
   'model.form.datemonth': '鏃ユ湡锛堟湀锛�',
   'model.form.daterange': '鏃ユ湡锛堝尯闂达級',
diff --git a/src/menu/bgcontroller/index.jsx b/src/menu/bgcontroller/index.jsx
index 9dbdec5..7018a0c 100644
--- a/src/menu/bgcontroller/index.jsx
+++ b/src/menu/bgcontroller/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Form } from 'antd'
+import { Form, Select } from 'antd'
 
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
@@ -10,6 +10,7 @@
 
 const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
 const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
+const { Option } = Select
 
 class MobController extends Component {
   static propTpyes = {
@@ -21,6 +22,8 @@
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     backgroundColor: '',
     backgroundImage: '',
+    backgroundSize: '',
+    backgroundRepeat: '',
   }
 
   UNSAFE_componentWillMount () {
@@ -35,7 +38,9 @@
 
     this.setState({
       backgroundColor: config.style.backgroundColor,
-      backgroundImage: bgImg
+      backgroundImage: bgImg,
+      backgroundSize: config.style.backgroundSize || '100%',
+      backgroundRepeat: config.style.backgroundRepeat || 'repeat',
     })
   }
 
@@ -72,8 +77,30 @@
     this.props.updateConfig(config)
   }
 
+  backgroundSizeChange = (val) => {
+    this.setState({
+      backgroundSize: val
+    })
+
+    let config = fromJS(this.props.config).toJS()
+    config.style.backgroundSize = val
+
+    this.props.updateConfig(config)
+  }
+
+  backgroundRepeatChange = (val) => {
+    this.setState({
+      backgroundRepeat: val
+    })
+
+    let config = fromJS(this.props.config).toJS()
+    config.style.backgroundRepeat = val
+
+    this.props.updateConfig(config)
+  }
+
   render () {
-    const { backgroundColor, backgroundImage } = this.state
+    const { backgroundColor, backgroundImage, backgroundSize, backgroundRepeat } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -94,6 +121,23 @@
           <Form.Item colon={false} label="鍥剧墖">
             <SourceComponent value={backgroundImage} type="" placement="right" onChange={this.imgChange}/>
           </Form.Item>
+          <Form.Item colon={false} label="姣斾緥">
+            <Select defaultValue={backgroundSize} onChange={this.backgroundSizeChange}>
+              <Option value="100%">100%</Option>
+              <Option value="100% 100%">100% 100%</Option>
+              <Option value="auto 100%">auto 100%</Option>
+              <Option value="contain">contain</Option>
+              <Option value="cover">cover</Option>
+            </Select>
+          </Form.Item>
+          <Form.Item colon={false} label="閲嶅">
+            <Select defaultValue={backgroundRepeat} onChange={this.backgroundRepeatChange}>
+              <Option value="repeat">repeat</Option>
+              <Option value="no-repeat">no-repeat</Option>
+              <Option value="repeat-x">repeat-x</Option>
+              <Option value="repeat-y">repeat-y</Option>
+            </Select>
+          </Form.Item>
         </Form>
       </div>
     )
diff --git a/src/menu/components/card/balcony/index.jsx b/src/menu/components/card/balcony/index.jsx
new file mode 100644
index 0000000..0fc02d5
--- /dev/null
+++ b/src/menu/components/card/balcony/index.jsx
@@ -0,0 +1,237 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+const CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/components/paste'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+
+class BalconyEditComponent extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, width: card.width || 24, linkType: 'static', position: 'relative', datatype: 'static' },
+        style: { marginLeft: '0px', marginRight: '0px', marginTop: '0px', marginBottom: '0px' },
+        columns: [],
+        scripts: [],
+        elements: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+
+        _card.elements = _card.elements.map(elem => {
+          elem.uuid = Utils.getuuid()
+          return elem
+        })
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  updateCard = (elements) => {
+    const { card } = this.state
+
+    let _card = {...card, elements: elements}
+
+    this.setState({
+      card: _card,
+    })
+
+    this.props.updateConfig(_card)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  addElement = () => {
+    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, card.uuid], newcard)
+  }
+
+  addButton = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.eleType = 'button'
+    newcard.label = 'button'
+    newcard.sqlType = ''
+    newcard.Ot = 'requiredSgl'
+    newcard.OpenType = 'prompt'
+    newcard.icon = ''
+    newcard.class = 'primary'
+    newcard.intertype = 'system'
+    newcard.execSuccess = 'grid'
+    newcard.execError = 'never'
+    newcard.popClose = 'never'
+    newcard.errorTime = 10
+    newcard.verify = null
+    newcard.show = 'link'
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鍏冪礌
+    MKEmitter.emit('cardAddElement', [card.uuid, card.uuid], newcard)
+  }
+
+  pasteComponent = (res, resolve) => {
+    const { card } = this.state
+
+    let type = res.copyType
+    delete res.copyType
+
+    res.uuid = Utils.getuuid()
+    res.focus = true
+
+    if (type === 'customCardElement') {
+      MKEmitter.emit('cardAddElement', [card.uuid, card.uuid], res)
+    } else {
+      res.eleType = 'button'
+      MKEmitter.emit('cardAddElement', [card.uuid, card.uuid], res)
+    }
+    resolve({status: true})
+  }
+
+  render() {
+    const { card } = this.state
+
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-balcony-edit-box" style={_style} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} type="plus" />
+            <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <CopyComponent type="balcony" card={card}/>
+            <PasteComponent options={['action', 'customCardElement']} updateConfig={this.pasteComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
+            {card.wrap.datatype === 'static' ? <Icon style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <CardCellComponent cards={card} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
+      </div>
+    )
+  }
+}
+
+export default BalconyEditComponent
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/index.scss b/src/menu/components/card/balcony/index.scss
new file mode 100644
index 0000000..1e071bd
--- /dev/null
+++ b/src/menu/components/card/balcony/index.scss
@@ -0,0 +1,77 @@
+.menu-balcony-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 30px;
+  
+  .card-control {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    .anticon-tool {
+      right: auto;
+      left: 1px;
+      padding: 1px;
+    }
+  }
+  .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 {
+    overflow: hidden;
+    position: relative;
+    background-color: #ffffff;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    min-height: 20px;
+  }
+  
+  .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;
+    }
+  }
+  .card-add-button {
+    text-align: right;
+    clear: left;
+    .anticon-plus {
+      font-size: 20px;
+      color: #26C281;
+      padding: 5px;
+      margin-right: 10px;
+    }
+  }
+}
+.menu-balcony-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-balcony-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/card/balcony/wrapsetting/index.jsx b/src/menu/components/card/balcony/wrapsetting/index.jsx
new file mode 100644
index 0000000..a8332db
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/index.jsx
@@ -0,0 +1,83 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class BalconyWrapSetting extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="鍗$墖璁剧疆"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            config={config}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default BalconyWrapSetting
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/index.scss b/src/menu/components/card/balcony/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx b/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..d0124d5
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx
@@ -0,0 +1,415 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select, Cascader } from 'antd'
+
+import MenuUtils from '@/utils/utils-custom.js'
+import StyleInput from '@/menu/components/share/styleInput'
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    config: PropTypes.object,
+    wrap: PropTypes.object,
+    inputSubmit: PropTypes.func
+  }
+
+  state = {
+    roleList: [],
+    modules: [],
+    supmodules: [],
+    appType: sessionStorage.getItem('appType'),
+    linkType: this.props.wrap.linkType,
+    position: this.props.wrap.position,
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    let menu = fromJS(window.GLOB.customMenu).toJS()
+
+    let modules = MenuUtils.getLinkModules(menu.components)
+    if (!modules) {
+      modules = []
+    }
+
+    let _menu = fromJS(window.GLOB.customMenu).toJS()
+
+    let supmodules = MenuUtils.getSupModules(_menu.components, '')
+    if (!supmodules) {
+      supmodules = []
+    }
+
+    this.setState({roleList, modules, supmodules})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  chose = (val) => {
+    let values = {}
+    if (val === 'top') {
+      values = {
+        top: '0px',
+        left: '50%',
+        right: '',
+        bottom: '',
+        transform: 'translateX(-50%)'
+      }
+    } else if (val === 'top-left') {
+      values = {
+        top: '0px',
+        left: '0px',
+        right: '',
+        bottom: '',
+        transform: ''
+      }
+    } else if (val === 'top-right') {
+      values = {
+        top: '0px',
+        left: '',
+        right: '0px',
+        bottom: '',
+        transform: ''
+      }
+    } else if (val === 'left-middle') {
+      values = {
+        top: '50%',
+        left: '0px',
+        right: '',
+        bottom: '',
+        transform: 'translateY(-50%)'
+      }
+    } else if (val === 'right-middle') {
+      values = {
+        top: '50%',
+        left: '',
+        right: '0px',
+        bottom: '',
+        transform: 'translateY(-50%)'
+      }
+    } else if (val === 'bottom-left') {
+      values = {
+        top: '',
+        left: '0px',
+        right: '',
+        bottom: '0px',
+        transform: ''
+      }
+    } else if (val === 'bottom-right') {
+      values = {
+        top: '',
+        left: '',
+        right: '0px',
+        bottom: '0px',
+        transform: ''
+      }
+    } else if (val === 'bottom') {
+      values = {
+        top: '',
+        left: '50%',
+        right: '',
+        bottom: '0px',
+        transform: 'translateX(-50%)'
+      }
+    } else if (val === 'middle') {
+      values = {
+        top: '50%',
+        left: '50%',
+        right: '',
+        bottom: '',
+        transform: 'translate(-50%, -50%)'
+      }
+    }
+    this.props.form.setFieldsValue(values)
+  }
+
+  render() {
+    const { wrap } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { roleList, modules, supmodules, linkType, position } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨闈欐�佸�硷紝鏃犻渶閰嶇疆鏁版嵁婧愩��">
+                  <Icon type="question-circle" />
+                  鏁版嵁鏉ユ簮
+                </Tooltip>
+              }>
+                {getFieldDecorator('datatype', {
+                  initialValue: wrap.datatype
+                })(
+                  <Radio.Group>
+                    <Radio value="dynamic">鍔ㄦ��</Radio>
+                    <Radio value="static">闈欐��</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="缁勪欢涓庡叾浠栫粍浠朵箣闂寸殑鎺у埗绫诲瀷锛岀嫭绔嬭〃绀轰笌鍏朵粬娌℃湁鍏宠仈銆�">
+                  <Icon type="question-circle" />
+                  鍙楁帶绫诲瀷
+                </Tooltip>
+              }>
+                {getFieldDecorator('linkType', {
+                  initialValue: wrap.linkType || 'static'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({linkType: e.target.value})}>
+                    <Radio value="static">鐙珛</Radio>
+                    <Radio value="sync">鍚屾</Radio>
+                    <Radio value="sup">涓婄骇</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {linkType === 'sup' ? <Col span={12}>
+              <Form.Item label="涓婄骇缁勪欢">
+                {getFieldDecorator('supModule', {
+                  initialValue: wrap.supModule,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '涓婄骇缁勪欢!'
+                    }
+                  ]
+                })(
+                  <Cascader options={supmodules} expandTrigger="hover" placeholder="" />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {linkType === 'sup' ? <Col span={12}>
+              <Form.Item label="鏄剧ず鎺у埗">
+                {getFieldDecorator('supControl', {
+                  initialValue: wrap.supControl || 'show'
+                })(
+                  <Radio.Group>
+                    <Radio key="hidden" value="hidden"> 閫夎鏄剧ず </Radio>
+                    <Radio key="show" value="show"> 濮嬬粓鏄剧ず </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {linkType === 'sync' ? <Col span={12}>
+              <Form.Item label="鍚屾缁勪欢">
+                {getFieldDecorator('syncModule', {
+                  initialValue: wrap.syncModule,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鍚屾缁勪欢!'
+                    }
+                  ]
+                })(
+                  <Cascader options={modules} expandTrigger="hover" placeholder="" />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {linkType === 'sync' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="褰撳悓姝ョ粍浠跺彲澶氶�夋椂锛岃缃叏閫夋湁鏁堛��">
+                  <Icon type="question-circle" />
+                  鍏ㄩ��
+                </Tooltip>
+              }>
+                {getFieldDecorator('checkAll', {
+                  initialValue: wrap.checkAll || 'hidden'
+                })(
+                  <Radio.Group>
+                    <Radio key="hidden" value="hidden"> 闅愯棌 </Radio>
+                    <Radio key="show" value="show"> 鏄剧ず </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="浣跨敤鍥哄畾瀹氫綅鏃讹紝璇峰湪娴嬭瘯鐜涓煡鐪嬪畾浣嶆晥鏋溿��">
+                  <Icon type="question-circle" />
+                  浣嶇疆
+                </Tooltip>
+              }>
+                {getFieldDecorator('position', {
+                  initialValue: wrap.position || 'relative'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({position: e.target.value})}>
+                    <Radio value="relative">鐩稿瀹氫綅</Radio>
+                    <Radio value="fixed">鍥哄畾瀹氫綅</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="蹇嵎閫夋嫨">
+                <Select onSelect={this.chose}>
+                  <Select.Option key='1' value={'top'}>涓�</Select.Option>
+                  <Select.Option key='2' value={'top-left'}>宸︿笂</Select.Option>
+                  <Select.Option key='3' value={'top-right'}>鍙充笂</Select.Option>
+                  <Select.Option key='4' value={'left-middle'}>宸︿腑</Select.Option>
+                  <Select.Option key='5' value={'right-middle'}>鍙充腑</Select.Option>
+                  <Select.Option key='6' value={'bottom-left'}>宸︿笅</Select.Option>
+                  <Select.Option key='7' value={'bottom-right'}>鍙充笅</Select.Option>
+                  <Select.Option key='8' value={'bottom'}>涓�</Select.Option>
+                  <Select.Option key='9' value={'middle'}>涓棿</Select.Option>
+                </Select>
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濅笂">
+                {getFieldDecorator('top', {
+                  initialValue: wrap.top || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濆彸">
+                {getFieldDecorator('right', {
+                  initialValue: wrap.right || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濅笅">
+                {getFieldDecorator('bottom', {
+                  initialValue: wrap.bottom || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濆乏">
+                {getFieldDecorator('left', {
+                  initialValue: wrap.left || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="瀹為檯瀹藉害">
+                {getFieldDecorator('realwidth', {
+                  initialValue: wrap.realwidth || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="鍙樻崲">
+                {getFieldDecorator('transform', {
+                  initialValue: wrap.transform || ''
+                })(
+                  <Select>
+                    <Select.Option key='1' value={''}>鏃�</Select.Option>
+                    <Select.Option key='2' value={'translateY(-50%)'}>涓婄Щ50%</Select.Option>
+                    <Select.Option key='3' value={'translateY(50%)'}>涓嬬Щ50%</Select.Option>
+                    <Select.Option key='4' value={'translateX(-50%)'}>宸︾Щ50%</Select.Option>
+                    <Select.Option key='5' value={'translateX(50%)'}>鍙崇Щ50%</Select.Option>
+                    <Select.Option key='6' value={'translate(-50%, -50%)'}>宸︿笂绉�50%</Select.Option>
+                    <Select.Option key='7' value={'translate(-50%, 50%)'}>宸︿笅绉�50%</Select.Option>
+                    <Select.Option key='8' value={'translate(50%, -50%)'}>鍙充笂绉�50%</Select.Option>
+                    <Select.Option key='9' value={'translate(50%, 50%)'}>鍙充笅绉�50%</Select.Option>
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.blacklist || []
+                })(
+                  <Select
+                    showSearch
+                    mode="multiple"
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {roleList.map(option =>
+                      <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/settingform/index.scss b/src/menu/components/card/balcony/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..9644e12
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/settingform/index.scss
@@ -0,0 +1,36 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .css {
+    padding-top: 10px;
+    .css-class {
+      position: absolute;
+      right: 13px;
+      top: -15px;
+      z-index: 1;
+      button {
+        height: 25px;
+      }
+    }
+    .ant-form-item {
+      margin-bottom: 0;
+    }
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+      .code-mirror-wrap .code-mirror-area .CodeMirror {
+        height: 100px;
+        min-height: 100px;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
index 7bdc28b..4ce1876 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -1,9 +1,11 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
 import { Icon, Popover, Button } from 'antd'
+
+import { resetStyle } from '@/utils/utils-custom.js'
 import './index.scss'
 
-const Card = ({ id, card, moveCard, findCard, editCard, delCard, profileCard, changeStyle, doubleClickCard }) => {
+const Card = ({ id, card, moveCard, findCard, editCard, copyCard, delCard, profileCard, changeStyle, doubleClickCard }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'action', id, originalIndex },
@@ -25,12 +27,6 @@
     },
   })
 
-  let _style = {opacity: isDragging ? 0 : 1}
-
-  if (card.style) {
-    _style = {...card.style, opacity: isDragging ? 0 : 1}
-  }
-
   let hasProfile = false
   if (['pop', 'prompt', 'exec'].includes(card.OpenType)) {
     hasProfile = true
@@ -41,25 +37,27 @@
   }
 
   let btnElement = null
+  let _style = resetStyle(card.style)
   if (card.show === 'icon') {
-    btnElement = (<Button style={card.btnstyle} type="link"><Icon type={card.icon}/></Button>)
+    btnElement = (<Button style={_style} type="link"><Icon type={card.icon}/></Button>)
   } else if (card.show === 'link') {
-    btnElement = (<Button style={card.btnstyle} type="link">{card.label}{card.icon ? <Icon type={card.icon}/> : null}</Button>)
+    btnElement = (<Button style={_style} type="link">{card.icon ? <Icon type={card.icon}/> : null}{card.label}</Button>)
   } else {
-    btnElement = (<Button icon={card.icon} style={card.btnstyle}> {card.label} </Button>)
+    btnElement = (<Button style={_style}> {card.label}{card.icon ? <Icon type={card.icon}/> : null} </Button>)
   }
 
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
         <Icon className="edit" title="缂栬緫" type="edit" onClick={() => editCard(id)} />
+        <Icon className="copy" title="澶嶅埗" type="copy" onClick={() => copyCard(id)} />
         <Icon className="close" title="鍒犻櫎" type="close" onClick={() => delCard(id)} />
         <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)} type="font-colors" />
         {hasProfile ? <Icon className="profile" title="setting" type="profile" onClick={() => profileCard(id)} /> : null}
       </div>
     } trigger="hover">
-      <div ref={node => drag(drop(node))} className={'ant-col card-button-cell ant-col-' + card.width} onDoubleClick={() => doubleClickCard(id)}>
-        <div style={_style}>
+      <div ref={node => drag(drop(node))} className={'ant-col card-button-cell ant-col-' + card.width} onDoubleClick={(e) => {e.stopPropagation(); doubleClickCard(id)}}>
+        <div style={{opacity: isDragging ? 0 : 1}}>
           {btnElement}
         </div>
       </div>
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
index 96b6549..9ee5976 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -11,13 +11,18 @@
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import './index.scss'
 
 const BarCode = asyncComponent(() => import('@/components/barcode'))
 const QrCode = asyncComponent(() => import('@/components/qrcode'))
 const Video = asyncComponent(() => import('@/components/video'))
 const MarkColumn = asyncIconComponent(() => import('@/menu/components/share/markcomponent'))
+const PicRadio = {
+  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
+  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
+  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
+}
 
 const Card = ({ id, parent, fields, card, moveCard, findCard, editCard, delCard, copyCard, changeStyle, updateMarks, doubleClickCard }) => {
   const originalIndex = findCard(id).index
@@ -45,6 +50,17 @@
   
   if (card.style) {
     _style = {...card.style, opacity: isDragging ? 0 : 1}
+    _style = resetStyle(_style)
+  }
+  if (card.eleType === 'picture' && card.maxWidth) {
+    _style.maxWidth = card.maxWidth
+    let left = _style.marginLeft && _style.marginLeft !== '0px' ? _style.marginLeft : 'auto'
+    let right = _style.marginRight && _style.marginRight !== '0px' ? _style.marginRight : 'auto'
+    _style.margin = (_style.marginTop || 0) + ' ' + right + ' ' + (_style.marginBottom || 0) + ' ' + left
+    delete _style.marginLeft
+    delete _style.marginRight
+    delete _style.marginTop
+    delete _style.marginBottom
   }
 
   const getContent = () => {
@@ -85,12 +101,8 @@
         _imagestyle.borderRadius = card.style.borderRadius
       }
 
-      if (card.lenWidRadio === '16:9') {
-        _imagestyle.paddingTop = '56.25%'
-      } else if (card.lenWidRadio === '3:2') {
-        _imagestyle.paddingTop = '66.67%'
-      } else if (card.lenWidRadio === '4:3') {
-        _imagestyle.paddingTop = '75%'
+      if (PicRadio[card.lenWidRadio]) {
+        _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
       } else {
         _imagestyle.paddingTop = '100%'
       }
@@ -146,7 +158,7 @@
         <Icon className="copy" title="澶嶅埗" type="copy" onClick={() => copyCard(id)} />
         <Icon className="close" title="鍒犻櫎" type="close" onClick={() => delCard(id)} />
         <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => changeStyle(id)} type="font-colors" />
-        {['text', 'number', 'slider'].includes(card.eleType) ? <MarkColumn columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
+        {['text', 'number', 'slider', 'sequence'].includes(card.eleType) ? <MarkColumn columns={fields} type={card.eleType} marks={card.marks} onSubmit={(vals) => updateMarks({...card, marks: vals})} /> : null }
       </div>
     } trigger="hover">
       <div ref={node => drag(drop(node))} className={'ant-col card-cell ant-col-' + card.width}>
diff --git a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
index eda8cc2..96eea80 100644
--- a/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -38,7 +38,11 @@
     let copycard = fromJS(card).toJS()
     let _cards = fromJS(cards).toJS()
 
-    copycard.copyType = 'customCardElement'
+    if (card.eleType === 'button') {
+      copycard.copyType = 'action'
+    } else {
+      copycard.copyType = 'customCardElement'
+    }
     copycard.focus = true
 
     let _val = fromJS(copycard).toJS()
@@ -112,6 +116,7 @@
               key={card.uuid}
               card={card}
               parent={parent}
+              copyCard={copyCard}
               moveCard={moveCard}
               editCard={editCard}
               changeStyle={changeStyle}
diff --git a/src/menu/components/card/cardcellcomponent/elementform/index.jsx b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
index 2f0f75c..38de87f 100644
--- a/src/menu/components/card/cardcellcomponent/elementform/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -15,7 +15,7 @@
   sequence: ['eleType', 'width'],
   text: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix', 'link'],
   number: ['eleType', 'datatype', 'format', 'width', 'height', 'prefix', 'postfix'],
-  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'link'],
+  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'maxWidth', 'link'],
   video: ['eleType', 'datatype', 'width', 'aspectRatio', 'autoPlay', 'loop'],
   icon: ['eleType', 'icon', 'datatype', 'width'],
   slider: ['eleType', 'datatype', 'width', 'color', 'maxValue'],
diff --git a/src/menu/components/card/cardcellcomponent/formconfig.jsx b/src/menu/components/card/cardcellcomponent/formconfig.jsx
index b81da36..ac0423d 100644
--- a/src/menu/components/card/cardcellcomponent/formconfig.jsx
+++ b/src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -4,11 +4,11 @@
 const Formdict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
 
 /**
- * @description 鑾峰彇鎸夐挳琛ㄥ崟閰嶇疆淇℃伅
- * @param {*} card           缂栬緫鎸夐挳
- * @param {*} type           鎸夐挳绫诲瀷锛岀敤浜庡尯鍒嗗彲閫夌殑鎵撳紑鏂瑰紡
+ * @description 鑾峰彇鍏冪礌閰嶇疆淇℃伅
+ * @param {*} card
+ * @param {*} type
  */
-export function getCardCellForm (card, type) {
+export function getCardCellForm (card, type, subtype, cardCell) {
   let _options = [
     { value: 'text', text: '鏂囨湰'},
     { value: 'number', text: '鏁板��'},
@@ -22,7 +22,7 @@
     { value: 'currentDate', text: '褰撳墠鏃堕棿'},
   ]
 
-  if (type === 'table') {
+  if (type === 'table' || (type === 'card' && subtype === 'datacard')) {
     _options.push({value: 'sequence', text: '搴忓彿'})
   }
   let appMenus = []
@@ -40,6 +40,17 @@
     } else {
       appMenus = []
     }
+  }
+
+  let dataTypes = [
+    { value: 'dynamic', text: '鍔ㄦ��' },
+    { value: 'static', text: '闈欐��' }
+  ]
+  if (cardCell.$cardType === 'extendCard') {
+    card.datatype = 'static'
+    dataTypes = [
+      { value: 'static', text: '闈欐��' }
+    ]
   }
 
   let forms = [
@@ -98,10 +109,7 @@
       label: '鏁版嵁绫诲瀷',
       initVal: card.datatype || 'static',
       required: true,
-      options: [
-        { value: 'dynamic', text: '鍔ㄦ��' },
-        { value: 'static', text: '闈欐��' }
-      ]
+      options: dataTypes
     },
     {
       type: 'select',
@@ -293,10 +301,32 @@
       required: true,
       options: [
         { value: '1:1', text: '1:1' },
-        { value: '3:2', text: '3:2' },
         { value: '4:3', text: '4:3' },
-        { value: '16:9', text: '16:9' }
+        { value: '3:2', text: '3:2' },
+        { value: '16:9', text: '16:9' },
+        { value: '2:1', text: '2:1' },
+        { value: '3:1', text: '3:1' },
+        { value: '4:1', text: '4:1' },
+        { value: '5:1', text: '5:1' },
+        { value: '6:1', text: '6:1' },
+        { value: '7:1', text: '7:1' },
+        { value: '8:1', text: '8:1' },
+        { value: '9:1', text: '9:1' },
+        { value: '10:1', text: '10:1' },
+        { value: '3:4', text: '3:4' },
+        { value: '2:3', text: '2:3' },
+        { value: '9:16', text: '9:16' },
       ]
+    },
+    {
+      type: 'number',
+      key: 'maxWidth',
+      min: 10,
+      max: 2000,
+      label: '鏈�澶у搴�',
+      initVal: card.maxWidth || '',
+      tooltip: '鍥剧墖瀹藉害鐨勬渶澶у�笺��',
+      required: false,
     },
     {
       type: 'select',
@@ -332,7 +362,7 @@
       forbid: !isApp,
       options: [
         { value: '', text: '鏃�' },
-        { value: 'page', text: '鑿滃崟' },
+        // { value: 'page', text: '鑿滃崟' },
         { value: 'linkpage', text: '鍏宠仈鑿滃崟' },
         { value: 'custom', text: '閾炬帴' }
       ]
@@ -358,15 +388,15 @@
         { value: 'self', text: '褰撳墠椤甸潰' }
       ]
     },
-    {
-      type: 'select',
-      key: 'copyMenuId',
-      label: '澶嶅埗鑿滃崟',
-      initVal: card.copyMenuId || '',
-      required: false,
-      forbid: !isApp,
-      options: appMenus
-    },
+    // {
+    //   type: 'select',
+    //   key: 'copyMenuId',
+    //   label: '澶嶅埗鑿滃崟',
+    //   initVal: card.copyMenuId || '',
+    //   required: false,
+    //   forbid: !isApp,
+    //   options: appMenus
+    // },
     {
       type: 'radio',
       key: 'joint',
diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx
index 58deb61..e46935d 100644
--- a/src/menu/components/card/cardcellcomponent/index.jsx
+++ b/src/menu/components/card/cardcellcomponent/index.jsx
@@ -34,6 +34,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,          // 缂栬緫涓厓绱�
     formlist: null,      // 琛ㄥ崟淇℃伅
     elements: null,      // 鎸夐挳缁�
@@ -47,16 +48,25 @@
    */
   UNSAFE_componentWillMount () {
     const { elements } = this.props
+    let _elements = fromJS(elements).toJS()
 
     this.setState({
-      elements: fromJS(elements).toJS()
+      elements: _elements.map(item => {
+        if (item.btnstyle) { // 鍏煎
+          item.style = item.style || {}
+          item.style = {...item.style, ...item.btnstyle}
+          delete item.btnstyle
+        }
+
+        return item
+      })
     })
   }
 
   componentDidMount () {
-    MKEmitter.addListener('cardAddElement', this.cardAddElement)
     MKEmitter.addListener('submitStyle', this.getStyle)
     MKEmitter.addListener('submitModal', this.handleSave)
+    MKEmitter.addListener('cardAddElement', this.cardAddElement)
     MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
   }
 
@@ -83,9 +93,9 @@
     this.setState = () => {
       return
     }
-    MKEmitter.removeListener('cardAddElement', this.cardAddElement)
     MKEmitter.removeListener('submitStyle', this.getStyle)
     MKEmitter.removeListener('submitModal', this.handleSave)
+    MKEmitter.removeListener('cardAddElement', this.cardAddElement)
     MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
   }
 
@@ -126,12 +136,10 @@
     const { cards, cardCell } = this.props
 
     let _style = element.style ? fromJS(element.style).toJS() : {}
-    let options = ['font', 'border', 'padding', 'margin', 'backgroundColor']
+    let options = ['font', 'border', 'padding', 'margin', 'background']
 
     if (element.eleType === 'button') {
-      if (element.btnstyle) {
-        _style = {..._style, ...element.btnstyle}
-      }
+      options.push('width', 'float')
     } else if (element.eleType === 'picture') {
       options = ['border', 'margin']
     } else if (element.eleType === 'slider') {
@@ -187,6 +195,17 @@
       if (line) {
         _card.innerHeight = fontSize * lineHeight * line
       }
+    } else if (_card.eleType === 'sequence') {
+      _card.style = style
+
+      let fontSize = 14
+      let lineHeight = 1.5
+
+      if (_card.style.fontSize) {
+        fontSize = parseInt(_card.style.fontSize)
+      }
+
+      _card.innerHeight = fontSize * lineHeight
     } else if (_card.eleType === 'barcode') {
       _card.style = style
 
@@ -198,47 +217,7 @@
 
       _card.innerHeight = _card.barHeight + (_card.displayValue === 'true' ? fontSize + 2 : 0)
     } else if (_card.eleType === 'button') { // 鎷嗗垎style
-      let _style = fromJS(style).toJS()
-      _card.style = {}
-
-      if (_style.marginTop) {
-        _card.style.marginTop = _style.marginTop
-        delete _style.marginTop
-      }
-      if (_style.marginBottom) {
-        _card.style.marginBottom = _style.marginBottom
-        delete _style.marginBottom
-      }
-      if (_style.marginLeft) {
-        _card.style.marginLeft = _style.marginLeft
-        delete _style.marginLeft
-      }
-      if (_style.marginRight) {
-        _card.style.marginRight = _style.marginRight
-        delete _style.marginRight
-      }
-      if (_style.paddingTop) {
-        _card.style.paddingTop = _style.paddingTop
-        delete _style.paddingTop
-      }
-      if (_style.paddingBottom) {
-        _card.style.paddingBottom = _style.paddingBottom
-        delete _style.paddingBottom
-      }
-      if (_style.paddingLeft) {
-        _card.style.paddingLeft = _style.paddingLeft
-        delete _style.paddingLeft
-      }
-      if (_style.paddingRight) {
-        _card.style.paddingRight = _style.paddingRight
-        delete _style.paddingRight
-      }
-      if (_style.textAlign) {
-        _card.style.textAlign = _style.textAlign
-        delete _style.textAlign
-      }
-
-      _card.btnstyle = _style
+      _card.style = style
     } else {
       _card.style = style
     }
@@ -259,7 +238,7 @@
    * @description 鍏冪礌缂栬緫锛岃幏鍙栧厓绱犺〃鍗曚俊鎭�
    */
   handleElement = (card) => {
-    const { cards } = this.props
+    const { cards, cardCell } = this.props
 
     if (card.eleType === 'button') {
       this.handleAction(card)
@@ -267,7 +246,7 @@
       this.setState({
         visible: true,
         card: card,
-        formlist: getCardCellForm(card, cards.type)
+        formlist: getCardCellForm(card, cards.type, cards.subtype, cardCell)
       })
     }
   }
@@ -310,7 +289,7 @@
     this.setState({
       actvisible: true,
       card: card,
-      formlist: getActionForm(card, functip, cards.setting, usefulFields, 'card', menulist, modules)
+      formlist: getActionForm(card, functip, cards, usefulFields, 'card', menulist, modules)
     })
   }
 
@@ -404,18 +383,18 @@
         if (cell.uuid === res.uuid) {
           res = {...cell, ...res}
           delete res.focus
-          let btnstyle = {}
+          let style = {}
 
-          if (res.class !== cell.class || res.show !== cell.show || !res.btnstyle) {
+          if (res.class !== cell.class || res.show !== cell.show || !res.style) {
             if (res.show === 'link' || res.show === 'icon') {
-              btnstyle.color = color[res.class]
-              btnstyle.backgroundColor = 'transparent'
+              style.color = color[res.class]
+              style.backgroundColor = 'transparent'
             } else {
-              btnstyle.color = '#ffffff'
-              btnstyle.backgroundColor = color[res.class]
+              style.color = '#ffffff'
+              style.backgroundColor = color[res.class]
             }
           }
-          res.btnstyle = {...res.btnstyle, ...btnstyle}
+          res.style = {...res.style, ...style}
 
           return res
         }
@@ -436,17 +415,14 @@
    */
   deleteElement = (card) => {
     const { cards, cardCell, side } = this.props
-    const { dict, elements } = this.state
+    const { dict, elements, appType } = this.state
     let _this = this
 
     confirm({
       content: dict['model.confirm'] + dict['model.delete'] + '鍏冪礌鍚楋紵',
       onOk() {
         let _elements = elements.filter(item => item.uuid !== card.uuid)
-
-        if (card.eleType === 'button') {
-          MKEmitter.emit('delButtons', [card.uuid])
-        }
+        
         if (card.OpenType === 'popview' || card.verify || card.modal) {
           card.$parentId = cardCell.uuid
           card.$side = side || ''
@@ -459,6 +435,11 @@
         }, () => {
           _this.props.updateElement(_elements)
         })
+
+        if (card.eleType !== 'button') return
+        if (appType === 'mob' || (appType === 'pc' && card.OpenType !== 'popview')) return
+        
+        MKEmitter.emit('delButtons', [card.uuid])
       },
       onCancel() {}
     })
@@ -500,15 +481,16 @@
 
   handleSubConfig = (item) => {
     const { cards } = this.props
+    const { appType } = this.state
     let btn = fromJS(item).toJS()
 
-    if ((sessionStorage.getItem('style-control') && sessionStorage.getItem('style-control') !== 'false')) return
+    if ((sessionStorage.getItem('style-control') && sessionStorage.getItem('style-control') === 'true')) return
 
     if (btn.eleType === 'button') {
       if (btn.OpenType === 'pop') {
         if (!btn.modal) {
           btn.modal = {
-            setting: { title: btn.label, width: 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
+            setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
             tables: [],
             groups: [],
             fields: []
@@ -647,7 +629,7 @@
         >
           <ActionForm
             dict={dict}
-            type="card"
+            type={cards.type === 'balcony' ? '' : 'card'}
             card={card}
             formlist={this.state.formlist}
             inputSubmit={this.handleActionSubmit}
diff --git a/src/menu/components/card/cardcellcomponent/index.scss b/src/menu/components/card/cardcellcomponent/index.scss
index 2fd0ecb..6ad726c 100644
--- a/src/menu/components/card/cardcellcomponent/index.scss
+++ b/src/menu/components/card/cardcellcomponent/index.scss
@@ -16,16 +16,23 @@
     cursor: pointer;
   }
 
+  .ant-btn {
+    padding: 0;
+  }
+
   .card-button-cell {
     float: left;
     button {
+      width: 100%;
       background-size: cover;
       background-position: center center;
       height: auto;
       min-height: 32px;
+      text-align: center;
       span {
         font-style: inherit;
         text-decoration: inherit;
+        font-weight: inherit;
       }
     }
   }
diff --git a/src/menu/components/card/cardcomponent/index.jsx b/src/menu/components/card/cardcomponent/index.jsx
index f32968a..af376d8 100644
--- a/src/menu/components/card/cardcomponent/index.jsx
+++ b/src/menu/components/card/cardcomponent/index.jsx
@@ -8,13 +8,14 @@
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import SettingForm from './settingform'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 const CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('./pastecomponent'))
 
 class CardBoxComponent extends Component {
   static propTpyes = {
@@ -88,7 +89,7 @@
     this.props.updateElement(_card)
   }
 
-  updateCard = (elements) => {
+  updateCard = (elements, type) => {
     const { card, side } = this.state
 
     let _card = {}
@@ -99,9 +100,16 @@
       _card = {...card, elements: elements}
     }
 
-    this.setState({
-      card: _card
-    })
+    if (type === 'paste') {
+      this.setState({
+        card: _card,
+        elements: fromJS(elements).toJS()
+      })
+    } else {
+      this.setState({
+        card: _card
+      })
+    }
 
     this.props.updateElement(_card)
   }
@@ -213,6 +221,14 @@
     }
   }
 
+  doubleClickCard = () => {
+    const { card } = this.state
+
+    if (card.setting.click === 'menu' && card.setting.menu) {
+      MKEmitter.emit('changeEditMenu', {MenuID: card.setting.menu})
+    }
+  }
+
   render() {
     const { cards, offset } = this.props
     const { card, elements, side, settingVisible, dict } = this.state
@@ -233,10 +249,11 @@
         marginTop: card.style.marginTop
       }
     }
+    _style = resetStyle(_style)
 
     return (
       <Col span={card.setting.width || 6} offset={offset || 0}>
-        <div className="card-item" style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <div className="card-item" style={_style} onClick={this.clickComponent} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
           <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
           <div className="card-control">
             <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
@@ -245,16 +262,17 @@
                 <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
                 <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.setState({settingVisible: true})} />
                 <CopyComponent type="cardcell" card={card}/>
+                <PasteComponent elements={elements} options={['action', 'customCardElement']} updateConfig={(list) => this.updateCard(list, 'paste')} />
                 <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-                {cards.subtype === 'propcard' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                   <div className="mk-popover-control">
-                    <Icon className="plus" title="宸︾Щ" type="arrow-left" onClick={() => this.props.move(card, 'left')} />
-                    <Icon className="close" title="鍙崇Щ" type="arrow-right" onClick={() => this.props.move(card, 'right')} />
+                    <Icon className="plus" title="鍓嶇Щ" type="arrow-left" onClick={() => this.props.move(card, 'left')} />
+                    <Icon className="close" title="鍚庣Щ" type="arrow-right" onClick={() => this.props.move(card, 'right')} />
                   </div>
                 } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}>
                   <Icon type="swap" id={card.uuid + 'swap'}/>
-                </Popover> : null}
-                {cards.subtype === 'propcard' ? <Icon className="close" title="鍒犻櫎鍗$墖" type="delete" onClick={() => this.props.deleteElement(card)} /> : null}
+                </Popover>
+                {cards.subtype === 'propcard' || card.$cardType === 'extendCard' ? <Icon className="close" title="鍒犻櫎鍗$墖" type="delete" onClick={() => this.props.deleteElement(card)} /> : null}
                 {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
               </div>
             } trigger="hover">
@@ -266,7 +284,7 @@
           wrapClassName="popview-modal"
           title={'鍗$墖璁剧疆'}
           visible={settingVisible}
-          width={700}
+          width={800}
           maskClosable={false}
           okText={dict['model.submit']}
           onOk={this.settingSubmit}
diff --git a/src/menu/components/card/cardcomponent/pastecomponent/index.jsx b/src/menu/components/card/cardcomponent/pastecomponent/index.jsx
new file mode 100644
index 0000000..bc98b34
--- /dev/null
+++ b/src/menu/components/card/cardcomponent/pastecomponent/index.jsx
@@ -0,0 +1,77 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Icon, Modal, notification } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
+
+class PasteController extends Component {
+  static propTpyes = {
+    config: PropTypes.object,        // 缁勪欢閰嶇疆
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false
+  }
+
+  handleMenuClick = () => {
+    this.setState({visible: true})
+  }
+
+  pasteSubmit = () => {
+    const { options, elements } = this.props
+    this.pasteFormRef.handleConfirm().then(res => {
+      if (!options.includes(res.copyType)) {
+        notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
+        return
+      }
+
+      let _uuid = Utils.getuuid()
+      if (res.copyType === 'action' && res.OpenType === 'popview') {
+        let _cell = fromJS(res).toJS()
+        _cell.$originUuid = res.uuid
+        _cell.uuid = _uuid
+        MKEmitter.emit('copyButtons', [_cell])
+      }
+      res.uuid = _uuid
+
+      this.props.updateConfig([...elements, res])
+      this.setState({visible: false})
+
+      notification.success({
+        top: 92,
+        message: '绮樿创鎴愬姛锛�',
+        duration: 2
+      })
+    })
+  }
+
+  render() {
+    const { visible } = this.state
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Icon type="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} />
+        <Modal
+          title="绮樿创"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.pasteSubmit}
+          onCancel={() => {this.setState({visible: false})}}
+          destroyOnClose
+        >
+          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default PasteController
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/menu/components/card/cardcomponent/pastecomponent/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/menu/components/card/cardcomponent/pastecomponent/index.scss
diff --git a/src/menu/components/card/cardcomponent/settingform/index.jsx b/src/menu/components/card/cardcomponent/settingform/index.jsx
index 738bd50..6424977 100644
--- a/src/menu/components/card/cardcomponent/settingform/index.jsx
+++ b/src/menu/components/card/cardcomponent/settingform/index.jsx
@@ -17,15 +17,15 @@
   state = {
     type: this.props.setting.type || 'simple',
     click: this.props.setting.click || '',
-    isApp: sessionStorage.getItem('appType') === 'pc',
+    appType: sessionStorage.getItem('appType'),
     menulist: []
   }
 
   UNSAFE_componentWillMount() {
-    const { isApp } = this.state
+    const { appType } = this.state
     let menulist = null
 
-    if (isApp) {
+    if (appType) {
       menulist = sessionStorage.getItem('appMenus')
     } else {
       menulist = sessionStorage.getItem('fstMenuList')
@@ -67,7 +67,7 @@
   render() {
     const { setting, cards } = this.props
     const { getFieldDecorator } = this.props.form
-    const { menulist, click, isApp } = this.state
+    const { menulist, click, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -81,7 +81,7 @@
     }
 
     return (
-      <div className="model-menu-setting-form">
+      <div className="model-menu-card-setting-form">
         <Form {...formItemLayout}>
           <Row gutter={24}>
             <Col span={12}>
@@ -102,7 +102,7 @@
                 })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit}/>)}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="閫夋嫨澶嶅紡鍗℃椂锛屽彲閰嶇疆榧犳爣鎮诞鏃剁殑鏄剧ず淇℃伅銆�">
                   <Icon type="question-circle" />
@@ -118,7 +118,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             {this.state.type === 'multi' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="澶嶅紡鍗$墖榧犳爣鎮诞淇℃伅鐨勫姩鐢绘晥鏋溿��">
@@ -155,19 +155,25 @@
               </Form.Item>
             </Col> : null}
             <Col span={12}>
-              <Form.Item label="鐐瑰嚮浜嬩欢">
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="褰撻�夋嫨瑙﹀彂鎸夐挳鏃讹紝鍙湁褰撳崱鐗囦腑鍙瓨鍦ㄤ竴涓寜閽椂鏈夋晥銆�">
+                  <Icon type="question-circle" />
+                  鐐瑰嚮浜嬩欢
+                </Tooltip>
+              }>
                 {getFieldDecorator('click', {
                   initialValue: click
                 })(
-                  <Radio.Group onChange={(e) => this.setState({click: e.target.value})}>
+                  <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({click: e.target.value})}>
                     <Radio value="">鏃�</Radio>
                     <Radio value="menu">鑿滃崟</Radio>
                     <Radio value="link">閾炬帴</Radio>
+                    <Radio value="button">鎸夐挳</Radio>
                   </Radio.Group>
                 )}
               </Form.Item>
             </Col>
-            {!isApp && click === 'menu' ? <Col span={12}>
+            {!appType && click === 'menu' ? <Col span={12}>
               <Form.Item label="鑿滃崟">
                 {getFieldDecorator('menu', {
                   initialValue: setting.menu || [],
@@ -182,7 +188,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {isApp && click === 'menu' ? <Col span={12}>
+            {appType && click === 'menu' ? <Col span={12}>
               <Form.Item label="鍏宠仈鑿滃崟">
                 {getFieldDecorator('menu', {
                   initialValue: setting.menu || '',
@@ -217,7 +223,7 @@
                 })( <TextArea rows={2}/> )}
               </Form.Item>
             </Col> : null}
-            {isApp ? <Col span={12}>
+            {appType === 'pc' && click !== '' && click !== 'button' ? <Col span={12}>
               <Form.Item label="鎵撳紑鏂瑰紡">
                 {getFieldDecorator('open', {
                   initialValue: setting.open || 'blank'
@@ -229,7 +235,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {click !== '' ? <Col span={12}>
+            {click !== '' && click !== 'button' ? <Col span={12}>
               <Form.Item label="鍙傛暟鎷兼帴">
                 {getFieldDecorator('joint', {
                   initialValue: setting.joint || 'true'
diff --git a/src/menu/components/card/cardcomponent/settingform/index.scss b/src/menu/components/card/cardcomponent/settingform/index.scss
index 8898344..36d76eb 100644
--- a/src/menu/components/card/cardcomponent/settingform/index.scss
+++ b/src/menu/components/card/cardcomponent/settingform/index.scss
@@ -1,4 +1,4 @@
-.model-menu-setting-form {
+.model-menu-card-setting-form {
   position: relative;
 
   .anticon-question-circle {
@@ -16,4 +16,7 @@
       width: 84%;
     }
   }
+  .ant-radio-wrapper {
+    margin-right: 3px;
+  }
 }
\ No newline at end of file
diff --git a/src/menu/components/card/data-card/index.jsx b/src/menu/components/card/data-card/index.jsx
index 7b12967..5c85b95 100644
--- a/src/menu/components/card/data-card/index.jsx
+++ b/src/menu/components/card/data-card/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -15,6 +15,7 @@
 const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
 const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
 const CardComponent = asyncComponent(() => import('../cardcomponent'))
+const MobPagination = asyncIconComponent(() => import('@/menu/components/share/mobPagination'))
 const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
@@ -34,14 +35,15 @@
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     card: null,
+    appType: sessionStorage.getItem('appType'),
     back: false
   }
 
   UNSAFE_componentWillMount () {
     const { card } = this.props
+    const { appType } = this.state
 
     if (card.isNew) {
-      let ismob = sessionStorage.getItem('appType') === 'mob'
       let _card = {
         uuid: card.uuid,
         type: card.type,
@@ -56,7 +58,7 @@
         name: card.name,
         subtype: card.subtype,
         setting: { interType: 'system' },
-        wrap: { name: card.name, width: card.width || 24, title: '', pagestyle: 'page', switch: 'false' },
+        wrap: { name: card.name, width: card.width || 24, title: '', pagestyle: 'page', switch: 'false', cardType: '' },
         style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
         headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
         columns: [],
@@ -66,7 +68,7 @@
         btnlog: [],
         subcards: [{
           uuid: Utils.getuuid(),
-          setting: { width: ismob ? 24 : 6, type: 'simple'},
+          setting: { width: appType === 'mob' ? 24 : 6, type: 'simple'},
           style: {
             borderWidth: '1px', borderColor: '#e8e8e8',
             paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
@@ -192,6 +194,7 @@
    * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
    */
   deleteCard = (cell) => {
+    const { appType } = this.state
     let card = fromJS(this.state.card).toJS()
     let _this = this
 
@@ -200,25 +203,31 @@
       onOk() {
         card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
 
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        cell.backElements && cell.backElements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        MKEmitter.emit('delButtons', uuids)
-
         if (card.btnlog) {
           card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
         }
 
         _this.setState({card})
         _this.props.updateConfig(card)
+
+        if (appType === 'mob') return
+
+        let uuids = []
+
+        cell.elements && cell.elements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+        cell.backElements && cell.backElements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -285,27 +294,27 @@
     newcard.execError = 'never'
     newcard.verify = null
     newcard.show = 'button'
-    newcard.btnstyle = {marginRight: '15px'}
+    newcard.style = {marginRight: '15px'}
 
     // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
     MKEmitter.emit('addButton', card.uuid, newcard)
   }
 
   setSubConfig = (item) => {
-    const { card } = this.state
+    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: 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: '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') {
+    } else if (btn.OpenType === 'popview' && appType !== 'mob') {
       MKEmitter.emit('changePopview', card, btn)
     }
   }
@@ -374,6 +383,54 @@
     }
   }
 
+  addCard = () => {
+    let card = fromJS(this.state.card).toJS()
+    let height = card.subcards[0].style.height
+    if (height === 'auto') {
+      height = '100px'
+    }
+
+    let newcard = {
+      uuid: Utils.getuuid(),
+      $cardType: 'extendCard',
+      setting: { width: 6, type: 'simple', click: 'button'},
+      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.setState({card})
+    this.props.updateConfig(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.setState({card})
+    this.props.updateConfig(card)
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -382,7 +439,7 @@
   }
 
   render() {
-    const { card } = this.state
+    const { card, appType } = this.state
 
     let offset = 0
     if (card.wrap.cardFloat && card.wrap.cardFloat !== 'left') {
@@ -395,17 +452,19 @@
         offset = Math.floor(offset / 2)
       }
     }
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-data-card-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className={'menu-data-card-edit-box ' + appType} style={_style} onClick={this.clickComponent} id={card.uuid}>
         <NormalHeader defaultshow="hidden" config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
-            <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" />
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鍗$墖" onClick={this.addCard} type="plus" /> : null}
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
             <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
             <WrapComponent config={card} updateConfig={this.updateComponent} />
             <CopyComponent type="datacard" card={card}/>
-            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
+            <PasteComponent config={card} options={['action', 'search', 'form', 'cardcell']} updateConfig={this.updateComponent} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
             <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
             <UserComponent config={card}/>
@@ -415,10 +474,11 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
-        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
-        {card.subcards.map((subcard, index) => (<CardComponent key={subcard.uuid} offset={!index ? offset : 0} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
+        <ActionComponent config={card} type="datacard" setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
+        {card.subcards.map((subcard, index) => (<CardComponent key={subcard.uuid} offset={!index ? offset : 0} cards={card} card={subcard} move={this.move} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
         <div style={{clear: 'both'}}></div>
-        {card.wrap.pagestyle !== 'switch' && card.setting.laypage === 'true' ? <Pagination total={85} size="small" showTotal={total => `鍏� ${total} 鏉} pageSize={20} defaultCurrent={1}/> : null}
+        {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}
       </div>
     )
   }
diff --git a/src/menu/components/card/data-card/index.scss b/src/menu/components/card/data-card/index.scss
index 6346310..71b6f6e 100644
--- a/src/menu/components/card/data-card/index.scss
+++ b/src/menu/components/card/data-card/index.scss
@@ -75,12 +75,31 @@
       line-height: 55px;
     }
   }
+  .normal-pagination {
+    .am-button::before {
+      display: none;
+    }
+    .am-button {
+      border: none;
+      font-size: 16px;
+    }
+  }
 }
 .menu-data-card-edit-box::after {
   display: block;
   content: ' ';
   clear: both;
 }
+.menu-data-card-edit-box.mob {
+  .model-menu-action-list {
+    position: absolute;
+    top: 5px;
+    right: 0px;
+    .page-card {
+      line-height: 40px;
+    }
+  }
+}
 .menu-data-card-edit-box:hover {
   z-index: 1;
   box-shadow: 0px 0px 4px #1890ff;
diff --git a/src/menu/components/card/data-card/wrapsetting/index.jsx b/src/menu/components/card/data-card/wrapsetting/index.jsx
index 81346a6..8877617 100644
--- a/src/menu/components/card/data-card/wrapsetting/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/index.jsx
@@ -8,7 +8,7 @@
 import SettingForm from './settingform'
 import './index.scss'
 
-class DataSource extends Component {
+class CardWrapSetting extends Component {
   static propTpyes = {
     config: PropTypes.any,
     updateConfig: PropTypes.func
@@ -80,4 +80,4 @@
   }
 }
 
-export default DataSource
\ No newline at end of file
+export default CardWrapSetting
\ No newline at end of file
diff --git a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
index 08b58e2..d1c8eb0 100644
--- a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
@@ -6,14 +6,17 @@
 
 class SettingForm extends Component {
   static propTpyes = {
-    dict: PropTypes.object,      // 瀛楀吀椤�
-    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
-    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
-    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+    dict: PropTypes.object,
+    config: PropTypes.object,
+    wrap: PropTypes.object,
+    inputSubmit: PropTypes.func
   }
 
   state = {
-    roleList: []
+    roleList: [],
+    appType: sessionStorage.getItem('appType'),
+    cardType: this.props.wrap.cardType,
+    MenuType: ''
   }
 
   UNSAFE_componentWillMount () {
@@ -28,7 +31,13 @@
       roleList = []
     }
 
-    this.setState({roleList})
+    let MenuType = ''
+
+    if (window.GLOB.customMenu && window.GLOB.customMenu.parentId === 'BillPrintTemp') {
+      MenuType = 'billPrint'
+    }
+
+    this.setState({roleList, MenuType})
   }
 
   handleConfirm = () => {
@@ -55,7 +64,7 @@
   render() {
     const { wrap, config } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList } = this.state
+    const { roleList, MenuType, appType, cardType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -132,7 +141,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.subtype === 'datacard' ? <Col span={12}>
+            {config.subtype === 'datacard' || (config.subtype === 'tablecard' && appType === 'mob') ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="鏁版嵁婧愪腑閫夋嫨鍒嗛〉鏃舵湁鏁堛��">
                   <Icon type="question-circle" />
@@ -144,7 +153,8 @@
                 })(
                   <Radio.Group>
                     <Radio value="page">椤电爜</Radio>
-                    <Radio value="switch">宸﹀彸鍒囨崲</Radio>
+                    {appType !== 'mob' ? <Radio value="switch">宸﹀彸鍒囨崲</Radio> : null}
+                    {appType === 'mob' ? <Radio value="slide">婊戝姩鍔犺浇</Radio> : null}
                   </Radio.Group>
                 )}
               </Form.Item>
@@ -154,10 +164,22 @@
                 {getFieldDecorator('cardType', {
                   initialValue: wrap.cardType || ''
                 })(
-                  <Radio.Group style={{whiteSpace: 'nowrap'}}>
+                  <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({cardType: e.target.value})}>
                     <Radio key="" value=""> 涓嶅彲閫� </Radio>
                     <Radio key="radio" value={'radio'}> 鍗曢�� </Radio>
                     {config.subtype !== 'propcard' ? <Radio key="checkbox" value={'checkbox'}> 澶氶�� </Radio> : null}
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {config.subtype === 'datacard' && appType === 'mob' && cardType === 'checkbox' ? <Col span={12}>
+              <Form.Item label="鍏ㄩ��">
+                {getFieldDecorator('checkAll', {
+                  initialValue: wrap.checkAll || 'hidden'
+                })(
+                  <Radio.Group>
+                    <Radio key="hidden" value="hidden"> 闅愯棌 </Radio>
+                    <Radio key="show" value="show"> 鏄剧ず </Radio>
                   </Radio.Group>
                 )}
               </Form.Item>
@@ -180,7 +202,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.subtype !== 'tablecard' ? <Col span={12}>
+            {config.subtype !== 'tablecard' && appType !== 'mob' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="榧犳爣鎮诞浜庡崱鐗囦笂鏂规椂锛屽崱鐗囨斁澶�1.05鍊嶃��">
                   <Icon type="question-circle" />
@@ -197,19 +219,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.subtype === 'tablecard' ? <Col span={12}>
-              <Form.Item label={
-                <Tooltip placement="topLeft" title="琛ㄦ牸楂樺害锛岃秴鍑烘椂婊氬姩锛岄珮搴︿负绌烘椂鏍规嵁鍐呭鑷�傚簲銆�">
-                  <Icon type="question-circle" />
-                  楂樺害
-                </Tooltip>
-              }>
-                {getFieldDecorator('height', {
-                  initialValue: wrap.height
-                })(<InputNumber min={100} max={2000} precision={0} onPressEnter={this.handleSubmit} />)}
-              </Form.Item>
-            </Col> : null}
-            {config.subtype === 'propcard' ? <Col span={12}>
+            {config.subtype === 'propcard' && MenuType === 'billPrint' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="閫夋嫨绫诲瀷涓恒�婇〉鐪�/椤佃剼銆嬫椂锛屾墦鍗扮殑姣忛〉閲岄兘浼氬甫鏈夎缁勪欢銆�">
                   <Icon type="question-circle" />
diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx
index 8cac50c..e132a91 100644
--- a/src/menu/components/card/prop-card/index.jsx
+++ b/src/menu/components/card/prop-card/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -33,15 +33,16 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,
     back: false
   }
 
   UNSAFE_componentWillMount () {
     const { card } = this.props
+    const { appType } = this.state
 
     if (card.isNew) {
-      let ismob = sessionStorage.getItem('appType') === 'mob'
       let _card = {
         uuid: card.uuid,
         type: card.type,
@@ -63,7 +64,7 @@
         scripts: [],
         subcards: [{
           uuid: Utils.getuuid(),
-          setting: { width: ismob ? 24 : 6, type: 'simple'},
+          setting: { width: appType === 'mob' ? 24 : 6, type: 'simple'},
           style: {
             borderWidth: '1px', borderColor: '#e8e8e8',
             paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
@@ -195,6 +196,7 @@
    * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
    */
   deleteCard = (cell) => {
+    const { appType } = this.state
     let card = fromJS(this.state.card).toJS()
     let _this = this
 
@@ -202,19 +204,6 @@
       content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
       onOk() {
         card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
-        
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        cell.backElements && cell.backElements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        MKEmitter.emit('delButtons', uuids)
 
         if (card.btnlog) {
           card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
@@ -222,6 +211,25 @@
 
         _this.setState({card})
         _this.props.updateConfig(card)
+
+        if (appType === 'mob') return
+
+        let uuids = []
+
+        cell.elements && cell.elements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+        cell.backElements && cell.backElements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -373,8 +381,10 @@
       }
     }
 
+    let _style = resetStyle(card.style)
+
     return (
-      <div className="menu-prop-card-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-prop-card-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <NormalHeader defaultshow="hidden" config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
diff --git a/src/menu/components/card/table-card/cardcomponent/index.jsx b/src/menu/components/card/table-card/cardcomponent/index.jsx
index e3d9ac7..a46143b 100644
--- a/src/menu/components/card/table-card/cardcomponent/index.jsx
+++ b/src/menu/components/card/table-card/cardcomponent/index.jsx
@@ -8,7 +8,7 @@
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import SettingForm from './settingform'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
@@ -163,10 +163,11 @@
   render() {
     const { cards } = this.props
     const { card, elements, settingVisible, dict } = this.state
+    let _style = resetStyle(card.style)
 
     return (
       <div className="ant-col ant-col-24">
-        <div className="card-item" style={card.style}>
+        <div className="card-item" style={_style}>
           <CardCellComponent cards={cards} cardCell={card} elements={elements} updateElement={this.updateCard}/>
           <div className="card-control">
             <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
@@ -176,6 +177,14 @@
                 <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.setState({settingVisible: true})} />
                 <CopyComponent type="cardcell" card={card}/>
                 <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+                <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+                  <div className="mk-popover-control">
+                    <Icon className="plus" title="鍓嶇Щ" type="arrow-left" onClick={() => this.props.move(card, 'left')} />
+                    <Icon className="close" title="鍚庣Щ" type="arrow-right" onClick={() => this.props.move(card, 'right')} />
+                  </div>
+                } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}>
+                  <Icon type="swap" id={card.uuid + 'swap'}/>
+                </Popover>
                 <Icon className="close" title="鍒犻櫎鍗$墖" type="delete" onClick={() => this.props.deleteElement(card)} />
               </div>
             } trigger="hover">
diff --git a/src/menu/components/card/table-card/cardcomponent/settingform/index.jsx b/src/menu/components/card/table-card/cardcomponent/settingform/index.jsx
index ba0dcf4..c4054ef 100644
--- a/src/menu/components/card/table-card/cardcomponent/settingform/index.jsx
+++ b/src/menu/components/card/table-card/cardcomponent/settingform/index.jsx
@@ -90,6 +90,7 @@
                         {option.label}
                       </Select.Option>
                     )}
+                    <Select.Option key={'index'} value={'$Index'}>搴忓彿锛堝墠绔級</Select.Option>
                   </Select>
                 )}
               </Form.Item>
diff --git a/src/menu/components/card/table-card/index.jsx b/src/menu/components/card/table-card/index.jsx
index cc8ddff..a7d5efe 100644
--- a/src/menu/components/card/table-card/index.jsx
+++ b/src/menu/components/card/table-card/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -15,6 +15,7 @@
 const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
 const WrapComponent = asyncIconComponent(() => import('../data-card/wrapsetting'))
 const CardComponent = asyncComponent(() => import('./cardcomponent'))
+const MobPagination = asyncIconComponent(() => import('@/menu/components/share/mobPagination'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
 const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
@@ -33,6 +34,7 @@
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     card: null,
+    appType: sessionStorage.getItem('appType'),
     back: false
   }
 
@@ -171,6 +173,7 @@
    * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
    */
   deleteCard = (cell) => {
+    const { appType } = this.state
     let card = fromJS(this.state.card).toJS()
     let _this = this
 
@@ -178,15 +181,6 @@
       content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
       onOk() {
         card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
-        
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-
-        MKEmitter.emit('delButtons', uuids)
 
         if (card.btnlog) {
           card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
@@ -194,6 +188,20 @@
 
         _this.setState({card})
         _this.props.updateConfig(card)
+
+        if (appType === 'mob') return
+
+        let uuids = []
+
+        cell.elements && cell.elements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -202,7 +210,7 @@
   changeStyle = () => {
     const { card } = this.state
 
-    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+    MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin'], card.style)
   }
 
   getStyle = (comIds, style) => {
@@ -314,6 +322,26 @@
     }
   }
 
+  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.setState({card})
+    this.props.updateConfig(card)
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -322,15 +350,16 @@
   }
 
   render() {
-    const { card } = this.state
+    const { card, appType } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-table-card-edit-box" style={{...card.style, height: card.wrap.height}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-table-card-edit-box" 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">
             <Icon className="plus" title="娣诲姞鍗$墖" onClick={this.addCard} type="plus" />
-            <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" />
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
             <WrapComponent config={card} updateConfig={this.updateComponent} />
             <CopyComponent type="tablecard" card={card}/>
             <PasteComponent config={card} options={['cardcell', 'search', 'form']} updateConfig={this.updateComponent} />
@@ -343,10 +372,11 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
-        <div style={{minHeight: card.wrap.height - 90}}>
-          {card.subcards.map(subcard => (<CardComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
+        <div style={{minHeight: 'calc(100% - 90px)'}}>
+          {card.subcards.map(subcard => (<CardComponent key={subcard.uuid} cards={card} card={subcard} updateElement={this.updateCard} move={this.move} deleteElement={this.deleteCard}/>))}
         </div>
-        {card.setting.laypage === 'true' ? <Pagination size="small" total={50} /> : null}
+        {card.setting.laypage === 'true' && card.wrap.pagestyle !== 'slide' && appType !== 'mob' ? <Pagination size="small" total={50} /> : null}
+        {card.setting.laypage === 'true' && card.wrap.pagestyle !== 'slide' && appType === 'mob' ? <MobPagination /> : null}
       </div>
     )
   }
diff --git a/src/menu/components/carousel/cardcomponent/index.jsx b/src/menu/components/carousel/cardcomponent/index.jsx
index 5a3909e..1519f58 100644
--- a/src/menu/components/carousel/cardcomponent/index.jsx
+++ b/src/menu/components/carousel/cardcomponent/index.jsx
@@ -8,7 +8,7 @@
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import SettingForm from './settingform'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
@@ -176,6 +176,7 @@
       _style.boxShadow = '0 0 4px ' + _style.shadow
     }
     _style.height = cards.style.height
+    _style = resetStyle(_style)
 
     return (
       <div className="card-item" style={_style} onClick={this.clickComponent} id={card.uuid}>
diff --git a/src/menu/components/carousel/data-card/index.jsx b/src/menu/components/carousel/data-card/index.jsx
index df2cf25..9a3ab4f 100644
--- a/src/menu/components/carousel/data-card/index.jsx
+++ b/src/menu/components/carousel/data-card/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -30,6 +30,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,
     back: false
   }
@@ -163,6 +164,7 @@
    * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
    */
   deleteCard = (cell) => {
+    const { appType } = this.state
     let card = fromJS(this.state.card).toJS()
     let _this = this
 
@@ -171,20 +173,26 @@
       onOk() {
         card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
 
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        MKEmitter.emit('delButtons', uuids)
-
         if (card.btnlog) {
           card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
         }
 
         _this.setState({card})
         _this.props.updateConfig(card)
+
+        if (appType === 'mob') return
+
+        let uuids = []
+
+        cell.elements && cell.elements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -251,9 +259,10 @@
 
   render() {
     const { card } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-data-carousel-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-data-carousel-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <WrapComponent config={card} updateConfig={this.updateComponent}/>
diff --git a/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx
index 0007143..21fec41 100644
--- a/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx
@@ -13,6 +13,7 @@
   }
 
   state = {
+    appType: sessionStorage.getItem('appType'),
     roleList: []
   }
 
@@ -55,7 +56,7 @@
   render() {
     const { wrap, config } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList } = this.state
+    const { roleList, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -161,7 +162,19 @@
                 )}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {appType === 'mob' ? <Col span={12}>
+              <Form.Item label="鍨傜洿鏄剧ず">
+                {getFieldDecorator('vertical', {
+                  initialValue: wrap.vertical || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄�</Radio>
+                    <Radio value="false">鍚�</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label="鎸囩ず鐐逛綅缃�">
                 {getFieldDecorator('dotPosition', {
                   initialValue: wrap.dotPosition || 'bottom'
@@ -174,8 +187,8 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
-            <Col span={12}>
+            </Col> : null}
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label="鍔ㄧ敾鏁堟灉">
                 {getFieldDecorator('effect', {
                   initialValue: wrap.effect || 'scrollx'
@@ -186,7 +199,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label="榛戝悕鍗�">
                 {getFieldDecorator('blacklist', {
diff --git a/src/menu/components/carousel/prop-card/index.jsx b/src/menu/components/carousel/prop-card/index.jsx
index b1f7abf..404d434 100644
--- a/src/menu/components/carousel/prop-card/index.jsx
+++ b/src/menu/components/carousel/prop-card/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -31,6 +31,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,
     back: false
   }
@@ -180,6 +181,7 @@
    * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
    */
   deleteCard = (cell) => {
+    const { appType } = this.state
     let card = fromJS(this.state.card).toJS()
     let _this = this
 
@@ -187,14 +189,6 @@
       content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
       onOk() {
         card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
-        
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        MKEmitter.emit('delButtons', uuids)
 
         if (card.btnlog) {
           card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
@@ -202,6 +196,20 @@
 
         _this.setState({card})
         _this.props.updateConfig(card)
+
+        if (appType === 'mob') return
+
+        let uuids = []
+
+        cell.elements && cell.elements.forEach(c => {
+          if (c.eleType !== 'button' || (appType === 'pc' && c.OpenType !== 'popview')) return
+
+          uuids.push(c.uuid)
+        })
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -328,9 +336,10 @@
 
   render() {
     const { card } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-prop-carousel-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-prop-carousel-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <Icon className="plus" title="娣诲姞鍗$墖" onClick={this.addCard} type="plus" />
diff --git a/src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx b/src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
index 29d0d30..42099ee 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
+++ b/src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
@@ -8,31 +8,34 @@
  * @param {object} card       // 鍥捐〃瀵硅薄
  */
 export function getBaseForm (card) {
-  let isApp = sessionStorage.getItem('appType') === 'pc'
-  let menulist = null
+  // let appType = sessionStorage.getItem('appType')
+  // let menulist = null
 
-  if (isApp) {
-    menulist = sessionStorage.getItem('appMenus')
-  } else {
-    menulist = sessionStorage.getItem('fstMenuList')
-  }
+  // if (appType === 'pc') {
+  //   menulist = sessionStorage.getItem('appMenus')
+  //   if (Array.isArray(card.linkmenu)) {
+  //     card.linkmenu = ''
+  //   }
+  // } else {
+  //   menulist = sessionStorage.getItem('fstMenuList')
+  // }
 
-  if (menulist) {
-    try {
-      menulist = JSON.parse(menulist)
-      if (isApp) {
-        menulist = menulist.map(item => {
-          item.value = item.MenuID
-          item.text = item.MenuName
-          return item
-        })
-      }
-    } catch {
-      menulist = []
-    }
-  } else {
-    menulist = []
-  }
+  // if (menulist) {
+  //   try {
+  //     menulist = JSON.parse(menulist)
+  //     if (appType === 'pc') {
+  //       menulist = menulist.map(item => {
+  //         item.value = item.MenuID
+  //         item.text = item.MenuName
+  //         return item
+  //       })
+  //     }
+  //   } catch {
+  //     menulist = []
+  //   }
+  // } else {
+  //   menulist = []
+  // }
 
   let roleList = sessionStorage.getItem('sysRoles')
   if (roleList) {
@@ -91,38 +94,38 @@
       required: false,
       options: roleList
     },
-    {
-      type: 'cascader',
-      key: 'linkmenu',
-      label: '鍏宠仈鑿滃崟',
-      initVal: card.linkmenu || [],
-      tooltip: '鍦ㄤ娇鐢ㄦ煴褰㈠浘涓旀湭鍚敤鑷畾涔夎缃椂鏈夋晥銆�',
-      required: false,
-      forbid: isApp,
-      options: menulist
-    },
-    {
-      type: 'select',
-      key: 'linkmenu',
-      label: '鍏宠仈鑿滃崟',
-      initVal: card.linkmenu || '',
-      tooltip: '鍙屽嚮楗煎浘锛屼細鎵撳紑鍏宠仈鐨勮彍鍗曘��',
-      required: false,
-      forbid: !isApp,
-      options: menulist
-    },
-    {
-      type: 'radio',
-      key: 'open',
-      label: '鎵撳紑鏂瑰紡',
-      initVal: card.open || 'blank',
-      required: false,
-      forbid: !isApp,
-      options: [
-        { value: 'blank', text: '鏂扮獥鍙�' },
-        { value: 'self', text: '褰撳墠绐楀彛' }
-      ]
-    }
+    // {
+    //   type: 'cascader',
+    //   key: 'linkmenu',
+    //   label: '鍏宠仈鑿滃崟',
+    //   initVal: card.linkmenu || [],
+    //   tooltip: '鍦ㄤ娇鐢ㄦ煴褰㈠浘涓旀湭鍚敤鑷畾涔夎缃椂鏈夋晥銆�',
+    //   required: false,
+    //   forbid: appType === 'pc' || appType === 'mob',
+    //   options: menulist
+    // },
+    // {
+    //   type: 'select',
+    //   key: 'linkmenu',
+    //   label: '鍏宠仈鑿滃崟',
+    //   initVal: card.linkmenu || '',
+    //   tooltip: '鍙屽嚮鏌辩姸鍥撅紝浼氭墦寮�鍏宠仈鐨勮彍鍗曘��',
+    //   required: false,
+    //   forbid: appType !== 'pc',
+    //   options: menulist
+    // },
+    // {
+    //   type: 'radio',
+    //   key: 'open',
+    //   label: '鎵撳紑鏂瑰紡',
+    //   initVal: card.open || 'blank',
+    //   required: false,
+    //   forbid: appType !== 'pc',
+    //   options: [
+    //     { value: 'blank', text: '鏂扮獥鍙�' },
+    //     { value: 'self', text: '褰撳墠绐楀彛' }
+    //   ]
+    // }
   ]
 }
 
@@ -132,6 +135,7 @@
  * @param {Array}  columns    // 鏄剧ず鍒�
  */
 export function getOptionForm (card, columns) {
+  let appType = sessionStorage.getItem('appType')
   let shapes = []
 
   if (card.chartType === 'line') {
@@ -159,28 +163,48 @@
   let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
   let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
 
+  let labelOptions = [{
+    value: 'false',
+    text: '闅愯棌'
+  }, {
+    value: 'true',
+    text: '鏄剧ず'
+  }]
+
+  if (card.chartType === 'bar') {
+    labelOptions[1].text = '澶栭儴'
+    labelOptions.push(...[{
+      value: 'top',
+      text: '椤堕儴'
+    }, {
+      value: 'middle',
+      text: '涓棿'
+    }, {
+      value: 'bottom',
+      text: '搴曢儴'
+    }])
+  }
+
   return [
     {
       type: 'radio',
       key: 'datatype',
       label: '鏁版嵁绫诲瀷',
       initVal: card.datatype || 'query',
-      tooltip: '缁熻鍥捐〃閫傜敤浜庤〃鏍间笉鍒嗛〉锛屼笖鏁版嵁闇�瑕佽浆鎹�',
+      tooltip: '缁熻鍥捐〃閫傜敤浜庡睍绀烘暟鎹被鍨嬩负鍔ㄦ�佸�笺��',
       required: false,
       options: [
         { value: 'query', text: Formdict['header.form.query'] },
         { value: 'statistics', text: Formdict['header.form.statistics'] }
       ]
-    },
-    {
+    }, {
       type: 'select',
       key: 'Xaxis',
       label: 'X-杞�',
       initVal: card.Xaxis || '',
       required: true,
       options: xfields
-    },
-    {
+    }, {
       type: 'select',
       key: 'InfoType',
       label: '绫诲瀷',
@@ -188,8 +212,7 @@
       hidden: card.datatype !== 'statistics',
       required: true,
       options: xfields
-    },
-    {
+    }, {
       type: 'select',
       key: 'InfoValue',
       label: '鍊�',
@@ -197,8 +220,7 @@
       hidden: card.datatype !== 'statistics',
       required: true,
       options: yfields
-    },
-    {
+    }, {
       type: 'select',
       key: 'legend',
       label: '鍥句緥浣嶇疆',
@@ -219,8 +241,7 @@
         { field: 'left-bottom', label: '宸︿笅' },
         { field: 'hidden', label: '闅愯棌' }
       ]
-    },
-    {
+    }, {
       type: 'select',
       key: 'Yaxis',
       label: 'Y-杞�',
@@ -229,16 +250,14 @@
       hidden: card.datatype === 'statistics',
       required: true,
       options: yfields
-    },
-    {
+    }, {
       type: 'select',
       key: 'shape',
       label: '褰㈢姸',
       initVal: card.shape || (shapes[0] && shapes[0].field),
       required: false,
       options: shapes
-    },
-    {
+    }, {
       type: 'radio',
       key: 'tooltip',
       label: '鎮诞鎻愮ず',
@@ -251,8 +270,7 @@
         value: 'false',
         text: '闅愯棌'
       }]
-    },
-    {
+    }, {
       type: 'radio',
       key: 'point',
       label: '鐐瑰浘',
@@ -266,8 +284,7 @@
         value: 'false',
         text: '闅愯棌'
       }]
-    },
-    {
+    }, {
       type: 'radio',
       key: 'transpose',
       label: '鍙樻崲',
@@ -281,8 +298,7 @@
         value: 'false',
         text: Formdict['model.false']
       }]
-    },
-    {
+    }, {
       type: 'radio',
       key: 'show',
       label: '鏍煎紡鍖�',
@@ -295,20 +311,41 @@
         value: 'percent',
         text: '鐧惧垎姣�'
       }]
-    },
-    {
-      type: 'radio',
+    }, {
+      type: labelOptions.length > 20 ? 'select' : 'radio',
       key: 'label',
-      label: '鏍囨敞鍊�',
+      label: '鏍囩',
       initVal: card.label || 'false',
       required: false,
+      options: labelOptions
+    }, {
+      type: 'radio',
+      key: 'labelColor',
+      label: '鏍囩棰滆壊',
+      initVal: card.labelColor || 'system',
+      tooltip: '浣跨敤绯荤粺鑹叉椂锛屼娇鐢ㄨ壊绯婚�夐」璁剧疆鐨勭郴缁熼鑹诧紝浣跨敤鑷畾涔変负棰滆壊璁剧疆涓畾涔夌殑鍥惧舰棰滆壊銆�',
+      required: false,
       options: [{
-        value: 'true',
-        text: '鏄剧ず'
+        value: 'system',
+        text: '绯荤粺'
       }, {
-        value: 'false',
-        text: '闅愯棌'
+        value: 'custom',
+        text: '鑷畾涔�'
       }]
+    // }, {
+    //   type: 'radio',
+    //   key: 'offset',
+    //   label: '鏍囨敞浣嶇疆',
+    //   initVal: card.offset || 'outer',
+    //   required: false,
+    //   options: [{
+    //     value: 'outer',
+    //     text: '澶栭儴'
+    //   }, {
+    //     value: 'inner',
+    //     text: '鍐呴儴'
+    //   }],
+    //   forbid: card.chartType !== 'bar'
     }, {
       type: 'radio',
       key: 'adjust',
@@ -322,6 +359,21 @@
       }, {
         value: 'stack',
         text: '鍫嗗彔'
+      }]
+    }, {
+      type: 'radio',
+      key: 'area',
+      label: '闈㈢Н鍥�',
+      initVal: card.area || 'false',
+      // tooltip: '浠呭湪褰㈢姸涓簊mooth鏃舵湁鏁堛��',
+      required: false,
+      forbid: ['bar'].includes(card.chartType),
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '涓嶆樉绀�'
       }]
     }, {
       type: 'radio',
@@ -353,16 +405,32 @@
         text: '鏋佸潗鏍�'
       }]
     }, {
-      type: 'number',
-      key: 'InfoDefNumber',
-      label: '灞曠ず鏁�',
-      tooltip: '榛樿鏄剧ず绫诲瀷鏁伴噺',
-      min: 1,
-      max: 50,
-      decimal: 0,
-      initVal: card.InfoDefNumber || 5,
-      hidden: card.datatype !== 'statistics',
-      required: true
+      type: 'radio',
+      key: 'grid',
+      label: '缃戞牸绾�',
+      initVal: card.grid || 'show',
+      required: false,
+      options: [{
+        value: 'show',
+        text: '鏄剧ず'
+      }, {
+        value: 'hidden',
+        text: '闅愯棌'
+      }]
+    }, {
+      type: 'radio',
+      key: 'y_line',
+      label: 'y杞磋竟绾�',
+      initVal: card.y_line || 'hidden',
+      tooltip: '鍥惧舰宸︿晶鎴栧彸渚х殑杈圭嚎銆�',
+      required: false,
+      options: [{
+        value: 'show',
+        text: '鏄剧ず'
+      }, {
+        value: 'hidden',
+        text: '闅愯棌'
+      }]
     }, {
       type: 'number',
       key: 'barSize',
@@ -375,19 +443,87 @@
       forbid: !['bar'].includes(card.chartType),
       required: false
     }, {
+      type: 'number',
+      key: 'barRadius',
+      label: '鏌卞舰鍦嗚',
+      tooltip: '鏌卞舰鍥句笂绔渾瑙掋��',
+      min: 0,
+      max: 200,
+      decimal: 0,
+      initVal: card.barRadius || 0,
+      forbid: !['bar'].includes(card.chartType),
+      required: false
+    }, {
+      type: 'number',
+      key: 'min',
+      label: '鏈�灏忓��',
+      tooltip: 'y杞存渶灏忓�硷紝涓虹┖鏃惰嚜閫傚簲銆�',
+      initVal: card.min,
+      required: false
+    }, {
+      type: 'number',
+      key: 'max',
+      label: '鏈�澶у��',
+      tooltip: 'y杞存渶澶у�硷紝涓虹┖鏃惰嚜閫傚簲銆�',
+      initVal: card.max,
+      required: false
+    }, {
       type: 'color',
       key: 'color',
       label: '鑹茬郴',
-      initVal: card.color || 'rgba(0, 0, 0, 0.85)',
-      tooltip: '鍧愭爣杞村強绀轰緥绛夋彁绀烘枃瀛椾娇鐢ㄧ殑棰滆壊銆�',
+      initVal: card.color || 'rgba(0, 0, 0, 0.65)',
+      tooltip: '鍧愭爣杞存彁绀烘枃瀛楀強绀轰緥鐨勯鑹层��',
+      required: false
+    }, {
+      type: 'color',
+      key: 'lineColor',
+      label: '杞寸嚎棰滆壊',
+      initVal: card.lineColor,
+      tooltip: '鍧愭爣杞寸嚎鐨勯鑹诧紝鍖呮嫭x杞淬�亂杞村強缃戞牸绾裤��',
+      allowClear: true,
+      required: false
+    }, {
+      type: 'color',
+      key: 'selectColor',
+      label: '閫変腑棰滆壊',
+      initVal: card.selectColor || '',
+      tooltip: '閫変腑鏌卞舰鍥剧殑棰滆壊锛屽湪浜や簰鏁堟灉銆婂厓绱犻�変腑锛堝閫夛級銆嬪拰銆婂厓绱犻�変腑锛堝崟閫夛級銆嬩腑鏈夋晥锛岃嚜瀹氫箟璁剧疆涓棤鏁堛��',
+      forbid: !['bar'].includes(card.chartType),
+      allowClear: true,
+      required: false
+    }, {
+      type: 'number',
+      key: 'rotate',
+      label: '鏃嬭浆',
+      tooltip: '鍧愭爣杞存爣娉ㄦ枃鏈殑鏃嬭浆瑙掑害銆�',
+      min: 0,
+      max: 360,
+      decimal: 0,
+      initVal: card.rotate,
+      forbid: appType !== 'mob',
+      required: false
+    }, {
+      type: 'select',
+      key: 'interaction',
+      label: '浜や簰鏁堟灉',
+      initVal: card.interaction || [],
+      multi: true,
       required: false,
-      options: [{
-        value: 'black',
-        text: '榛戣壊'
-      }, {
-        value: 'white',
-        text: '鐧借壊'
-      }]
+      forbid: appType === 'mob',
+      options: [
+        { value: 'element-active', label: '鍏冪礌鑱氱劍' },
+        { value: 'element-selected', label: '鍏冪礌閫変腑锛堝閫夛級' },
+        { value: 'element-single-selected', label: '鍏冪礌閫変腑锛堝崟閫夛級' },
+        { value: 'active-region', label: '鑳屾櫙妗�' },
+        { value: 'view-zoom', label: '瑙嗗浘缂╂斁' },
+        { value: 'element-highlight', label: '鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-color', label: '鍚岃壊鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-x', label: '鍚孹杞村厓绱犻珮浜�' },
+        { value: 'legend-filter', label: '鍥句緥杩囨护' },
+        { value: 'legend-active', label: '鍥句緥鑱氱劍' },
+        { value: 'legend-highlight', label: '鍥句緥楂樹寒' },
+        { value: 'brush', label: '閫夋杩囨护' },
+      ]
     }
   ]
 }
diff --git a/src/menu/components/chart/antv-bar/chartcompile/index.jsx b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
index db034f3..3f31823 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-bar/chartcompile/index.jsx
@@ -24,6 +24,7 @@
 
   state = {
     view: 'normal',
+    ramp: 'false',
     visible: false,
     datatype: '',
     plot: null,
@@ -48,6 +49,34 @@
         }
       },
     ],
+    rampColorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'label',
+        editable: false,
+        width: '20%'
+      },
+      {
+        title: '棰滆壊1',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+      {
+        title: '棰滆壊2',
+        dataIndex: 'color1',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
     statColorColumns: [
       {
         title: '鎸囨爣',
@@ -67,19 +96,48 @@
         }
       },
     ],
+    rampStatColorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'type',
+        inputType: 'input',
+        editable: true,
+        width: '20%'
+      },
+      {
+        title: '棰滆壊1',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+      {
+        title: '棰滆壊2',
+        dataIndex: 'color1',
+        inputType: 'color',
+        editable: true,
+        width: '30%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ],
     cusColumns: [
       {
         title: '鎸囨爣',
         dataIndex: 'name',
         editable: false,
-        width: '20%'
+        width: '14%'
       },
       {
         title: '褰㈢姸',
         dataIndex: 'shape',
         inputType: 'cascader',
         editable: true,
-        width: '20%',
+        width: '12%',
         render: (text, record) => {
           return text.join(' / ').replace('line', '鎶樼嚎').replace('bar', '鏌卞舰')
         },
@@ -117,7 +175,7 @@
         dataIndex: 'axis',
         inputType: 'select',
         editable: true,
-        width: '20%',
+        width: '12%',
         options: [
           { value: 'true', text: '鏄剧ず'},
           { value: 'false', text: '闅愯棌'}
@@ -132,7 +190,7 @@
         dataIndex: 'label',
         inputType: 'select',
         editable: true,
-        width: '20%',
+        width: '12%',
         options: [
           { value: 'true', text: '鏄剧ず'},
           { value: 'false', text: '闅愯棌'}
@@ -141,6 +199,37 @@
           let trans = {'true': '鏄剧ず', 'false': '闅愯棌'}
           return trans[text] || '闅愯棌'
         }
+      },
+      {
+        title: '鏍囬',
+        dataIndex: 'title',
+        inputType: 'select',
+        editable: true,
+        width: '12%',
+        options: [
+          { value: 'true', text: '鏄剧ず'},
+          { value: 'false', text: '闅愯棌'}
+        ],
+        render: (text, record) => {
+          let trans = {'true': '鏄剧ず', 'false': '闅愯棌'}
+          return trans[text] || '鏄剧ず'
+        }
+      },
+      {
+        title: '鏈�灏忓��',
+        dataIndex: 'min',
+        inputType: 'number',
+        editable: true,
+        required: false,
+        width: '12%'
+      },
+      {
+        title: '鏈�澶у��',
+        dataIndex: 'max',
+        inputType: 'number',
+        editable: true,
+        required: false,
+        width: '12%'
       },
     ]
   }
@@ -163,6 +252,7 @@
     this.setState({
       visible: true,
       view: 'normal',
+      ramp: config.plot.ramp || 'false',
       datatype: config.plot.datatype || 'query',
       fieldName: fieldName,
       plot: fromJS(config.plot).toJS(),
@@ -181,7 +271,7 @@
         formlist: formlist.map(item => {
           if (['Yaxis'].includes(item.key)) {
             item.hidden = val === 'statistics'
-          } else if (['InfoType', 'InfoValue', 'InfoDefNumber'].includes(item.key)) {
+          } else if (['InfoType', 'InfoValue'].includes(item.key)) {
             item.hidden = val !== 'statistics'
           }
           return item
@@ -291,7 +381,7 @@
                   }
                 ]
               })(
-                <Radio.Group disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
+                <Radio.Group style={{whiteSpace: 'nowrap'}} disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
                   {item.options.map(option => {
                     return (
                       <Radio key={option.value} value={option.value}>{option.text}</Radio>
@@ -314,7 +404,7 @@
               {getFieldDecorator(item.key, {
                 initialValue: item.initVal
               })(
-                <ColorSketch />
+                <ColorSketch allowClear={item.allowClear} />
               )}
             </Form.Item>
           </Col>
@@ -329,6 +419,35 @@
     let val = e.target.value
 
     this.setState({plot: {...plot, enabled: val}})
+  }
+
+  mutilBarChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+
+    this.setState({plot: {...plot, mutilBar: val}})
+  }
+
+  rampChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+    let colors = plot.colors || []
+
+    if (val === 'true') {
+      colors = colors.map(item => {
+        item.color1 = item.color1 || item.color
+        return item
+      })
+    }
+
+    this.setState({plot: {...plot, colors, ramp: val}, ramp: val})
+  }
+
+  rampDirectionChange = (e) => {
+    const { plot } = this.state
+    let val = e.target.value
+
+    this.setState({plot: {...plot, rampDirection: val}})
   }
 
   onSubmit = () => {
@@ -411,6 +530,7 @@
                 name: labels[item] || item,
                 axis: i === 0 ? 'true' : 'false',
                 label: 'false',
+                title: 'true',
                 shape: _plot.chartType === 'bar' && i === 0 ? ['bar', 'rect'] : ['line', 'smooth']
               }
             })
@@ -425,7 +545,8 @@
                   uuid: Utils.getuuid(),
                   type: item,
                   label: labels[item] || item,
-                  color: chartColors[i % limit]
+                  color: chartColors[i % limit],
+                  color1: chartColors[i % limit]
                 }
               })
             }
@@ -459,7 +580,8 @@
     plot.colors.push({
       uuid: Utils.getuuid(),
       type: `鎸囨爣${plot.colors.length}`,
-      color: 'rgb(91, 143, 249)'
+      color: 'rgb(91, 143, 249)',
+      color1: 'rgb(91, 143, 249)'
     })
 
     this.setState({plot})
@@ -478,7 +600,7 @@
   }
 
   render() {
-    const { view, visible, datatype, plot, colorColumns, statColorColumns, cusColumns, baseFormlist } = this.state
+    const { view, visible, datatype, plot, ramp, colorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -497,7 +619,7 @@
           wrapClassName="popview-modal menu-chart-edit-modal"
           title="鍥捐〃缂栬緫"
           visible={visible}
-          width={850}
+          width={950}
           maskClosable={false}
           onOk={this.onSubmit}
           onCancel={() => { this.setState({ visible: false }) }}
@@ -514,9 +636,29 @@
             </TabPane>
             {plot ? <TabPane tab="棰滆壊璁剧疆" key="color">
               <div>
+                <Col span={8} style={{height: '40px', top: '-5px', zIndex: 1}}>
+                  <Form {...formItemLayout}>
+                    <Form.Item label="娓愬彉鑹�" style={{marginBottom: 10}}>
+                      <Radio.Group value={plot.ramp || 'false'} onChange={this.rampChange}>
+                        <Radio value="false">涓嶄娇鐢�</Radio>
+                        <Radio value="true">浣跨敤</Radio>
+                      </Radio.Group>
+                    </Form.Item>
+                  </Form>
+                </Col>
+                {plot.chartType === 'line' ? <Col span={8} style={{height: '40px', top: '-5px', zIndex: 1}}>
+                  <Form {...formItemLayout}>
+                    <Form.Item label="娓愬彉鏂瑰悜" style={{marginBottom: 10}}>
+                      <Radio.Group value={plot.rampDirection || 'horizontal'} onChange={this.rampDirectionChange}>
+                        <Radio value="horizontal">姘村钩</Radio>
+                        <Radio value="vertical">鍨傜洿</Radio>
+                      </Radio.Group>
+                    </Form.Item>
+                  </Form>
+                </Col> : null}
                 {datatype === 'statistics' ? <Button className="color-add mk-green" onClick={this.addColor}>{this.props.dict['model.add']}</Button> : null}
-                {datatype === 'statistics' ? <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={statColorColumns} onChange={this.changeColor}/> : null}
-                {datatype !== 'statistics' ? <EditTable actions={['edit']} data={plot.colors || []} columns={colorColumns} onChange={this.changeColor}/> : 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}
               </div>
             </TabPane> : null}
             {plot ? <TabPane tab="鑷畾涔夎缃�" disabled={datatype === 'statistics'} key="custom">
@@ -530,7 +672,18 @@
                   </Form.Item>
                 </Form>
               </Col>
-              <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>娉細浣跨敤鑷畾涔夎缃椂锛屾樉绀虹殑鍧愭爣杞寸涓�涓湪宸︿晶锛岀浜屼釜鍦ㄥ彸渚э紝澶氫綑鐨勪笉鐢熸晥锛涙煴褰㈠浘鍙彲浠ユ坊鍔犱竴涓紙璁剧疆澶氫釜鏃讹紝绗竴涓敓鏁堬級銆�</Col>
+              <Col span={12}>
+                <Form {...formItemLayout}>
+                  <Form.Item label="澶氭煴鎺掑垪" style={{marginBottom: 10}}>
+                    <Radio.Group value={plot.mutilBar || 'dodge'} onChange={this.mutilBarChange}>
+                      <Radio value="dodge">鍒嗙粍</Radio>
+                      <Radio value="stack">鍫嗗彔</Radio>
+                      <Radio value="overlap">閲嶅彔</Radio>
+                    </Radio.Group>
+                  </Form.Item>
+                </Form>
+              </Col>
+              <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>娉細浣跨敤鑷畾涔夎缃椂锛屾樉绀虹殑鍧愭爣杞寸涓�涓湪宸︿晶锛岀浜屼釜鍦ㄥ彸渚э紝澶氫綑鐨勪笉鐢熸晥銆�</Col>
               <EditTable actions={['edit', 'move']} data={plot.customs || []} columns={cusColumns} onChange={this.changeCustom}/>
             </TabPane> : null}
           </Tabs>
diff --git a/src/menu/components/chart/antv-bar/chartcompile/index.scss b/src/menu/components/chart/antv-bar/chartcompile/index.scss
index 5928db8..244c6aa 100644
--- a/src/menu/components/chart/antv-bar/chartcompile/index.scss
+++ b/src/menu/components/chart/antv-bar/chartcompile/index.scss
@@ -20,6 +20,9 @@
         .ant-input-number {
           width: 100%;
         }
+        .ant-radio-wrapper {
+          margin-right: 5px;
+        }
         .ant-tabs-nav-wrap {
           text-align: center;
         }
diff --git a/src/menu/components/chart/antv-bar/index.jsx b/src/menu/components/chart/antv-bar/index.jsx
index 40cfcf1..19cd40e 100644
--- a/src/menu/components/chart/antv-bar/index.jsx
+++ b/src/menu/components/chart/antv-bar/index.jsx
@@ -8,7 +8,7 @@
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import { chartColors } from '@/utils/option.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -35,6 +35,7 @@
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     card: null,
+    appType: sessionStorage.getItem('appType'),
     eventListener: null
   }
 
@@ -50,6 +51,7 @@
         width: card.width || 24,
         height: 400,
         barSize: 35,
+        color: 'rgba(0, 0, 0, 0.65)',
         name: card.name
       }
 
@@ -73,7 +75,7 @@
         parentId: card.parentId || '',
         format: 'array',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
         pageable: false,   // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
-        switchable: false, // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        switchable: card.type === 'bar' ? true : false, // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
         dataName: card.dataName || '',
         width: _plot.width,
         name: _plot.name,
@@ -121,9 +123,11 @@
   }
 
   componentDidMount () {
-    this.viewrender()
     MKEmitter.addListener('submitStyle', this.getStyle)
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    setTimeout(() => {
+      this.viewrender()
+    }, 1000)
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -150,7 +154,8 @@
         _element.innerHTML = ''
       }
 
-      setTimeout(this.viewrender, 100)
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(this.viewrender, 100)
     }
   }
 
@@ -193,10 +198,14 @@
    */
   linerender = () => {
     const { card } = this.state
-    let plot = {...card.plot, height: card.plot.height - 80} // 鍘婚櫎title鎵�鍗犵┖闂�
-    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
+    let plot = {...card.plot} // 鍘婚櫎title鎵�鍗犵┖闂�
+    let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || ['y']
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     let data = this.getdata(X_axis, Y_axis)
 
@@ -235,8 +244,29 @@
   
       chart.data(dv.rows)
 
-      chart.axis(X_axis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
-      chart.axis('value', { grid: { style: { fill: color } }, label: { style: { fill: color } } })
+      // chart.axis(X_axis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
+      // chart.axis('value', { grid: { line: { style: { stroke: color } }}, label: { style: { fill: color } } })
+
+      let xc = {label: { style: { fill: color } }}
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        xc.tickLine = {style: { stroke: plot.lineColor }}
+        xc.line = { style: { stroke: plot.lineColor } }
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      chart.axis(X_axis, xc)
+      chart.axis('value', yc)
   
       if (plot.coordinate !== 'polar') {
         chart.scale(X_axis, {
@@ -245,7 +275,7 @@
       }
       chart.scale('value', {
         nice: true,
-        range: [0, 0.93]
+        range: [0, 0.9]
       })
   
       if (!plot.legend || plot.legend === 'hidden') {
@@ -280,11 +310,23 @@
       let colorIndex = 0
 
       if (plot.colors && plot.colors.length > 0) {
-        plot.colors.forEach(item => {
-          if (!colors.has(transfield[item.type])) {
-            colors.set(transfield[item.type], item.color)
+        if (plot.ramp === 'true') {
+          let _s = 'l(0) '
+          if (plot.rampDirection === 'vertical') {
+            _s = 'l(90) '
           }
-        })
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], `${_s}0:${item.color} 1:${item.color1}` )
+            }
+          })
+        } else {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], item.color)
+            }
+          })
+        }
       }
   
       let _chart = chart
@@ -304,25 +346,33 @@
       if (plot.colors && plot.colors.length > 0) {
         let limit = chartColors.length
         _chart.color('key', (key) => {
-          if (colors.get(key)) {
+          if (colors.has(key)) {
+            if (plot.area === 'true' && plot.rampDirection === 'vertical') {
+              return colors.get(key).replace(/l\(9?0\) 0:|\s1:.*/ig, '')
+            }
             return colors.get(key)
           } else {
-            colors.set(key, chartColors[colorIndex % limit])
             colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
           }
         })
       } else {
         _chart.color('key')
       }
-      if (plot.label === 'true') {
-        _chart.label('value', (value) => {
+      if (plot.label !== 'false') {
+        _chart.label('value*key', (value, key) => {
           if (plot.show === 'percent') {
             value = value + '%'
+          }
+          let _color = color
+
+          if (plot.labelColor === 'custom' && colors.has(key)) {
+            _color = colors.get(key)
           }
           return {
             content: value,
             style: {
-              fill: color
+              fill: _color
             }
           }
         })
@@ -336,6 +386,32 @@
           .size(3)
           .shape('circle')
       }
+
+      if (plot.area === 'true') {
+        let area = chart.area().position(`${X_axis}*value`).tooltip(false)
+        if (plot.shape === 'smooth') {
+          area.shape('smooth')
+        }
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          area.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          area.color('key')
+        }
+      }
+
+      if (plot.interaction && plot.interaction.length) {
+        plot.interaction.forEach(t => {
+          chart.interaction(t)
+        })
+      }
       chart.render()
     } else {
       this.customrender(data)
@@ -347,11 +423,16 @@
    */
   customrender = (data) => {
     let card = fromJS(this.state.card).toJS()
-    let plot = {...card.plot, height: card.plot.height - 80} // 鍘婚櫎title鎵�鍗犵┖闂�
-    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
+    let plot = {...card.plot} // 鍘婚櫎title鎵�鍗犵┖闂�
+    let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let fields = []
     let legends = []
     let transfield = {}
+    let Bar_axis = []
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     card.columns.forEach(col => {
       if (col.field) {
@@ -364,41 +445,90 @@
     let limit = chartColors.length
 
     if (plot.colors && plot.colors.length > 0) {
-      plot.colors.forEach(item => {
-        if (!colors.has(item.type)) {
-          colors.set(item.type, item.color)
-        }
-      })
+      if (plot.ramp === 'true') {
+        let bars = {}
+        plot.customs.forEach(item => {
+          if (!item.shape || !item.shape[0] || item.shape[0] === 'bar') {
+            bars[item.type] = true
+          }
+        })
+        plot.colors.forEach(item => {
+          if (!colors.has(transfield[item.type])) {
+            if (bars[item.type]) {
+              colors.set(transfield[item.type], `l(90) 0:${item.color} 1:${item.color1}` )
+            } else {
+              colors.set(transfield[item.type], `l(0) 0:${item.color} 1:${item.color1}` )
+            }
+          }
+        })
+      } else {
+        plot.colors.forEach(item => {
+          if (!colors.has(transfield[item.type])) {
+            colors.set(transfield[item.type], item.color)
+          }
+        })
+      }
     }
 
     let axisIndex = 0
     let hasBar = false
+
+    plot.$paddingLeft = 30
+    plot.$paddingRight = 30
 
     plot.customs.forEach(item => {
       item.name = transfield[item.type] || item.type
       item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
       item.shape = item.shape ? (item.shape[1] || '') : ''
 
-      if (colors.get(item.type)) {
-        item.color = colors.get(item.type)
+      if (colors.has(item.name)) {
+        item.color = colors.get(item.name)
       } else {
         item.color = chartColors[colorIndex % limit]
         colorIndex++
       }
 
-      if (item.chartType === 'bar' && !hasBar) {
+      if (item.chartType === 'bar') {
+        Bar_axis.push(item.type)
         hasBar = true
-      } else if (item.chartType === 'bar') {
-        item.chartType = 'line'
-        item.shape = 'smooth'
       }
 
       if (item.axis === 'true' && axisIndex < 2) {
         if (axisIndex === 0) {
-          item.axis = { grid: {style: { fill: color }}, title: { style: { fill: color } }, label: {style: { fill: color }} }
+          // item.axis = { grid: {line: { style: { stroke: color } }}, title: { style: { fill: color } }, label: {style: { fill: color }} }
+          item.axis = { label: {style: { fill: color }} }
+          if (item.title !== 'false') {
+            item.axis.title = { style: { fill: color } }
+            plot.$paddingLeft = 50
+          }
+          if (plot.grid === 'hidden') {
+            item.axis.grid = null
+          }
+          if (plot.y_line === 'show') {
+            item.axis.line = {style: { stroke: '#D1D2CE' }}
+          }
+          if (plot.lineColor) {
+            if (item.axis.grid !== null) {
+              item.axis.grid = { line: { style: { stroke: plot.lineColor } }}
+            }
+            if (item.axis.line) {
+              item.axis.line = { style: { stroke: plot.lineColor } }
+            }
+          }
+          
           fields.unshift(item)
         } else {
-          item.axis = { grid: null, title: {style: { fill: color }}, label: {style: { fill: color }} }
+          item.axis = { grid: null, label: {style: { fill: color }} }
+          if (item.title !== 'false') {
+            item.axis.title = { style: { fill: color } }
+            plot.$paddingRight = 60
+          }
+          if (plot.y_line === 'show') {
+            item.axis.line = {style: { stroke: '#D1D2CE' }}
+          }
+          if (plot.lineColor && item.axis.line) {
+            item.axis.line = { style: { stroke: plot.lineColor } }
+          }
           fields.splice(1, 0, item)
         }
         axisIndex++
@@ -426,15 +556,29 @@
       }
     })
 
+    let padding = [10, 30, 30, 30]
+    if (plot.mutilBar === 'overlap') {
+      Bar_axis = []
+    }
+
+    if (!Bar_axis.length) {
+      padding = [10, plot.$paddingRight, 30, plot.$paddingLeft]
+    }
+
     const chart = new Chart({
       container: card.uuid + 'canvas',
       autoFit: true,
-      height: plot.height || 400
+      height: plot.height || 400,
     })
 
-    chart.data(dv.rows)
+    // chart.axis(plot.Xaxis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
 
-    chart.axis(plot.Xaxis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
+    let xc = {label: { style: { fill: color } }}
+    if (plot.lineColor) {
+      xc.tickLine = {style: { stroke: plot.lineColor }}
+      xc.line = { style: { stroke: plot.lineColor } }
+    }
+    chart.axis(plot.Xaxis, xc)
 
     if (!hasBar) {
       chart.scale(plot.Xaxis, {
@@ -465,16 +609,211 @@
       nice: true
     })
 
-    fields.forEach(item => {
-      chart.axis(item.name, item.axis)
-      
-      chart.scale(item.name, {
-        nice: true,
-        range: [0, 0.93]
+    let lablecfg = {
+      position: 'top',
+      offset: 2,
+      style: {
+        fill: '#fff'
+      }
+    }
+
+    if (plot.label === 'top') {
+      lablecfg.offset = -5
+      lablecfg.style.textBaseline = 'top'
+    } else if (plot.label === 'middle') {
+      lablecfg.position = 'middle'
+      lablecfg.offset = 0
+    } else if (plot.label === 'bottom') {
+      lablecfg.position = 'bottom'
+      lablecfg.offset = 0
+    } else if (plot.label === 'true') {
+      lablecfg.style.fill = color
+    }
+    
+    if (Bar_axis.length) {
+      const view1 = chart.createView({
+        region: {
+          start: { x: 0, y: 0 },
+          end: { x: 1, y: 1 }
+        },
+        padding
+      })
+      const dst = new DataSet()
+      const dvt = dst.createView().source(data)
+  
+      dvt.transform({
+        type: 'fold',
+        fields: [...Bar_axis],
+        key: 'key',
+        value: 'value'
+      })
+  
+      dvt.transform({
+        type: 'map',
+        callback(row) {
+          row.key = transfield[row.key] || row.key
+          return row
+        },
       })
 
-      if (item.chartType === 'bar') {
-        let _chart = chart
+      view1.data(dvt.rows)
+      view1.scale('value', {
+        nice: true,
+        range: [0, 0.9]
+      })
+
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      view1.axis('value', yc)
+  
+      view1.legend(false)
+  
+      if (plot.mutilBar !== 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust([
+            {
+              type: 'dodge',
+              marginRatio: 0
+            }
+          ])
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: key,
+              value: value
+            }
+          })
+
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      } else if (plot.mutilBar === 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust('stack')
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, type) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: type,
+              value: value
+            }
+          })
+  
+        if (plot.colors && plot.colors.length > 0) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (colors.has(key)) {
+              return colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      }
+    }
+
+    const view2 = chart.createView({
+      region: {
+        start: { x: 0, y: 0 },
+        end: { x: 1, y: 1 }
+      },
+      padding
+    })
+
+    view2.data(dv.rows)
+
+    view2.legend(false)
+
+    fields.forEach(item => {
+      if (item.chartType === 'bar' && !Bar_axis.length) {
+        view2.axis(item.name, item.axis)
+      
+        view2.scale(item.name, {
+          nice: true,
+          range: [0, 0.9]
+        })
+
+        let _chart = view2
           .interval()
           .position(`${plot.Xaxis}*${item.name}`)
           .color(item.color)
@@ -492,21 +831,35 @@
         if (plot.barSize) {
           _chart.size(plot.barSize || 35)
         }
-        if (item.label === 'true') {
+        if (item.label !== 'false') {
           _chart.label(item.name, (value) => {
             if (plot.show === 'percent') {
               value = value + '%'
             }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom') {
+              lablecfg.style.fill = item.color
+            }
             return {
               content: value,
-              style: {
-                fill: color
-              }
+              ...lablecfg
             }
           })
         }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
       } else if (item.chartType === 'line') {
-        let _chart = chart
+        if (!Bar_axis.length) {
+          view2.axis(item.name, item.axis)
+        } else {
+          view2.axis(item.name, { grid: null, title: null, label: null })
+        }
+        view2.scale(item.name, {
+          nice: true,
+          range: [0, 0.9]
+        })
+        let _chart = view2
           .line()
           .position(`${plot.Xaxis}*${item.name}`)
           .color(item.color)
@@ -521,15 +874,20 @@
             }
           })
 
-        if (item.label === 'true') {
+        if (item.label !== 'false') {
           _chart.label(item.name, (value) => {
             if (plot.show === 'percent') {
               value = value + '%'
             }
+            let _color = color
+
+            if (plot.labelColor === 'custom') {
+              _color = item.color
+            }
             return {
               content: value,
               style: {
-                fill: color
+                fill: _color
               }
             }
           })
@@ -546,6 +904,14 @@
       }
     })
 
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        if (t === 'element-active' || t === 'element-highlight') {
+          chart.interaction(t)
+        }
+      })
+    }
+
     chart.render()
   }
 
@@ -554,10 +920,14 @@
    */
   barrender = () => {
     const { card } = this.state
-    let plot = {...card.plot, height: card.plot.height - 80}
-    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
+    let plot = {...card.plot}
+    let color = plot.color || 'rgba(0, 0, 0, 0.65)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || ['y']
+
+    if (card.plot.title || card.search.length > 0) {
+      plot.height = card.plot.height - 70
+    }
 
     let data = this.getdata(X_axis, Y_axis)
     
@@ -594,15 +964,36 @@
         autoFit: true,
         height: plot.height || 400
       })
-  
+
       chart.data(dv.rows)
 
-      chart.axis(X_axis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
-      chart.axis('value', { grid: { style: { fill: color } }, label: { style: { fill: color } } })
+      // chart.axis(X_axis, { label: { style: { fill: color } }, tickLine: {style: { stroke: color }}, line: { style: { stroke: color } } })
+      // chart.axis('value', { grid: { line: { style: { stroke: color } }}, label: { style: { fill: color } } })
+
+      let xc = {label: { style: { fill: color } }}
+      let yc = {label: { style: { fill: color } }}
+      if (plot.grid === 'hidden') {
+        yc.grid = null
+      }
+      if (plot.y_line === 'show') {
+        yc.line = {style: { stroke: '#D1D2CE' }}
+      }
+      if (plot.lineColor) {
+        xc.tickLine = {style: { stroke: plot.lineColor }}
+        xc.line = { style: { stroke: plot.lineColor } }
+        if (yc.grid !== null) {
+          yc.grid = { line: { style: { stroke: plot.lineColor } }}
+        }
+        if (yc.line) {
+          yc.line = { style: { stroke: plot.lineColor } }
+        }
+      }
+      chart.axis(X_axis, xc)
+      chart.axis('value', yc)
   
       chart.scale('value', {
         nice: true,
-        range: [0, 0.93]
+        range: [0, 0.9]
       })
   
       if (!plot.legend || plot.legend === 'hidden') {
@@ -622,10 +1013,6 @@
         })
       }
   
-      if (plot.transpose === 'true') {
-        chart.coordinate().transpose()
-      }
-  
       if (plot.coordinate === 'polar') {
         chart.coordinate('polar', {
           innerRadius: 0.1,
@@ -635,13 +1022,60 @@
 
       let colors = new Map()
       let colorIndex = 0
+      let lablecfg = {
+        position: 'top',
+        offset: 2,
+        style: {
+          fill: '#fff'
+        }
+      }
+
+      if (plot.label === 'top') {
+        lablecfg.offset = -5
+        lablecfg.style.textBaseline = 'top'
+      } else if (plot.label === 'middle') {
+        lablecfg.position = 'middle'
+        lablecfg.offset = 0
+      } else if (plot.label === 'bottom') {
+        lablecfg.position = 'bottom'
+        lablecfg.offset = 0
+      } else if (plot.label === 'true') {
+        lablecfg.style.fill = color
+      }
+
+      if (plot.transpose === 'true') {
+        chart.coordinate().transpose()
+        if (plot.label === 'top') {
+          delete lablecfg.style.textBaseline
+          lablecfg.position = 'right'
+          lablecfg.offset = -3
+          lablecfg.style.textAlign = 'end'
+        } else if (plot.label === 'middle') {
+          lablecfg.position = 'middle'
+          lablecfg.offset = 0
+        } else if (plot.label === 'bottom') {
+          lablecfg.position = 'left'
+          lablecfg.offset = 2
+        } else if (plot.label === 'true') {
+          lablecfg.position = 'right'
+          lablecfg.offset = 2
+        }
+      }
 
       if (plot.colors && plot.colors.length > 0) {
-        plot.colors.forEach(item => {
-          if (!colors.has(transfield[item.type])) {
-            colors.set(transfield[item.type], item.color)
-          }
-        })
+        if (plot.ramp === 'true') {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], `l(90) 0:${item.color} 1:${item.color1}` )
+            }
+          })
+        } else {
+          plot.colors.forEach(item => {
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], item.color)
+            }
+          })
+        }
       }
   
       if (plot.adjust !== 'stack') {
@@ -668,32 +1102,47 @@
         if (plot.colors && plot.colors.length > 0) {
           let limit = chartColors.length
           _chart.color('key', (key) => {
-            if (colors.get(key)) {
+            if (colors.has(key)) {
               return colors.get(key)
             } else {
-              colors.set(key, chartColors[colorIndex % limit])
               colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
             }
           })
         } else {
           _chart.color('key')
         }
-        if (plot.label === 'true') {
-          _chart.label('value', (value) => {
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
             if (plot.show === 'percent') {
               value = value + '%'
             }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
+            
             return {
               content: value,
-              style: {
-                fill: color
-              }
+              ...lablecfg
             }
           })
         }
 
         if (plot.barSize || plot.correction) {
           _chart.size(plot.barSize || 35)
+        }
+        if (plot.selectColor) {
+          _chart.state({
+            selected: {
+              style: {
+                fill: plot.selectColor,
+              }
+            }
+          })
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
         }
       } else if (plot.adjust === 'stack') {
         let _chart = chart
@@ -714,26 +1163,28 @@
         if (plot.colors && plot.colors.length > 0) {
           let limit = chartColors.length
           _chart.color('key', (key) => {
-            if (colors.get(key)) {
+            if (colors.has(key)) {
               return colors.get(key)
             } else {
-              colors.set(key, chartColors[colorIndex % limit])
               colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
             }
           })
         } else {
           _chart.color('key')
         }
-        if (plot.label === 'true') {
-          _chart.label('value', (value) => {
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
             if (plot.show === 'percent') {
               value = value + '%'
             }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
+              lablecfg.style.fill = colors.get(key)
+            }
             return {
               content: value,
-              style: {
-                fill: color
-              }
+              ...lablecfg
             }
           })
         }
@@ -741,6 +1192,24 @@
         if (plot.barSize || plot.correction) {
           _chart.size(plot.barSize || 35)
         }
+        if (plot.selectColor) {
+          _chart.state({
+            selected: {
+              style: {
+                fill: plot.selectColor,
+              }
+            }
+          })
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      }
+
+      if (plot.interaction && plot.interaction.length) {
+        plot.interaction.forEach(t => {
+          chart.interaction(t)
+        })
       }
   
       chart.render()
@@ -751,13 +1220,15 @@
 
   updateComponent = (component) => {
     const card = fromJS(this.state.card).toJS()
-    let refresh = false
     if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
       let _element = document.getElementById(card.uuid + 'canvas')
       if (_element) {
         _element.innerHTML = ''
       }
-      refresh = true
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(() => {
+        this.viewrender()
+      }, 150)
     }
 
     component.width = component.plot.width
@@ -765,12 +1236,6 @@
     
     this.setState({
       card: component
-    }, () => {
-      if (refresh) {
-        setTimeout(() => {
-          this.viewrender()
-        }, 100)
-      }
     })
     this.props.updateConfig(component)
   }
@@ -875,15 +1340,15 @@
   }
 
   render() {
-    const { card } = this.state
+    const { card, appType } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-line-chart-edit-box" style={{...card.style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
+      <div className="menu-line-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
-            <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" />
-            <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" /> : null}
             <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
             <CopyComponent type="line" card={card}/>
             <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
@@ -897,12 +1362,13 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
-        <ActionComponent
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
+        <div className="canvas" id={card.uuid + 'canvas'}></div>
+        {appType !== 'mob' ? <ActionComponent
           type="chart"
           config={card}
           updateaction={this.updateComponent}
-        />
-        <div className="canvas" id={card.uuid + 'canvas'}></div>
+        /> : null}
       </div>
     )
   }
diff --git a/src/menu/components/chart/antv-bar/index.scss b/src/menu/components/chart/antv-bar/index.scss
index 9754b3c..0c212d3 100644
--- a/src/menu/components/chart/antv-bar/index.scss
+++ b/src/menu/components/chart/antv-bar/index.scss
@@ -8,9 +8,12 @@
   
   .canvas {
     margin: 0px;
-    // padding: 20px 15px 15px;
-    padding: 15px;
+    padding: 15px 10px 10px;
     letter-spacing: 0px;
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   .chart-header {
@@ -47,6 +50,7 @@
   .model-menu-action-list {
     position: absolute;
     right: 0px;
+    top: 30px;
     z-index: 4;
     font-size: 16px;
   
@@ -58,6 +62,9 @@
       float: right;
     }
   }
+  .normal-header + .canvas + .model-menu-action-list {
+    top: 45px;
+  }
 }
 .menu-line-chart-edit-box:hover {
   z-index: 1;
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx b/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
new file mode 100644
index 0000000..335df94
--- /dev/null
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
@@ -0,0 +1,233 @@
+// import zhCN from '@/locales/zh-CN/model.js'
+// import enUS from '@/locales/en-US/model.js'
+
+// const Formdict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ */
+export function getBaseForm (card) {
+  let roleList = sessionStorage.getItem('sysRoles')
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  return [
+    {
+      type: 'text',
+      key: 'title',
+      label: '鏍囬',
+      initVal: card.title,
+      required: false
+    },
+    {
+      type: 'text',
+      key: 'name',
+      label: '缁勪欢鍚嶇О',
+      initVal: card.name,
+      tooltip: '鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�',
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'width',
+      label: '瀹藉害',
+      initVal: card.width,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'height',
+      label: '楂樺害',
+      initVal: card.height,
+      min: 100,
+      max: 1000,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'blacklist',
+      label: '榛戝悕鍗�',
+      initVal: card.blacklist || [],
+      multi: true,
+      required: false,
+      options: roleList
+    }
+  ]
+}
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ * @param {Array}  columns    // 鏄剧ず鍒�
+ */
+export function getOptionForm (card, columns) {
+  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
+
+  return [
+    {
+      type: 'text',
+      key: 'label',
+      label: '鎸囨爣鍚嶇О',
+      initVal: card.label || '',
+      required: false
+    },
+    {
+      type: 'select',
+      key: 'valueField',
+      label: '鏄剧ず鍊�',
+      initVal: card.valueField || '',
+      required: true,
+      options: yfields
+    },
+    {
+      type: 'number',
+      key: 'maxValue',
+      label: '鏈�澶у��',
+      initVal: card.maxValue || 100,
+      tooltip: '浠〃鐩樻渶澶у埢搴﹀��',
+      min: 0,
+      max: 999999,
+      decimal: 1,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'tickInterval',
+      label: '闂撮殧',
+      initVal: card.tickInterval || 10,
+      tooltip: '浠〃鐩樺埢搴﹂棿闅斿�笺��',
+      min: 0,
+      max: 999999,
+      decimal: 1,
+      required: true
+    },
+    {
+      type: 'radio',
+      key: 'percent',
+      label: '鐧惧垎鐜�',
+      initVal: card.percent || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '浣跨敤'
+      }, {
+        value: 'false',
+        text: '涓嶄娇鐢�'
+      }]
+    },
+    {
+      type: 'color',
+      key: 'tickColor',
+      label: '鍒诲害绾�',
+      initVal: card.tickColor || '#CBCBCB',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'labelColor',
+      label: '鎸囨爣棰滆壊',
+      initVal: card.labelColor || '#545454',
+      required: false
+    }
+  ]
+}
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ * @param {Array}  columns    // 鏄剧ず鍒�
+ */
+export function getRadioOptionForm (card, columns) {
+  let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
+  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
+
+  return [
+    {
+      type: 'select',
+      key: 'labelField',
+      label: '鎸囨爣',
+      initVal: card.labelField || '',
+      required: true,
+      options: xfields
+    },
+    {
+      type: 'select',
+      key: 'valueField',
+      label: '鍊�',
+      initVal: card.valueField || '',
+      required: true,
+      options: yfields
+    },
+    {
+      type: 'number',
+      key: 'maxValue',
+      label: '鏈�澶у��',
+      initVal: card.maxValue || 100,
+      min: 0,
+      max: 999999,
+      decimal: 1,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'radius',
+      label: '澶栫幆',
+      initVal: card.radius || 75,
+      tooltip: '鍥惧舰鎵�鍗犲尯鍩熺殑鐧惧垎鐜囥��',
+      min: 30,
+      max: 100,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'fontSize',
+      label: '瀛椾綋澶у皬',
+      initVal: card.fontSize || 28,
+      min: 12,
+      max: 200,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'radio',
+      key: 'percent',
+      label: '鐧惧垎鐜�',
+      initVal: card.percent || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '浣跨敤'
+      }, {
+        value: 'false',
+        text: '涓嶄娇鐢�'
+      }]
+    },
+    {
+      type: 'color',
+      key: 'backColor',
+      label: '鑳屾櫙鑹�',
+      initVal: card.backColor || '#ebedf0',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'labelColor',
+      label: '瀛椾綋棰滆壊',
+      initVal: card.labelColor || '#8c8c8c',
+      required: false
+    }
+  ]
+}
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx b/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
new file mode 100644
index 0000000..76effa8
--- /dev/null
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
@@ -0,0 +1,333 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Modal, Form, Row, Col, Select, Icon, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import { getBaseForm, getOptionForm, getRadioOptionForm } from './formconfig'
+import asyncComponent from '@/utils/asyncComponent'
+import ColorSketch from '@/mob/colorsketch'
+import './index.scss'
+
+const { TabPane } = Tabs
+
+const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
+const NormalForm = asyncComponent(() => import('@/menu/components/share/normalform'))
+
+class LineChartDrawerForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    plot: PropTypes.object,
+    config: PropTypes.object,
+    plotchange: PropTypes.func
+  }
+
+  state = {
+    visible: false,
+    plot: null,
+    formlist: null,
+    baseFormlist: null,
+    view: 'normal',
+    colorColumns: [
+      {
+        title: '鎸囨爣',
+        dataIndex: 'tick',
+        inputType: this.props.config.subtype === 'ratioboard' ? 'text' : 'number',
+        editable: true,
+        width: '40%'
+      },
+      {
+        title: '棰滆壊',
+        dataIndex: 'color',
+        inputType: 'color',
+        editable: true,
+        width: '40%',
+        render: (text, record) => {
+          return (<div style={{width: '80px', height: '23px', background: text}}></div>)
+        }
+      },
+    ]
+  }
+
+  showDrawer = () => {
+    const { config } = this.props
+
+    this.setState({
+      visible: true,
+      view: 'normal',
+      plot: fromJS(config.plot).toJS(),
+      baseFormlist: getBaseForm(config.plot),
+      formlist: config.subtype === 'ratioboard' ? getRadioOptionForm(config.plot, config.columns) : getOptionForm(config.plot, config.columns)
+    })
+  }
+
+  getFields() {
+    const { formlist } = this.state
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    if (!formlist) {
+      return fields
+    }
+
+    formlist.forEach((item, index) => {
+      if (item.hidden || item.forbid) return
+      
+      if (item.type === 'text') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select mode={item.multi ? 'multiple' : ''}>
+                  {item.options.map((option, index) =>
+                    <Select.Option key={index} value={option.field}>
+                      {option.label}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group disabled={item.readonly}>
+                  {item.options.map(option => {
+                    return (
+                      <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                    )
+                  })}
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'color') {
+        fields.push(
+          <Col span={12} key={index} className="color-col">
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(
+                <ColorSketch />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  onSubmit = () => {
+    const { config } = this.props
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _plot = {...plot, ...values}
+          
+          this.setState({
+            plot: _plot,
+            visible: false
+          })
+  
+          this.props.plotchange({...config, plot: _plot})
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        let _plot = {...plot, ...res}
+
+        this.setState({
+          plot: _plot,
+          visible: false
+        })
+
+        this.props.plotchange({...config, plot: _plot})
+      })
+    } else {
+      this.setState({
+        visible: false
+      })
+
+      this.props.plotchange({...config, plot: plot})
+    }
+  }
+
+  changeTab = (tab) => {
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _plot = {...plot, ...values}
+
+          this.setState({
+            plot: _plot,
+            view: tab
+          })
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        let _plot = {...plot, ...res}
+
+        this.setState({
+          plot: _plot,
+          view: tab
+        })
+      })
+    } else {
+      this.setState({
+        view: tab
+      })
+    }
+  }
+
+  addColor = () => {
+    let plot = fromJS(this.state.plot).toJS()
+    plot.colors = plot.colors || []
+
+    plot.colors.push({
+      uuid: Utils.getuuid(),
+      tick: plot.maxValue || 1,
+      color: '#1890ff'
+    })
+
+    this.setState({plot})
+  }
+
+  changeColor = (colors) => {
+    const { plot } = this.state
+
+    this.setState({plot: {...plot, colors}})
+  }
+
+  render() {
+    const { visible, plot, colorColumns, view, baseFormlist } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div className="line-chart-drawer-form">
+        <Icon type="edit" title="缂栬緫" onClick={this.showDrawer} />
+        <Modal
+          wrapClassName="popview-modal menu-chart-edit-modal"
+          title="鍥捐〃缂栬緫"
+          visible={visible}
+          width={850}
+          maskClosable={false}
+          onOk={this.onSubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <Tabs activeKey={view} className="menu-chart-edit-box" onChange={this.changeTab}>
+            <TabPane tab="缁勪欢璁剧疆" key="base">
+              <NormalForm dict={this.props.dict} formlist={baseFormlist} inputSubmit={this.onSubmit} wrappedComponentRef={(inst) => this.baseRef = inst}/>
+            </TabPane>
+            <TabPane tab="鍥捐〃璁剧疆" key="normal">
+              <Form {...formItemLayout}>
+                <Row gutter={16}>{this.getFields()}</Row>
+              </Form>
+            </TabPane>
+            {plot ? <TabPane tab="棰滆壊璁剧疆" key="color">
+              <div>
+                <Button className="color-add mk-green" onClick={this.addColor}>{this.props.dict['model.add']}</Button>
+                <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={colorColumns} onChange={this.changeColor}/>
+              </div>
+            </TabPane> : null}
+          </Tabs>
+          
+        </Modal>
+      </div>
+    );
+  }
+}
+
+export default Form.create()(LineChartDrawerForm)
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-dashboard/chartcompile/index.scss b/src/menu/components/chart/antv-dashboard/chartcompile/index.scss
new file mode 100644
index 0000000..607a36d
--- /dev/null
+++ b/src/menu/components/chart/antv-dashboard/chartcompile/index.scss
@@ -0,0 +1,44 @@
+.line-chart-drawer-form {
+  display: inline-block;
+  > .anticon-edit {
+    color: #1890ff;
+  }
+}
+.menu-chart-edit-modal {
+  .ant-modal {
+    top: 50px;
+    .ant-modal-body {
+      min-height: 50vh;
+      max-height: calc(100vh - 190px);
+      padding-top: 10px;
+      .anticon-question-circle {
+        color: #c49f47;
+        position: relative;
+        left: -3px;
+      }
+      .ant-input-number {
+        width: 100%;
+      }
+      .ant-tabs-nav-wrap {
+        text-align: center;
+      }
+      .color-sketch-block {
+        position: relative;
+        top: 5px;
+        width: 240px;
+      }
+      .color-add {
+        float: right;
+        margin-bottom: 10px;
+        position: relative;
+        z-index: 1;
+      }
+      .color-col {
+        .ant-form-item-control {
+          height: 40px;
+        }
+      }
+    }
+  }
+}
+
diff --git a/src/menu/components/chart/antv-dashboard/index.jsx b/src/menu/components/chart/antv-dashboard/index.jsx
new file mode 100644
index 0000000..54f8e71
--- /dev/null
+++ b/src/menu/components/chart/antv-dashboard/index.jsx
@@ -0,0 +1,538 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+import { Chart, registerShape } from '@antv/g2'
+
+import MKEmitter from '@/utils/events.js'
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+
+registerShape('point', 'pointer', {
+  draw(cfg, container) {
+    const group = container.addGroup({});
+    // 鑾峰彇鏋佸潗鏍囩郴涓嬬敾甯冧腑蹇冪偣
+    const center = this.parsePoint({ x: 0, y: 0 });
+    // 缁樺埗鎸囬拡
+    group.addShape('line', {
+      attrs: {
+        x1: center.x,
+        y1: center.y,
+        x2: cfg.x,
+        y2: cfg.y,
+        stroke: cfg.color,
+        lineWidth: 5,
+        lineCap: 'round',
+      },
+    });
+    group.addShape('circle', {
+      attrs: {
+        x: center.x,
+        y: center.y,
+        r: 9.75,
+        stroke: cfg.color,
+        lineWidth: 4.5,
+        fill: '#fff',
+      },
+    });
+    return group;
+  },
+})
+
+registerShape('point', 'hidden', {
+  draw(cfg, container) {
+    return container.addGroup({})
+  }
+})
+
+class antvDashboardChart extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    updateConfig: PropTypes.func,
+    deletecomponent: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    ismob: sessionStorage.getItem('appType') === 'mob',
+    eventListener: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card, ismob } = this.props
+
+    if (card.isNew) {
+      let _plot = null
+      if (card.subtype === 'ratioboard') {
+        _plot = {
+          width: card.width || 12,
+          height: 400,
+          labelField: '',
+          valueField: '',
+          name: card.name,
+          maxValue: 100,
+          radius: 75,
+          fontSize: 28,
+          percent: 'true',
+          backColor: '#ebedf0',
+          labelColor: '#8c8c8c'
+        }
+      } else {
+        _plot = {
+          width: card.width || 12,
+          height: 400,
+          label: '',
+          valueField: '',
+          name: card.name,
+          maxValue: 100,
+          tickInterval: 10,
+          labelColor: '#545454',
+          tickColor: '#CBCBCB',
+          percent: 'true'
+        }
+      }
+
+      if (ismob) {
+        _plot.width = 24
+      }
+
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: card.subtype === 'ratioboard' ? 'array' : 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: _plot.width,
+        name: _plot.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        style: {
+          borderWidth: '1px', borderColor: 'rgb(217, 217, 217)',
+          marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+        },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        scripts: [],
+        search: [],
+        action: [],
+        plot: _plot,
+        btnlog: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.plot = config.plot
+        _card.plot.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+      }
+
+      this.props.updateConfig(_card)
+      this.setState({
+        card: _card
+      })
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    MKEmitter.addListener('submitStyle', this.getStyle)
+
+    setTimeout(() => {
+      this.viewrender()
+    }, 1000)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('tabsChange', this.handleTabsChange)
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  handleTabsChange = (parentId) => {
+    const { card } = this.state
+
+    if (parentId === card.parentId) {
+      let _element = document.getElementById(card.uuid + 'canvas')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(this.viewrender, 100)
+    }
+  }
+
+  viewrender = () => {
+    const { card } = this.state
+    if (card.subtype === 'ratioboard') {
+      this.ratioboardrender()
+    } else {
+      this.dashboardrender()
+    }
+  }
+
+  getratiodata = () => {
+    const { card } = this.state
+
+    let val = (Math.random() * card.plot.maxValue).toFixed(1)
+    let data = [
+      { type: '鏂扮敤鎴�', value: val, $percent: val / card.plot.maxValue, $color: '#1890ff' },
+    ]
+    if (card.plot.colors && card.plot.colors.length > 0) {
+      data = []
+      card.plot.colors.forEach(item => {
+        let _val = (Math.random() * card.plot.maxValue).toFixed(1)
+        data.push({
+          type: item.tick,
+          value: _val,
+          $percent: _val / card.plot.maxValue,
+          $color: item.color
+        })
+      })
+    }
+
+    return data
+  }
+
+  ratioboardrender = () => {
+    const { card } = this.state
+    const plot = card.plot
+
+    const data = this.getratiodata()
+    
+    const chart = new Chart({
+      container: card.uuid + 'dashboard',
+      autoFit: true,
+      height: plot.title ? plot.height - 45 : plot.height,
+    })
+    
+    chart.data(data)
+    chart.coordinate('polar', {
+      startAngle: -Math.PI / 2,
+      endAngle: 3 * Math.PI / 2,
+      radius: (plot.radius || 75) / 100
+    })
+    chart.scale('$percent', {
+      min: 0,
+      max: 1,
+      tickInterval: 1,
+    })
+    chart.axis(false)
+    chart.facet('rect', {
+      fields: ['type'],
+      showTitle: false,
+      eachView: function eachView(view, facet) {
+        const data = facet.data[0]
+
+        view.point().position('').shape('hidden')
+
+        view.annotation().arc({
+          top: false,
+          start: [0, 1],
+          end: [0.9999, 1],
+          style: {
+            stroke: plot.backColor,
+            lineWidth: 10
+          }
+        })
+
+        let _tick = data.$percent
+        if (_tick >= 1) {
+          _tick = 0.9999
+        }
+
+        view.annotation().arc({
+          start: [0, 1],
+          end: [_tick, 1],
+          style: {
+            stroke: data.$color,
+            lineWidth: 10,
+          }
+        })
+        // 浠〃鐩樹俊鎭�
+        let text = ''
+        if (plot.percent === 'true') {
+          text = +(data.$percent * 100).toFixed(2) + '%'
+        } else {
+          text = data.value
+        }
+    
+        view.annotation().text({
+          position: ['50%', '45%'],
+          content: data.type,
+          style: {
+            fontSize: plot.fontSize * 0.8,
+            fill: plot.labelColor,
+            fontWeight: 300,
+            textAlign: 'center'
+          },
+          offsetX: 0
+        })
+        view.annotation().text({
+          position: ['50%', '55%'],
+          content: text,
+          style: {
+            fontSize: plot.fontSize,
+            fill: plot.labelColor,
+            fontWeight: 500,
+            textAlign: 'center'
+          },
+          offsetX: 0,
+          offsetY: 10
+        })
+      }
+    })
+    chart.render()
+  }
+
+  getdata = () => {
+    const { card } = this.state
+
+    const data = []
+    const val = (Math.random() * card.plot.maxValue).toFixed(1)
+    data.push({ value: +val })
+    return data
+  }
+
+  dashboardrender = () => {
+    const { card } = this.state
+    const plot = card.plot
+    const data = this.getdata()
+
+    const chart = new Chart({
+      container: card.uuid + 'dashboard',
+      autoFit: true,
+      height: plot.title ? plot.height - 45 : plot.height,
+      padding: [0, 0, 0, 0],
+    })
+    chart.data(data)
+    chart.scale('value', {
+      min: 0,
+      max: plot.maxValue,
+      tickInterval: plot.tickInterval,
+    })
+    chart.coordinate('polar', {
+      startAngle: (-9 / 8) * Math.PI,
+      endAngle: (1 / 8) * Math.PI,
+      radius: 0.75,
+    })
+
+    chart.axis('1', false)
+    chart.axis('value', {
+      line: null,
+      label: {
+        offset: -36,
+        style: {
+          fontSize: 18,
+          fill: plot.tickColor,
+          textAlign: 'center',
+          textBaseline: 'middle',
+        },
+      },
+      tickLine: {
+        length: -24,
+        style: {
+          stroke: plot.tickColor
+        }
+      },
+      grid: null,
+    })
+    chart.legend(false)
+    chart.tooltip(false)
+    chart
+      .point()
+      .position('value*1')
+      .shape('pointer')
+      .color('value', (val) => {
+        let _color = '#1890FF'
+        if (plot.colors && plot.colors.length > 0) {
+          _color = plot.colors[plot.colors.length - 1].color || '#1890FF'
+          plot.colors.some(item => {
+            if (item.tick > val) {
+              _color = item.color
+              return true
+            }
+            return false
+          })
+        }
+        return _color
+      })
+      .animate({
+        appear: {
+          animation: 'fade-in'
+        }
+      })
+
+    // 缁樺埗浠〃鐩樿儗鏅�
+    chart.annotation().arc({
+      top: false,
+      start: [0, 1],
+      end: [plot.maxValue, 1],
+      style: {
+        stroke: '#ebedf0',
+        lineWidth: 18,
+        lineDash: null,
+      },
+    })
+
+    if (!plot.colors || plot.colors.length === 0) {
+      chart.annotation().arc({
+        start: [0, 1],
+        end: [plot.maxValue, 1],
+        style: {
+          stroke: '#1890FF',
+          lineWidth: 18,
+          lineDash: null,
+        },
+      });
+    } else {
+      let start = 0
+      plot.colors.forEach(item => {
+        chart.annotation().arc({
+          start: [start, 1],
+          end: [item.tick, 1],
+          style: {
+            stroke: item.color,
+            lineWidth: 18,
+            lineDash: null,
+          },
+        })
+        start = item.tick
+      })
+    }
+
+    if (plot.label) {
+      chart.annotation().text({
+        position: ['50%', '85%'],
+        content: plot.label,
+        style: {
+          fontSize: 20,
+          fill: plot.labelColor,
+          textAlign: 'center',
+        },
+      })
+    }
+
+    let val = data[0].value
+    if (plot.percent !== 'false' && plot.maxValue) {
+      val = +(val / plot.maxValue * 100).toFixed(2) + ' %'
+    }
+
+    chart.annotation().text({
+      position: ['50%', '90%'],
+      content: val,
+      style: {
+        fontSize: 36,
+        fill: plot.labelColor,
+        textAlign: 'center',
+      },
+      offsetY: 15,
+    })
+
+    chart.render()
+  }
+
+  updateComponent = (component) => {
+    const card = fromJS(this.state.card).toJS()
+
+    if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
+      let _element = document.getElementById(card.uuid + 'dashboard')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(() => {
+        this.viewrender()
+      }, 150)
+    }
+
+    component.width = component.plot.width
+    component.name = component.plot.name
+    
+    this.setState({
+      card: component
+    })
+    this.props.updateConfig(component)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid || comIds.length > 1) return
+
+    let _card = {...card, style}
+
+    this.updateComponent(_card)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card } = this.state
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-dashboard-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
+            <CopyComponent type="dashboard" card={card}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            <SettingComponent config={card} updateConfig={this.updateComponent}/>
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        {card.plot.title ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
+        <div className="canvas" id={card.uuid + 'dashboard'}></div>
+      </div>
+    )
+  }
+}
+
+export default antvDashboardChart
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-dashboard/index.scss b/src/menu/components/chart/antv-dashboard/index.scss
new file mode 100644
index 0000000..efb4267
--- /dev/null
+++ b/src/menu/components/chart/antv-dashboard/index.scss
@@ -0,0 +1,50 @@
+.menu-dashboard-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  
+  .canvas {
+    margin: 0px;
+    padding: 15px;
+    letter-spacing: 0px;
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
+  }
+
+  >.anticon-tool {
+    position: absolute;
+    right: 1px;
+    top: 1px;
+    z-index: 2;
+    font-size: 16px;
+    padding: 5px;
+    cursor: pointer;
+    color: rgba(0, 0, 0, 0.85);
+    background: rgba(255, 255, 255, 0.55);
+  }
+
+  .model-menu-action-list {
+    position: absolute;
+    right: 0px;
+    z-index: 4;
+    padding-top: 10px;
+    font-size: 16px;
+  
+    .ant-row .anticon-plus {
+      float: right;
+    }
+  
+    .page-card {
+      float: right;
+    }
+  }
+}
+.menu-dashboard-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx b/src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
index 6c4e322..20a3b61 100644
--- a/src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
+++ b/src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
@@ -8,7 +8,8 @@
  * @param {object} card       // 鍥捐〃瀵硅薄
  */
 export function getBaseForm (card) {
-  let isApp = sessionStorage.getItem('appType') === 'pc'
+  let appType = sessionStorage.getItem('appType')
+  let isApp = appType === 'pc' || appType === 'mob'
   let menulist = null
 
   if (isApp) {
@@ -131,6 +132,7 @@
  * @param {Array}  columns    // 鏄剧ず鍒�
  */
 export function getOptionForm (card, columns) {
+  let appType = sessionStorage.getItem('appType')
   let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
   let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
 
@@ -144,13 +146,14 @@
       options: [
         { value: 'pie', text: '楗煎浘' },
         { value: 'ring', text: '鐜浘' },
+        { value: 'nest', text: '宓屽' },
         { value: 'nightingale', text: '鍗椾竵鏍煎皵鍥�' }
       ]
     },
     {
       type: 'select',
       key: 'Xaxis',
-      label: 'X-杞�',
+      label: '鍚嶇О',
       initVal: card.Xaxis || '',
       required: true,
       options: xfields
@@ -158,10 +161,20 @@
     {
       type: 'select',
       key: 'Yaxis',
-      label: 'Y-杞�',
+      label: '鍊�',
       initVal: card.Yaxis || '',
       required: true,
       options: yfields
+    },
+    {
+      type: 'select',
+      key: 'type',
+      label: '绫诲瀷',
+      initVal: card.type || '',
+      tooltip: '鍐呯幆鐨勫垎绫诲瓧娈点��',
+      required: true,
+      options: xfields,
+      hidden: card.shape !== 'nest',
     },
     {
       type: 'select',
@@ -183,7 +196,8 @@
         { field: 'left-top', label: '宸︿笂' },
         { field: 'left-bottom', label: '宸︿笅' },
         { field: 'hidden', label: '闅愯棌' }
-      ]
+      ],
+      hidden: card.shape === 'nest',
     },
     {
       type: 'number',
@@ -239,7 +253,7 @@
     {
       type: 'radio',
       key: 'label',
-      label: '鏍囨敞鍊�',
+      label: '鏍囩',
       initVal: card.label || 'false',
       required: false,
       options: [{
@@ -250,8 +264,11 @@
         text: '鍐呬晶'
       }, {
         value: 'outer',
-        text: '澶栦晶'
-      }]
+        text: '铚樿洓'
+      }, {
+        value: 'normal',
+        text: '甯歌'
+      }],
     }, {
       type: 'radio',
       key: 'repeat',
@@ -269,19 +286,51 @@
         text: '绱姞'
       }]
     }, {
+      type: 'number',
+      key: 'splitLine',
+      label: '鍒嗛殧绾�',
+      initVal: card.splitLine || '',
+      tooltip: '鍒嗛殧绾跨殑瀹藉害銆�',
+      min: 0,
+      max: 20,
+      decimal: 0,
+      required: false
+    }, {
+      type: 'color',
+      key: 'splitColor',
+      label: '鍒嗛殧鑹�',
+      initVal: card.splitColor || '#ffffff',
+      tooltip: '鍒嗛殧绾跨殑棰滆壊锛屽瓨鍦ㄥ垎闅旂嚎鏃舵湁鏁堛��',
+      required: false
+    }, {
       type: 'color',
       key: 'color',
       label: '鑹茬郴',
       initVal: card.color || 'rgba(0, 0, 0, 0.85)',
       tooltip: '鍧愭爣杞村強绀轰緥绛夋彁绀烘枃瀛椾娇鐢ㄧ殑棰滆壊銆�',
+      required: false
+    }, {
+      type: 'select',
+      key: 'interaction',
+      label: '浜や簰鏁堟灉',
+      initVal: card.interaction || [],
+      multi: true,
       required: false,
-      options: [{
-        value: 'black',
-        text: '榛戣壊'
-      }, {
-        value: 'white',
-        text: '鐧借壊'
-      }]
+      forbid: appType === 'mob',
+      options: [
+        { value: 'element-active', label: '鍏冪礌鑱氱劍' },
+        { value: 'element-selected', label: '鍏冪礌閫変腑锛堝閫夛級' },
+        { value: 'element-single-selected', label: '鍏冪礌閫変腑锛堝崟閫夛級' },
+        // { value: 'active-region', label: '鑳屾櫙妗�' },
+        // { value: 'view-zoom', label: '瑙嗗浘缂╂斁' },
+        { value: 'element-highlight', label: '鍏冪礌楂樹寒' },
+        // { value: 'element-highlight-by-color', label: '鍚岃壊鍏冪礌楂樹寒' },
+        // { value: 'element-highlight-by-x', label: '鍚孹杞村厓绱犻珮浜�' },
+        { value: 'legend-filter', label: '鍥句緥杩囨护' },
+        { value: 'legend-active', label: '鍥句緥鑱氱劍' },
+        { value: 'legend-highlight', label: '鍥句緥楂樹寒' },
+        // { value: 'brush', label: '閫夋杩囨护' },
+      ]
     }
   ]
 }
diff --git a/src/menu/components/chart/antv-pie/chartcompile/index.jsx b/src/menu/components/chart/antv-pie/chartcompile/index.jsx
index 2152dde..4f2638b 100644
--- a/src/menu/components/chart/antv-pie/chartcompile/index.jsx
+++ b/src/menu/components/chart/antv-pie/chartcompile/index.jsx
@@ -70,6 +70,10 @@
         formlist: formlist.map(item => {
           if (item.key === 'innerRadius') {
             item.hidden = val === 'pie'
+          } else if (item.key === 'type') {
+            item.hidden = val !== 'nest'
+          } else if (item.key === 'legend') {
+            item.hidden = val === 'nest'
           }
           return item
         })
@@ -157,7 +161,7 @@
               })(
                 <Select mode={item.multi ? 'multiple' : ''}>
                   {item.options.map((option, index) =>
-                    <Select.Option key={index} value={option.field}>
+                    <Select.Option key={index} value={option.field || option.value}>
                       {option.label}
                     </Select.Option>
                   )}
@@ -184,7 +188,7 @@
                   }
                 ]
               })(
-                <Radio.Group disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
+                <Radio.Group style={{whiteSpace: 'nowrap'}} disabled={item.readonly} onChange={(e) => this.radioChange(e, item.key)}>
                   {item.options.map(option => {
                     return (
                       <Radio key={option.value} value={option.value}>{option.text}</Radio>
diff --git a/src/menu/components/chart/antv-pie/index.jsx b/src/menu/components/chart/antv-pie/index.jsx
index 374720a..593fcd5 100644
--- a/src/menu/components/chart/antv-pie/index.jsx
+++ b/src/menu/components/chart/antv-pie/index.jsx
@@ -1,14 +1,14 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Icon, Popover, notification } from 'antd'
+import { Icon, Popover } from 'antd'
 import { Chart } from '@antv/g2'
-import DataSet from '@antv/data-set'
+import DataSet, { DataView } from '@antv/data-set'
 
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
@@ -18,7 +18,6 @@
 const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
-const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
 const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
 const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
 const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
@@ -33,11 +32,12 @@
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     card: null,
+    ismob: sessionStorage.getItem('appType') === 'mob',
     eventListener: null
   }
 
   UNSAFE_componentWillMount () {
-    const { card } = this.props
+    const { card, ismob } = this.props
 
     if (card.isNew) {
       let _plot = {
@@ -48,8 +48,15 @@
         name: card.name
       }
 
+      if (ismob) {
+        _plot.width = 24
+      }
+
       if (card.subtype === 'ring') {
         _plot.innerRadius = 50
+      } else if (card.subtype === 'nest') {
+        _plot.innerRadius = 30
+        _plot.radius = 80
       }
 
       let _card = {
@@ -105,9 +112,12 @@
   }
 
   componentDidMount () {
-    this.pierender()
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
     MKEmitter.addListener('submitStyle', this.getStyle)
+
+    setTimeout(() => {
+      this.viewrender()
+    }, 1000)
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -134,7 +144,18 @@
         _element.innerHTML = ''
       }
 
-      setTimeout(this.pierender, 100)
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(this.viewrender, 100)
+    }
+  }
+
+  viewrender = () => {
+    const { card } = this.state
+
+    if (card.plot.shape === 'nest') {
+      this.nestrender()
+    } else {
+      this.pierender()
     }
   }
 
@@ -145,13 +166,6 @@
       { label: '2003', value: 33.7 },
       { label: '2004', value: 30.7 },
       { label: '2005', value: 25.8 },
-      { label: '2006', value: 31.7 },
-      { label: '2007', value: 33 },
-      { label: '2008', value: 46 },
-      { label: '2009', value: 38.3 },
-      { label: '2010', value: 28 },
-      { label: '2011', value: 42.5 },
-      { label: '2012', value: 30.3 }
     ]
 
     let data = xdata.map(item => {
@@ -164,13 +178,252 @@
     return data
   }
 
-  pierender = () => {
-    const { card } = this.state
-    let plot = {...card.plot, height: card.plot.height - 80}
-    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
+  getnestdata = (X_axis, Y_axis, type) => {
+    const xdata = [
+      { name: '鐙瓙', type: '鐏薄', value: 11 },
+      { name: '鐧界緤', type: '鐏薄', value: 10 },
+      { name: '姘寸摱', type: '椋庡悜', value: 14 },
+      { name: '灏勬墜', type: '鐏薄', value: 10 },
+      { name: '鍙屽瓙', type: '椋庡悜', value: 7 },
+      { name: '澶╁钩', type: '椋庡悜', value: 7 },
+      { name: '鎽╃警', type: '鍦熻薄', value: 14 },
+      { name: '閲戠墰', type: '鍦熻薄', value: 3 },
+      { name: '澶勫コ', type: '鍦熻薄', value: 3 },
+      { name: '澶╄潕', type: '姘磋薄', value: 11 },
+      { name: '宸ㄨ煿', type: '姘磋薄', value: 5 },
+      { name: '鍙岄奔', type: '姘磋薄', value: 5 },
+    ]
 
+    let map = new Map()
+    let sort = 1
+    let data = xdata.map(item => {
+      let _sort = sort
+      if (map.has(item.type)) {
+        _sort = map.get(item.type)
+      } else {
+        map.set(item.type, _sort)
+        sort++
+      }
+      return {
+        [X_axis]: item.name,
+        [Y_axis]: item.value,
+        [type]: item.type,
+        $sort: _sort
+      }
+    })
+
+    return data
+  }
+
+  nestrender = () => {
+    const { card } = this.state
+    const plot = card.plot
+
+    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
     let X_axis = plot.Xaxis || 'x'
     let Y_axis = plot.Yaxis || 'y'
+    let type = plot.type || 'type'
+    let height = plot.height || 400
+    if (card.plot.title || card.search.length > 0) {
+      height = height - 45
+    }
+
+    const _data = this.getnestdata(X_axis, Y_axis, type)
+    const dvx = new DataView().source(_data)
+
+    dvx.transform({
+      type: 'sort-by',
+      fields: ['$sort']
+    })
+
+    let data = dvx.rows
+
+    // 閫氳繃 DataSet 璁$畻鐧惧垎姣�
+    const dv = new DataView()
+    dv.source(data).transform({
+      type: 'percent',
+      field: Y_axis,
+      dimension: type,
+      as: '$percent'
+    })
+
+    const dv1 = new DataView()
+    dv1.source(data).transform({
+      type: 'percent',
+      field: Y_axis,
+      dimension: X_axis,
+      as: '$percent',
+    })
+
+    const chart = new Chart({
+      container: card.uuid + 'canvas',
+      autoFit: true,
+      height: height,
+      padding: 0,
+    })
+
+    chart.data(dv.rows)
+
+    if (plot.show !== 'value') {
+      chart.scale('percent', {
+        formatter: (val) => {
+          val = val * 100 + '%'
+          return val
+        }
+      })
+
+      Y_axis = '$percent'
+    }
+    let radius = plot.radius / 100
+    let innerRadius = plot.innerRadius / 100
+    
+    chart.coordinate('theta', {
+      innerRadius: innerRadius,
+      radius: innerRadius + (radius - innerRadius) / 2,
+    })
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        showTitle: false,
+        showMarkers: false
+      })
+    }
+
+    chart.legend(false)
+    let chart1 = chart
+      .interval()
+      .adjust('stack')
+      .position(Y_axis)
+      .color(type)
+      .tooltip(`${type}*${Y_axis}`, (type, percent) => {
+        if (plot.show !== 'value') {
+          percent = (percent * 100).toFixed(2) + '%'
+        }
+        return {
+          name: type,
+          value: percent,
+        }
+      })
+
+    if (plot.splitLine) {
+      chart1.style({
+        lineWidth: plot.splitLine,
+        stroke: plot.splitColor,
+      })
+    }
+    if (plot.label !== 'false') {
+      chart1.label(type, {
+        offset: -10,
+      })
+    }
+    
+    const outterView = chart.createView()
+    
+    outterView.data(dv1.rows)
+
+    if (plot.show !== 'value') {
+      outterView.scale('percent', {
+        formatter: (val) => {
+          val = val * 100 + '%'
+          return val
+        }
+      })
+    }
+    outterView.coordinate('theta', {
+      innerRadius: (innerRadius + (radius - innerRadius) / 2) / radius,
+      radius: radius
+    })
+    let chart2 = outterView
+      .interval()
+      .adjust('stack')
+      .position(Y_axis)
+      .color(X_axis)
+      .tooltip(`${X_axis}*${Y_axis}`, (name, value) => {
+        if (plot.show !== 'value') {
+          value = (value * 100).toFixed(2) + '%'
+        }
+        return {
+          name: name,
+          value: value
+        }
+      })
+
+    if (plot.splitLine) {
+      chart2.style({
+        lineWidth: plot.splitLine,
+        stroke: plot.splitColor,
+      })
+    }
+
+    if (plot.label !== 'false') {
+      if (plot.label === 'inner') {
+        chart2.label(Y_axis, {
+          offset: -30,
+          content: (data) => {
+            let _val = ''
+            if (plot.show !== 'value') {
+              _val = `${(data[Y_axis] * 100).toFixed(2)}%`
+            } else {
+              _val = `${data[Y_axis]}`
+            }
+            return _val
+          },
+          style: {
+            textAlign: 'center',
+            fontSize: 16,
+            shadowBlur: 2,
+            shadowColor: 'rgba(0, 0, 0, .45)',
+            fill: '#fff',
+          }
+        })
+      } else {
+        chart2.label(Y_axis, {
+          layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' },
+          labelHeight: 20,
+          content: (data) => {
+            let _val = ''
+            if (plot.show !== 'value') {
+              _val = `${(data[Y_axis] * 100).toFixed(2)}%`
+            } else {
+              _val = `${data[Y_axis]}`
+            }
+
+            return `${data[X_axis]}: ${_val}`
+          },
+          labelLine: {
+            style: {
+              lineWidth: 0.5,
+            },
+          },
+          style: {
+            fill: color
+          }
+        })
+      }
+    }
+    
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
+    }
+    
+    chart.render()
+  }
+
+  pierender = () => {
+    const { card } = this.state
+    const plot = card.plot
+
+    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
+    let X_axis = plot.Xaxis || 'x'
+    let Y_axis = plot.Yaxis || 'y'
+    let height = plot.height || 400
+    if (card.plot.title || card.search.length > 0) {
+      height = height - 45
+    }
 
     let data = this.getdata(X_axis, Y_axis)
 
@@ -180,7 +433,7 @@
     const chart = new Chart({
       container: card.uuid + 'canvas',
       autoFit: true,
-      height: plot.height || 400
+      height: height
     })
 
     if (plot.shape !== 'nightingale' && plot.show !== 'value') {
@@ -245,6 +498,7 @@
       })
     }
 
+    // 楗煎浘鎴栫幆鍥�
     if (plot.shape !== 'nightingale') {
       let _chart = chart
         .interval()
@@ -260,24 +514,26 @@
             value: value
           }
         })
+
+      if (plot.splitLine) {
+        _chart.style({
+          lineWidth: plot.splitLine,
+          stroke: plot.splitColor,
+        })
+      }
+
       if (plot.label !== 'false') {
         if (plot.label === 'inner') {
           _chart.label(Y_axis, {
             offset: -30,
             content: (data) => {
-              let _label = ''
               let _val = ''
               if (plot.show !== 'value') {
                 _val = `${(data[Y_axis] * 100).toFixed(2)}%`
               } else {
                 _val = `${data[Y_axis]}`
               }
-              if (plot.label === 'inner') {
-                _label = _val
-              } else {
-                _label = `${data[X_axis]}: ${_val}`
-              }
-              return _label
+              return _val
             },
             style: {
               textAlign: 'center',
@@ -289,22 +545,17 @@
           })
         } else {
           _chart.label(Y_axis, {
-            layout: { type: 'pie-spider' },
+            layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' },
             labelHeight: 20,
             content: (data) => {
-              let _label = ''
               let _val = ''
               if (plot.show !== 'value') {
                 _val = `${(data[Y_axis] * 100).toFixed(2)}%`
               } else {
                 _val = `${data[Y_axis]}`
               }
-              if (plot.label === 'inner') {
-                _label = _val
-              } else {
-                _label = `${data[X_axis]}: ${_val}`
-              }
-              return _label
+
+              return `${data[X_axis]}: ${_val}`
             },
             labelLine: {
               style: {
@@ -317,10 +568,8 @@
           })
         }
       }
-      chart.interaction('element-active')
     } else {
       chart.axis(false)
-      chart.interaction('element-highlight')
       let _chart = chart
         .interval()
         .position(`${X_axis}*${Y_axis}`)
@@ -337,11 +586,19 @@
           }
 
           _chart.label(X_axis, _label)
-          .style({
-            lineWidth: 1,
-            stroke: '#fff',
+        }
+        if (plot.splitLine) {
+          _chart.style({
+            lineWidth: plot.splitLine,
+            stroke: plot.splitColor,
           })
         }
+    }
+
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
     }
 
     chart.render()
@@ -349,13 +606,16 @@
 
   updateComponent = (component) => {
     const card = fromJS(this.state.card).toJS()
-    let refresh = false
+
     if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
       let _element = document.getElementById(card.uuid + 'canvas')
       if (_element) {
         _element.innerHTML = ''
       }
-      refresh = true
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(() => {
+        this.viewrender()
+      }, 150)
     }
 
     component.width = component.plot.width
@@ -363,12 +623,6 @@
     
     this.setState({
       card: component
-    }, () => {
-      if (refresh) {
-        setTimeout(() => {
-          this.pierender()
-        }, 100)
-      }
     })
     this.props.updateConfig(component)
   }
@@ -410,32 +664,6 @@
     this.updateComponent(_card)
   }
 
-  handleLog = (type, logs, item) => {
-    let card = fromJS(this.state.card).toJS()
-
-    if (type === 'revert') {
-      card.action = card.action ? [...card.action, item] : [item]
-      card.btnlog = logs
-
-      this.setState({ card })
-      this.props.updateConfig(card)
-      notification.success({
-        top: 92,
-        message: '鎭㈠鎴愬姛锛�',
-        duration: 2
-      })
-    } else {
-      card.btnlog = logs
-      this.setState({ card })
-      this.props.updateConfig(card)
-      notification.success({
-        top: 92,
-        message: '娓呴櫎鎴愬姛锛�',
-        duration: 2
-      })
-    }
-  }
-
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -444,19 +672,18 @@
   }
 
   render() {
-    const { card } = this.state
+    const { card, ismob } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-pie-chart-edit-box" style={{...card.style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
-        <NormalHeader config={card} updateComponent={this.updateComponent}/>
+      <div className="menu-pie-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
-            <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" />
+            {!ismob ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
             <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
             <CopyComponent type="pie" card={card}/>
             <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
             <ClockComponent config={card} updateConfig={this.updateComponent}/>
             <UserComponent config={card}/>
             <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -465,6 +692,7 @@
         } trigger="hover">
           <Icon type="tool" />
         </Popover>
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
         <div className="canvas" id={card.uuid + 'canvas'}></div>
       </div>
     )
diff --git a/src/menu/components/chart/antv-pie/index.scss b/src/menu/components/chart/antv-pie/index.scss
index 560f140..43bf1c5 100644
--- a/src/menu/components/chart/antv-pie/index.scss
+++ b/src/menu/components/chart/antv-pie/index.scss
@@ -10,6 +10,10 @@
     margin: 0px;
     padding: 15px;
     letter-spacing: 0px;
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
   }
 
   >.anticon-tool {
diff --git a/src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx b/src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx
new file mode 100644
index 0000000..20b0331
--- /dev/null
+++ b/src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx
@@ -0,0 +1,174 @@
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ */
+export function getBaseForm (card) {
+  let roleList = sessionStorage.getItem('sysRoles')
+  if (roleList) {
+    try {
+      roleList = JSON.parse(roleList)
+    } catch {
+      roleList = []
+    }
+  } else {
+    roleList = []
+  }
+
+  return [
+    {
+      type: 'text',
+      key: 'title',
+      label: '鏍囬',
+      initVal: card.title,
+      required: false
+    },
+    {
+      type: 'text',
+      key: 'name',
+      label: '缁勪欢鍚嶇О',
+      initVal: card.name,
+      tooltip: '鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�',
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'width',
+      label: '瀹藉害',
+      initVal: card.width,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      min: 1,
+      max: 24,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'height',
+      label: '楂樺害',
+      initVal: card.height,
+      min: 100,
+      max: 1000,
+      decimal: 0,
+      required: true
+    },
+    {
+      type: 'select',
+      key: 'blacklist',
+      label: '榛戝悕鍗�',
+      initVal: card.blacklist || [],
+      multi: true,
+      required: false,
+      options: roleList
+    }
+  ]
+}
+
+/**
+ * @description 鑾峰彇鍥捐〃瑙嗗浘閰嶇疆琛ㄥ崟
+ * @param {object} card       // 鍥捐〃瀵硅薄
+ * @param {Array}  columns    // 鏄剧ず鍒�
+ */
+export function getOptionForm (card, columns) {
+  let appType = sessionStorage.getItem('appType')
+  let xfields = columns.filter(item => /^Nvarchar/ig.test(item.datatype))
+  let yfields = columns.filter(item => /^(Int|Decimal)/ig.test(item.datatype))
+
+  return [
+    {
+      type: 'select',
+      key: 'gender',
+      label: '绫诲瀷',
+      initVal: card.gender || '',
+      required: true,
+      options: xfields
+    },
+    {
+      type: 'select',
+      key: 'Xaxis',
+      label: 'X-杞�',
+      initVal: card.Xaxis || '',
+      required: true,
+      options: columns
+    },
+    {
+      type: 'select',
+      key: 'Yaxis',
+      label: 'Y-杞�',
+      initVal: card.Yaxis || '',
+      required: true,
+      options: yfields
+    },
+    {
+      type: 'radio',
+      key: 'shape',
+      label: '褰㈢姸',
+      initVal: card.shape || 'circle',
+      required: false,
+      options: [{
+        value: 'circle',
+        text: 'circle'
+      }, {
+        value: 'square',
+        text: 'square'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'tooltip',
+      label: '鎮诞鎻愮ず',
+      initVal: card.tooltip || 'true',
+      required: false,
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    },
+    {
+      type: 'text',
+      key: 'Xunit',
+      label: 'X杞村崟浣�',
+      initVal: card.Xunit || '',
+      required: false
+    },
+    {
+      type: 'text',
+      key: 'Yunit',
+      label: 'Y杞村崟浣�',
+      initVal: card.Yunit || '',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'color',
+      label: '鑹茬郴',
+      initVal: card.color || 'rgba(0, 0, 0, 0.65)',
+      tooltip: '鍧愭爣杞存彁绀烘枃瀛楀強绀轰緥鐨勯鑹层��',
+      required: false
+    }, {
+      type: 'select',
+      key: 'interaction',
+      label: '浜や簰鏁堟灉',
+      initVal: card.interaction || [],
+      multi: true,
+      required: false,
+      forbid: appType === 'mob',
+      options: [
+        { value: 'element-active', label: '鍏冪礌鑱氱劍' },
+        { value: 'element-selected', label: '鍏冪礌閫変腑锛堝閫夛級' },
+        { value: 'element-single-selected', label: '鍏冪礌閫変腑锛堝崟閫夛級' },
+        // { value: 'active-region', label: '鑳屾櫙妗�' },
+        { value: 'view-zoom', label: '瑙嗗浘缂╂斁' },
+        { value: 'element-highlight', label: '鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-color', label: '鍚岃壊鍏冪礌楂樹寒' },
+        { value: 'element-highlight-by-x', label: '鍚孹杞村厓绱犻珮浜�' },
+        { value: 'legend-filter', label: '鍥句緥杩囨护' },
+        { value: 'legend-active', label: '鍥句緥鑱氱劍' },
+        { value: 'legend-highlight', label: '鍥句緥楂樹寒' },
+        { value: 'brush', label: '閫夋杩囨护' },
+      ]
+    }
+  ]
+}
diff --git a/src/menu/components/chart/antv-scatter/chartcompile/index.jsx b/src/menu/components/chart/antv-scatter/chartcompile/index.jsx
new file mode 100644
index 0000000..0982251
--- /dev/null
+++ b/src/menu/components/chart/antv-scatter/chartcompile/index.jsx
@@ -0,0 +1,271 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Modal, Form, Row, Col, Select, Icon, Radio, Tooltip, Input, InputNumber, Tabs } from 'antd'
+
+import { getBaseForm, getOptionForm } from './formconfig'
+import asyncComponent from '@/utils/asyncComponent'
+import ColorSketch from '@/mob/colorsketch'
+import './index.scss'
+
+const { TabPane } = Tabs
+const NormalForm = asyncComponent(() => import('@/menu/components/share/normalform'))
+
+class LineChartDrawerForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    plot: PropTypes.object,
+    config: PropTypes.object,
+    plotchange: PropTypes.func
+  }
+
+  state = {
+    view: 'normal',
+    visible: false,
+    plot: null,
+    formlist: null,
+    baseFormlist: null
+  }
+
+  showDrawer = () => {
+    const { config } = this.props
+
+    this.setState({
+      visible: true,
+      view: 'normal',
+      plot: fromJS(config.plot).toJS(),
+      baseFormlist: getBaseForm(config.plot),
+      formlist: getOptionForm(config.plot, config.columns)
+    })
+  }
+
+  getFields() {
+    const { formlist } = this.state
+    const { getFieldDecorator } = this.props.form
+    const fields = []
+
+    if (!formlist) {
+      return fields
+    }
+
+    formlist.forEach((item, index) => {
+      if (item.hidden || item.forbid) return
+      
+      if (item.type === 'text') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" disabled={item.readonly} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'number') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.input'] + item.label + '!'
+                  }
+                ]
+              })(<InputNumber min={item.min} max={item.max} precision={item.decimal} onPressEnter={this.onSubmit}/>)}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'select') { // 涓嬫媺
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Select mode={item.multi ? 'multiple' : ''}>
+                  {item.options.map((option, index) =>
+                    <Select.Option key={index} value={option.field || option.value}>
+                      {option.label || option.text}
+                    </Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'radio') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <Radio.Group disabled={item.readonly}>
+                  {item.options.map(option => {
+                    return (
+                      <Radio key={option.value} value={option.value}>{option.text}</Radio>
+                    )
+                  })}
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+        )
+      } else if (item.type === 'color') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.tooltip ?
+              <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(
+                <ColorSketch />
+              )}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    return fields
+  }
+
+  onSubmit = () => {
+    const { config } = this.props
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          let _plot = {...plot, ...values}
+
+          this.setState({
+            plot: _plot,
+            visible: false
+          })
+
+          this.props.plotchange({...config, plot: _plot})
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        let _plot = {...plot, ...res}
+
+        this.setState({
+          plot: _plot,
+          visible: false
+        })
+
+        this.props.plotchange({...config, plot: _plot})
+      })
+    }
+  }
+
+  changeTab = (tab) => {
+    const { plot, view } = this.state
+
+    if (view === 'normal') {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          this.setState({
+            plot: {...plot, ...values},
+            view: tab
+          })
+        }
+      })
+    } else if (view === 'base') {
+      this.baseRef.handleConfirm().then(res => {
+        this.setState({
+          plot: {...plot, ...res},
+          view: tab
+        })
+      })
+    }
+  }
+
+  render() {
+    const { view, visible, baseFormlist } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <div className="line-chart-drawer-form">
+        <Icon type="edit" title="缂栬緫" onClick={this.showDrawer} />
+        <Modal
+          wrapClassName="popview-modal menu-chart-edit-modal"
+          title="鍥捐〃缂栬緫"
+          visible={visible}
+          width={850}
+          maskClosable={false}
+          onOk={this.onSubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <Tabs activeKey={view} className="menu-chart-edit-box" onChange={this.changeTab}>
+            <TabPane tab="缁勪欢璁剧疆" key="base">
+              <NormalForm dict={this.props.dict} formlist={baseFormlist} inputSubmit={this.onSubmit} wrappedComponentRef={(inst) => this.baseRef = inst}/>
+            </TabPane>
+            <TabPane tab="鍥捐〃璁剧疆" key="normal">
+              <Form {...formItemLayout}>
+                <Row gutter={16}>{this.getFields()}</Row>
+              </Form>
+            </TabPane>
+          </Tabs>
+        </Modal>
+      </div>
+    );
+  }
+}
+
+export default Form.create()(LineChartDrawerForm)
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-scatter/chartcompile/index.scss b/src/menu/components/chart/antv-scatter/chartcompile/index.scss
new file mode 100644
index 0000000..5928db8
--- /dev/null
+++ b/src/menu/components/chart/antv-scatter/chartcompile/index.scss
@@ -0,0 +1,41 @@
+.line-chart-drawer-form {
+  display: inline-block;
+  > .anticon-edit {
+    color: #1890ff;
+  }
+}
+.menu-chart-edit-modal {
+  .ant-modal {
+    top: 50px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      min-height: 50vh;
+      padding-top: 10px;
+      .menu-chart-edit-box {
+        .anticon-question-circle {
+          color: #c49f47;
+          position: relative;
+          left: -3px;
+        }
+        .ant-input-number {
+          width: 100%;
+        }
+        .ant-tabs-nav-wrap {
+          text-align: center;
+        }
+        .color-sketch-block {
+          position: relative;
+          top: 5px;
+          width: 240px;
+        }
+        .color-add {
+          float: right;
+          margin-bottom: 10px;
+          position: relative;
+          z-index: 1;
+        }
+      }
+    }
+  }
+}
+
diff --git a/src/menu/components/chart/antv-scatter/index.jsx b/src/menu/components/chart/antv-scatter/index.jsx
new file mode 100644
index 0000000..a002498
--- /dev/null
+++ b/src/menu/components/chart/antv-scatter/index.jsx
@@ -0,0 +1,404 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, notification } from 'antd'
+import { Chart } from '@antv/g2'
+
+import MKEmitter from '@/utils/events.js'
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
+const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+
+class antvScatterChart extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    updateConfig: PropTypes.func,
+    deletecomponent: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    appType: sessionStorage.getItem('appType'),
+    eventListener: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _plot = {
+        width: card.width || 24,
+        height: 400,
+        gender: '',
+        Xaxis: '',
+        Xunit: '',
+        Yaxis: '',
+        Yunit: '',
+        shape: 'circle',
+        color: 'rgba(0, 0, 0, 0.65)',
+        name: card.name
+      }
+
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'array',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,   // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false, // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: _plot.width,
+        name: _plot.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        style: {
+          borderWidth: '1px', borderColor: 'rgb(217, 217, 217)',
+          marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
+        },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        scripts: [],
+        search: [],
+        action: [],
+        plot: _plot,
+        btnlog: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.plot = config.plot
+        _card.plot.name = card.name
+        _card.style = config.style
+        _card.headerStyle = config.headerStyle
+
+        _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.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('tabsChange', this.handleTabsChange)
+    setTimeout(() => {
+      this.ponitrender()
+    }, 1000)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+    MKEmitter.removeListener('tabsChange', this.handleTabsChange)
+  }
+
+  handleTabsChange = (parentId) => {
+    const { card } = this.state
+
+    if (parentId === card.parentId) {
+      let _element = document.getElementById(card.uuid + 'canvas')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(this.ponitrender, 100)
+    }
+  }
+
+  getdata = () => {
+    let data = []
+
+    for (let i = 0; i < 500; i++) {
+      let item = {}
+      let n = Math.random()
+      let m = Math.random()
+      if (n > 0.7) {
+        n = n * n
+      } else if (n < 0.3) {
+        n = Math.sqrt(n)
+      }
+      if (m > 0.7) {
+        m = m * m
+      } else if (m < 0.3) {
+        m = Math.sqrt(m)
+      }
+
+      if (i % 2 === 0) {
+        item.gender = 'male'
+        item.height = 160 + Math.floor(n * 35 * 10) / 10
+        item.weight = 50 + Math.floor(m * 55 * 10) / 10
+      } else {
+        item.gender = 'female'
+        item.height = 140 + Math.floor(n * 40 * 10) / 10
+        item.weight = 41 + Math.floor(m * 45 * 10) / 10
+      }
+
+      data.push(item)
+    }
+
+    return data
+  }
+
+  /**
+   * @description 鏁g偣鍥�
+   */
+  ponitrender = () => {
+    const { card } = this.state
+    const plot = card.plot
+    const data = this.getdata()
+    let height = plot.height - 25
+
+    if (card.plot.title || card.search.length > 0) {
+      height = plot.height - 70
+    }
+
+    const chart = new Chart({
+      container: card.uuid + 'canvas',
+      autoFit: true,
+      height: height
+    })
+
+    chart.data(data);
+    chart.scale({
+      height: { nice: true },
+      weight: { nice: true },
+    })
+    
+    // chart.axis('height', { label: { style: { fill: plot.color } }, tickLine: {style: { stroke: plot.color }}, line: { style: { stroke: plot.color } } })
+    // chart.axis('weight', { grid: { line: { style: { stroke: plot.color } }}, label: { style: { fill: plot.color } } })
+    chart.axis('height', { label: { style: { fill: plot.color } } })
+    chart.axis('weight', { label: { style: { fill: plot.color } } })
+    chart.legend({
+      position: plot.legend || 'bottom',
+      itemName: { style: { fill: plot.color } }
+    })
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        showTitle: false,
+        showCrosshairs: true,
+        crosshairs: {
+          type: 'xy',
+        }
+      })
+    }
+    
+    chart
+      .point()
+      .position('height*weight')
+      .color('gender')
+      .shape(plot.shape)
+      .tooltip('gender*height*weight', (gender, height, weight) => {
+        return {
+          name: gender,
+          value: height + (plot.Xunit ? `(${plot.Xunit}), ` : ', ') + weight + (plot.Yunit ? `(${plot.Yunit})` : '')
+        };
+      })
+      .style({
+        fillOpacity: 0.85
+      })
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
+    }
+    chart.render()
+  }
+
+  updateComponent = (component) => {
+    const card = fromJS(this.state.card).toJS()
+
+    if (!is(fromJS(component.plot), fromJS(card.plot)) || !is(fromJS(component.style), fromJS(card.style))) {
+      let _element = document.getElementById(card.uuid + 'canvas')
+      if (_element) {
+        _element.innerHTML = ''
+      }
+      this.$timer && clearTimeout(this.$timer)
+      this.$timer = setTimeout(() => {
+        this.ponitrender()
+      }, 150)
+    }
+
+    component.width = component.plot.width
+    component.name = component.plot.name
+    
+    this.setState({
+      card: component
+    })
+    this.props.updateConfig(component)
+  }
+
+  addSearch = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+
+    newcard.label = 'label'
+    newcard.initval = ''
+    newcard.type = 'select'
+    newcard.resourceType = '0'
+    newcard.options = []
+    newcard.setAll = 'false'
+    newcard.orderType = 'asc'
+    newcard.display = 'dropdown'
+    newcard.match = '='
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎼滅储
+    MKEmitter.emit('addSearch', card.uuid, newcard)
+  }
+
+  addButton = () => {
+    const { card } = this.state
+
+    let newcard = {}
+    newcard.uuid = Utils.getuuid()
+    newcard.focus = true
+    
+    newcard.label = '瀵煎嚭Excel'
+    newcard.sqlType = ''
+    newcard.Ot = 'requiredSgl'
+    newcard.OpenType = 'excelOut'
+    newcard.icon = 'download'
+    newcard.class = 'dgreen'
+    newcard.intertype = card.setting.interType
+    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.popClose = 'never'
+    newcard.errorTime = 10
+    newcard.verify = null
+    newcard.show = 'icon'
+
+    // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
+    MKEmitter.emit('addButton', card.uuid, newcard)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid || comIds.length > 1) return
+
+    let _card = {...card, style}
+
+    this.updateComponent(_card)
+  }
+
+  handleLog = (type, logs, item) => {
+    let card = fromJS(this.state.card).toJS()
+
+    if (type === 'revert') {
+      card.action = card.action ? [...card.action, item] : [item]
+      card.btnlog = logs
+
+      this.setState({ card })
+      this.props.updateConfig(card)
+      notification.success({
+        top: 92,
+        message: '鎭㈠鎴愬姛锛�',
+        duration: 2
+      })
+    } else {
+      card.btnlog = logs
+      this.setState({ card })
+      this.props.updateConfig(card)
+      notification.success({
+        top: 92,
+        message: '娓呴櫎鎴愬姛锛�',
+        duration: 2
+      })
+    }
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card, appType } = this.state
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-scatter-chart-edit-box" style={{..._style, height: card.plot.height || 400}} onClick={this.clickComponent} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle"/> : null}
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" /> : null}
+            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
+            <CopyComponent type="line" card={card}/>
+            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors"/>
+            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog}/>
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)}/>
+            <SettingComponent config={card} updateConfig={this.updateComponent}/>
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        {card.plot.title || card.search.length > 0 ? <NormalHeader config={card} updateComponent={this.updateComponent}/> : null}
+        <div className="canvas" id={card.uuid + 'canvas'}></div>
+        {appType !== 'mob' ? <ActionComponent type="chart" config={card} updateaction={this.updateComponent}/> : null}
+      </div>
+    )
+  }
+}
+
+export default antvScatterChart
\ No newline at end of file
diff --git a/src/menu/components/chart/antv-scatter/index.scss b/src/menu/components/chart/antv-scatter/index.scss
new file mode 100644
index 0000000..4403718
--- /dev/null
+++ b/src/menu/components/chart/antv-scatter/index.scss
@@ -0,0 +1,72 @@
+.menu-scatter-chart-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  
+  .canvas {
+    margin: 0px;
+    padding: 15px 10px 10px;
+    letter-spacing: 0px;
+    height: 100%;
+  }
+  .normal-header + .canvas {
+    height: calc(100% - 45px);
+  }
+
+  .chart-header {
+    position: relative;
+    height: 45px;
+    border-bottom: 1px solid #e8e8e8;
+    overflow: hidden;
+    padding-right: 35px;
+
+    .chart-title {
+      text-decoration: inherit;
+      font-weight: inherit;
+      font-style: inherit;
+      float: left;
+      line-height: 45px;
+      margin-left: 10px;
+      position: relative;
+      z-index: 1;
+    }
+  }
+
+  >.anticon-tool {
+    position: absolute;
+    right: 1px;
+    top: 1px;
+    z-index: 2;
+    font-size: 16px;
+    padding: 5px;
+    cursor: pointer;
+    color: rgba(0, 0, 0, 0.85);
+    background: rgba(255, 255, 255, 0.55);
+  }
+
+  .model-menu-action-list {
+    position: absolute;
+    right: 0px;
+    top: 30px;
+    z-index: 4;
+    font-size: 16px;
+  
+    .ant-row .anticon-plus {
+      float: right;
+    }
+  
+    .page-card {
+      float: right;
+    }
+  }
+  .normal-header + .canvas + .model-menu-action-list {
+    top: 45px;
+  }
+}
+.menu-scatter-chart-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/code/sandbox/index.jsx b/src/menu/components/code/sandbox/index.jsx
index 7e1fb66..e125817 100644
--- a/src/menu/components/code/sandbox/index.jsx
+++ b/src/menu/components/code/sandbox/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
@@ -152,8 +152,10 @@
 
   render() {
     const { card } = this.state
+    let _style = resetStyle(card.style)
+
     return (
-      <div className="menu-editor-sand-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-editor-sand-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <WrapComponent config={card} updateConfig={this.updateComponent} />
diff --git a/src/menu/components/form/formaction/actionform/index.jsx b/src/menu/components/form/formaction/actionform/index.jsx
index 454a16e..35fb01b 100644
--- a/src/menu/components/form/formaction/actionform/index.jsx
+++ b/src/menu/components/form/formaction/actionform/index.jsx
@@ -49,11 +49,11 @@
     const { card } = this.props
 
     if (card.type === 'prev') {
-      return ['type', 'label']
+      return ['type', 'label', 'enable']
     } else if (card.type === 'next') {
       return ['type', 'label', 'enable']
     }
-    let _options = ['type', 'label', 'intertype', 'syncComponent', 'linkmenu', 'open'] // 閫夐」鍒楄〃
+    let _options = ['type', 'label', 'intertype', 'syncComponent', 'linkmenu', 'open', 'enable'] // 閫夐」鍒楄〃
     
     if (_intertype === 'custom') {
       _options.push('procMode', 'interface', 'callbackType', 'cbTable', 'proInterface', 'method', 'cross')
diff --git a/src/menu/components/form/formaction/formconfig.jsx b/src/menu/components/form/formaction/formconfig.jsx
index 1a84804..6eb2048 100644
--- a/src/menu/components/form/formaction/formconfig.jsx
+++ b/src/menu/components/form/formaction/formconfig.jsx
@@ -10,7 +10,7 @@
  */
 
 export function getActionForm (card, functip, tableName, usefulFields, modules) {
-  const isApp = sessionStorage.getItem('appType') === 'pc'
+  const appType = sessionStorage.getItem('appType')
   let _type = '鎻愪氦'
   if (card.type === 'prev') {
     _type = '涓婁竴姝�'
@@ -19,7 +19,7 @@
   }
 
   let menulist = []
-  if (isApp) {
+  if (appType === 'pc' || appType === 'mob') {
     menulist = sessionStorage.getItem('appMenus')
     if (menulist) {
       try {
@@ -242,7 +242,7 @@
       readonly: false
     },
     {
-      type: isApp ? 'select' : 'cascader',
+      type: (appType === 'pc' || appType === 'mob') ? 'select' : 'cascader',
       key: 'linkmenu',
       label: '鎵撳紑鑿滃崟',
       tooltip: '鎵ц鎴愬姛鍚庨渶瑕佹墦寮�鐨勮彍鍗曘��',
@@ -256,7 +256,7 @@
       label: '鎵撳紑鏂瑰紡',
       initVal: card.open || 'blank',
       required: false,
-      forbid: !isApp,
+      forbid: appType !== 'pc',
       options: [{
         value: 'blank',
         text: '鏂扮獥鍙�'
@@ -278,7 +278,7 @@
       type: 'radio',
       key: 'enable',
       label: '鏄惁鏄剧ず',
-      initVal: card.enable || 'false',
+      initVal: card.enable || 'true',
       required: false,
       options: [{
         value: 'true',
diff --git a/src/menu/components/form/formaction/index.jsx b/src/menu/components/form/formaction/index.jsx
index fcbdb30..8127e42 100644
--- a/src/menu/components/form/formaction/index.jsx
+++ b/src/menu/components/form/formaction/index.jsx
@@ -7,6 +7,7 @@
 import enUS from '@/locales/en-US/model.js'
 import asyncComponent from '@/utils/asyncComponent'
 import { getActionForm } from './formconfig'
+import { resetStyle } from '@/utils/utils-custom.js'
 
 import MKEmitter from '@/utils/events.js'
 import MenuUtils from '@/utils/utils-custom.js'
@@ -23,6 +24,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,          // 缂栬緫涓厓绱�
     formlist: null,      // 琛ㄥ崟淇℃伅
     visible: false,      // 妯℃�佹鎺у埗
@@ -172,6 +174,21 @@
     })
   }
 
+  changeMenu = () => {
+    const { appType } = this.state
+    const { group } = this.props
+
+    if (appType !== 'pc' && appType !== 'mob') return
+    if (!group.subButton.linkmenu) return
+
+    MKEmitter.emit('changeEditMenu', {
+      MenuID: group.subButton.linkmenu,
+      copyMenuId: '',
+      MenuNo: '',
+      MenuName: '',
+    })
+  }
+
   render() {
     const { group, config } = this.props
     const { visible, profVisible, card, dict } = this.state
@@ -184,7 +201,7 @@
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => this.handleStyle(group.prevButton)} type="font-colors" />
           </div>
         } trigger="hover">
-          <Button type="link" className="prev" style={group.prevButton.style}>{group.prevButton.label}</Button>
+          <Button type="link" className={'prev ' + group.prevButton.enable} style={resetStyle(group.prevButton.style)}>{group.prevButton.label}</Button>
         </Popover> : null}
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
@@ -193,7 +210,7 @@
             <Icon className="profile" title="setting" type="profile" onClick={() => this.profileAction()} />
           </div>
         } trigger="hover">
-          <Button type="link" className="submit mk-primary" style={group.subButton.style}>{group.subButton.label}</Button>
+          <Button type="link" className="submit mk-primary" onDoubleClick={this.changeMenu} style={resetStyle(group.subButton.style)}>{group.subButton.label}</Button>
         </Popover>
         {group.sort !== config.subcards.length ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
@@ -201,7 +218,7 @@
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => this.handleStyle(group.nextButton)} type="font-colors" />
           </div>
         } trigger="hover">
-          <Button type="link" className={'skip ' + group.nextButton.enable} style={group.nextButton.style}>{group.nextButton.label}</Button>
+          <Button type="link" className={'skip ' + group.nextButton.enable} style={resetStyle(group.nextButton.style)}>{group.nextButton.label}</Button>
         </Popover> : null}
         {/* 缂栬緫鎸夐挳锛氬鍒躲�佺紪杈� */}
         <Modal
diff --git a/src/menu/components/form/formaction/index.scss b/src/menu/components/form/formaction/index.scss
index 1fa18b5..b7a1cd3 100644
--- a/src/menu/components/form/formaction/index.scss
+++ b/src/menu/components/form/formaction/index.scss
@@ -6,6 +6,11 @@
   .prev {
     margin-right: 15px;
   }
+  .prev.false {
+    span {
+      text-decoration: line-through;
+    }
+  }
   .submit {
     border: none;
   }
diff --git a/src/menu/components/form/normal-form/groupform/index.jsx b/src/menu/components/form/normal-form/groupform/index.jsx
index c1611f9..488cd6c 100644
--- a/src/menu/components/form/normal-form/groupform/index.jsx
+++ b/src/menu/components/form/normal-form/groupform/index.jsx
@@ -18,13 +18,22 @@
 
   UNSAFE_componentWillMount () {
     const { group } = this.props
+    const { appType } = this.state
     let fields = []
 
-    group.fields.forEach(f => {
-      if (f.field && ['select', 'link', 'text', 'number'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
-        fields.push(f)
-      }
-    })
+    if (appType === 'mob') {
+      group.fields.forEach(f => {
+        if (f.field && ['text', 'number'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
+          fields.push(f)
+        }
+      })
+    } else {
+      group.fields.forEach(f => {
+        if (f.field && ['select', 'link', 'text', 'number'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
+          fields.push(f)
+        }
+      })
+    }
 
     this.setState({
       fields: fields
@@ -55,7 +64,7 @@
   render() {
     const { group, dict } = this.props
     const { getFieldDecorator } = this.props.form
-    const { fields } = this.state
+    const { fields, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -123,7 +132,7 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={12}>
+          {appType !== 'mob' ? <Col span={12}>
             <Form.Item label="琛ㄥ崟鎺掑垪">
               {getFieldDecorator('align', {
                 initialValue: group.setting.align || 'left_right'
@@ -134,7 +143,7 @@
                 </Radio.Group>
               )}
             </Form.Item>
-          </Col>
+          </Col> : null}
         </Row>
       </Form>
     )
diff --git a/src/menu/components/form/normal-form/index.jsx b/src/menu/components/form/normal-form/index.jsx
index 1610711..eae27ac 100644
--- a/src/menu/components/form/normal-form/index.jsx
+++ b/src/menu/components/form/normal-form/index.jsx
@@ -8,16 +8,18 @@
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
 import { getModalForm } from '@/templates/zshare/formconfig'
-import ModalForm from '@/templates/zshare/modalform'
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import './index.scss'
 
+const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
 const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
 const WrapComponent = asyncIconComponent(() => import('@/menu/components/form/wrapsetting'))
 const CardComponent = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
+const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
 const FormTitle = asyncComponent(() => import('../dragtitle'))
 const GroupForm = asyncComponent(() => import('./groupform'))
 const FormAction = asyncComponent(() => import('../formaction'))
@@ -37,6 +39,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,
     back: false,
     group: null,
@@ -66,7 +69,7 @@
         name: card.name,
         subtype: card.subtype,
         setting: { },
-        wrap: { name: card.name, width: card.width || 24, datatype: 'static', color: '#1890ff' },
+        wrap: { name: card.name, width: card.width || 24, datatype: 'static', groupLabel: 'show', color: '#1890ff' },
         style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
         columns: [],
         scripts: [],
@@ -76,8 +79,8 @@
           sort: 1,
           style: {},
           fields: [],
-          prevButton: {label: '涓婁竴姝�', type: 'prev'},
-          subButton: {label: '鎻愪氦', type: 'submit', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
+          prevButton: {label: '涓婁竴姝�', type: 'prev', enable: 'true'},
+          subButton: {label: '鎻愪氦', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
           nextButton: {label: '璺宠繃', type: 'next', enable: 'false'}
         }]
       }
@@ -179,33 +182,6 @@
     this.props.updateConfig(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)
-        
-        let uuids = []
-        cell.elements && cell.elements.forEach(c => {
-          if (c.eleType === 'button') {
-            uuids.push(c.uuid)
-          }
-        })
-        MKEmitter.emit('delButtons', uuids)
-
-        _this.setState({card})
-        _this.props.updateConfig(card)
-      },
-      onCancel() {}
-    })
-  }
-
   changeStyle = () => {
     const { card } = this.state
 
@@ -235,8 +211,8 @@
       sort: card.subcards.length + 1,
       style: {},
       fields: [],
-      prevButton: {label: '涓婁竴姝�', type: 'prev'},
-      subButton: {label: '鎻愪氦', type: 'submit', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
+      prevButton: {label: '涓婁竴姝�', type: 'prev', enable: 'true'},
+      subButton: {label: '鎻愪氦', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
       nextButton: {label: '璺宠繃', type: 'next', enable: 'false'}
     }
 
@@ -362,7 +338,7 @@
     })
   }
 
-  handleList = (list) => {
+  handleList = (list, newcard) => {
     let group = fromJS(this.state.group).toJS()
     let card = fromJS(this.state.card).toJS()
 
@@ -375,7 +351,11 @@
       return item
     })
 
-    this.setState({card, group})
+    this.setState({card, group}, () => {
+      if (newcard) {
+        this.handleForm(newcard)
+      }
+    })
     this.props.updateConfig(card)
   }
 
@@ -404,9 +384,13 @@
   }
 
   addForm = () => {
+    const { appType } = this.state
     let group = fromJS(this.state.group).toJS()
     let lastItem = group.fields[group.fields.length - 1]
-    let span = lastItem ? lastItem.span : 12
+    let span = appType === 'mob' ? 24 : 12
+    if (lastItem && lastItem.span) {
+      span = lastItem.span
+    }
 
     let newcard = {
       uuid: Utils.getuuid(),
@@ -439,13 +423,14 @@
     group.fields = group.fields.filter(item => !item.focus)
 
     this.setState({group, visible: false, editform: null})
+    this.updateGroup(group)
   }
 
   /**
    * @description 琛ㄥ崟缂栬緫
    */
   handleForm = (_item) => {
-    const { card, group } = this.state
+    const { card, group, appType } = this.state
     let _form = fromJS(_item).toJS()
     let _inputfields = []
     let _tabfields = []
@@ -457,7 +442,11 @@
     let standardform = null
 
     _inputfields = group.fields.filter(item => item.type === 'text' || item.type === 'number' || item.type === 'textarea' || item.type === 'color')
-    _tabfields = group.fields.filter(item => _form.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
+    if (appType === 'mob') {
+      _tabfields = group.fields.filter(item => _form.field !== item.field && item.hidden !== 'true' && ['text', 'number'].includes(item.type))
+    } else {
+      _tabfields = group.fields.filter(item => _form.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
+    }
     _tabfields.unshift({field: '', text: '鍘熻〃鍗�'})
 
     let uniq = new Map()
@@ -467,7 +456,8 @@
       if (_form.uuid === item.uuid) {
         index = i
       }
-      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
+      
+      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
       if (item.field && !uniq.has(item.field)) {
         uniq.set(item.field, true)
 
@@ -505,7 +495,7 @@
       _form.linkSubField = _form.linkSubField.filter(item => fields.includes(item))
     }
 
-    if (!_form.span && standardform && standardform.span) {
+    if (appType !== 'mob' && !_form.span && standardform && standardform.span) {
       _form.span = standardform.span
       _form.labelwidth = standardform.labelwidth
     }
@@ -560,7 +550,7 @@
         return
       }
 
-      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
@@ -607,6 +597,47 @@
     })
   }
 
+  pasteForm = (res) => {
+    let _config = fromJS(this.state.group).toJS()
+    let fieldrepet = false // 瀛楁閲嶅
+    let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
+
+    _config.fields.forEach(item => {
+      if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
+        fieldrepet = true
+      } else if (res.label && item.label === res.label) {
+        labelrepet = true
+      }
+    })
+
+    if (fieldrepet) {
+      notification.warning({
+        top: 92,
+        message: '瀛楁宸插瓨鍦紒',
+        duration: 10
+      })
+      return
+    } else if (labelrepet) {
+      notification.warning({
+        top: 92,
+        message: '鍚嶇О宸插瓨鍦紒',
+        duration: 10
+      })
+      return
+    }
+    _config.fields.push(res)
+
+    this.updateGroup(_config)
+
+    this.handleForm(res)
+
+    notification.success({
+      top: 92,
+      message: '绮樿创鎴愬姛锛�',
+      duration: 2
+    })
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -615,16 +646,16 @@
   }
 
   render() {
-    const { card, dict, group } = this.state
+    const { card, dict, group, appType } = this.state
 
     return (
-      <div className="menu-normal-form-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-normal-form-edit-box" style={resetStyle(card.style)} onClick={this.clickComponent} id={card.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <Icon className="plus" title="娣诲姞鍒嗙粍" onClick={this.addCard} type="plus" />
             <WrapComponent config={card} updateConfig={this.updateComponent} />
             <CopyComponent type="propcard" card={card}/>
-            <PasteComponent config={card} options={['cardcell']} updateConfig={this.updateComponent} />
+            <PasteComponent config={card} options={['form']} updateConfig={this.pasteForm} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
             <UserComponent config={card}/>
             <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -646,12 +677,12 @@
           <Icon className="plus" title="娣诲姞琛ㄥ崟" onClick={this.addForm} type="plus" />
           <FieldsComponent config={group} type="form" updatefield={this.updateGroup} />
           <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
-          <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1鍒�</Button>
-          <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>
+          {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}
+          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3鍒�</Button> : null}
+          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4鍒�</Button> : null}
           <div style={{clear: 'both'}}></div>
-          <CardComponent
+          {appType !== 'mob' ? <CardComponent
             list={group.fields}
             setting={group.setting}
             showField={this.state.showField}
@@ -659,7 +690,14 @@
             handleList={this.handleList}
             handleForm={this.handleForm}
             closeForm={this.closeForm}
-          />
+          /> : <MobCardComponent
+            list={group.fields}
+            setting={group.setting}
+            showField={this.state.showField}
+            handleList={this.handleList}
+            handleForm={this.handleForm}
+            closeForm={this.closeForm}
+          />}
           <FormAction config={card} group={group} updateconfig={this.updateGroup}/>
         </div> : null}
         <Modal
diff --git a/src/menu/components/form/wrapsetting/settingform/index.jsx b/src/menu/components/form/wrapsetting/settingform/index.jsx
index 78d7589..ea4257c 100644
--- a/src/menu/components/form/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/form/wrapsetting/settingform/index.jsx
@@ -149,6 +149,23 @@
             </Col>
             <Col span={12}>
               <Form.Item label={
+                <Tooltip placement="topLeft" title="鍔犺浇鏃舵槸鍚︽樉绀哄垎缁勫悕绉般��">
+                  <Icon type="question-circle" />
+                  鍒嗙粍鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('groupLabel', {
+                  initialValue: wrap.groupLabel || 'show'
+                })(
+                  <Radio.Group>
+                    <Radio value="show">鏄剧ず</Radio>
+                    <Radio value="hidden">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
                 <Tooltip placement="topLeft" title="瀹屾垚鍚庣殑棰滆壊">
                   <Icon type="question-circle" />
                   棰滆壊鎺у埗
diff --git a/src/menu/components/form/wrapsetting/settingform/index.scss b/src/menu/components/form/wrapsetting/settingform/index.scss
index a85d1ac..65d3417 100644
--- a/src/menu/components/form/wrapsetting/settingform/index.scss
+++ b/src/menu/components/form/wrapsetting/settingform/index.scss
@@ -9,6 +9,7 @@
     width: 100%;
   }
   .color-sketch-block {
-    margin-top: 6px;
+    position: relative;
+    top: 6px;
   }
 }
\ No newline at end of file
diff --git a/src/menu/components/group/groupcomponents/card.jsx b/src/menu/components/group/groupcomponents/card.jsx
index 99d3e95..ec99ddf 100644
--- a/src/menu/components/group/groupcomponents/card.jsx
+++ b/src/menu/components/group/groupcomponents/card.jsx
@@ -9,8 +9,15 @@
 const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
 const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
+const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
+const AntvScatter = asyncComponent(() => import('@/menu/components/chart/antv-scatter'))
+const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
+const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
+const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
+const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
+const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -50,6 +57,14 @@
       return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'dashboard') {
+      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'tree') {
+      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'scatter') {
+      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'form') {
+      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'card' && card.subtype === 'datacard') {
       return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'card' && card.subtype === 'propcard') {
@@ -58,8 +73,14 @@
       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 === 'carousel' && card.subtype === 'datacard') {
+      return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'carousel' && card.subtype === 'propcard') {
+      return (<CarouselPropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'code') {
+      return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/group/groupcomponents/index.jsx b/src/menu/components/group/groupcomponents/index.jsx
index 7a8719e..ac14bfa 100644
--- a/src/menu/components/group/groupcomponents/index.jsx
+++ b/src/menu/components/group/groupcomponents/index.jsx
@@ -6,6 +6,7 @@
 
 import Utils from '@/utils/utils.js'
 import MKEmitter from '@/utils/events.js'
+import MenuUtils from '@/utils/utils-custom.js'
 import Card from './card'
 import './index.scss'
 
@@ -38,49 +39,16 @@
   const deleteCard = (id) => {
     const { card } = findCard(id)
 
-    let uuids = []
-    if (card.action && card.action.length) {
-      card.action.forEach(act => {
-        if (!act.origin) {
-          uuids.push(act.uuid)
-        }
-      })
-    }
-    if (card.type === 'card') {
-      card.subcards.forEach(_card => {
-        _card.elements && _card.elements.forEach(cell => {
-          if (cell.eleType === 'button') {
-            uuids.push(cell.uuid)
-          }
-        })
-        _card.backElements && _card.backElements.forEach(cell => {
-          if (cell.eleType === 'button') {
-            uuids.push(cell.uuid)
-          }
-        })
-      })
-    } else if (card.type === 'table' && card.subtype === 'tablecard') {
-      card.subcards.forEach(_card => {
-        _card.elements && _card.elements.forEach(cell => {
-          if (cell.eleType === 'button') {
-            uuids.push(cell.uuid)
-          }
-        })
-      })
-    } else if (card.type === 'table' && card.subtype === 'normaltable') {
-      card.cols && card.cols.forEach(col => {
-        if (col.type !== 'action') return
-        col.elements && col.elements.forEach(cell => {
-          uuids.push(cell.uuid)
-        })
-      })
-    }
+    let uuids = MenuUtils.getDelButtonIds(card)
 
     confirm({
       title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
       onOk() {
-        MKEmitter.emit('delButtons', uuids)
         handleList({...config, components: cards.filter(item => item.uuid !== card.uuid)})
+
+        if (uuids.length === 0) return
+
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -99,11 +67,20 @@
 
       let name = ''
       let names = {
-        bar: '鏌辩姸鍥�',
+        bbar: '鏌辩姸鍥�',
         line: '鎶樼嚎鍥�',
+        tabs: '鏍囩缁�',
         pie: '楗煎浘',
+        search: '鎼滅储',
         table: '琛ㄦ牸',
+        group: '鍒嗙粍',
         editor: '瀵屾枃鏈�',
+        code: '鑷畾涔�',
+        carousel: '杞挱',
+        form: '琛ㄥ崟',
+        dashboard: '浠〃鐩�',
+        scatter: '鏁g偣鍥�',
+        tree: '鏍戝舰鍒楄〃',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/components/group/groupcomponents/index.scss b/src/menu/components/group/groupcomponents/index.scss
index ad63183..b739fe0 100644
--- a/src/menu/components/group/groupcomponents/index.scss
+++ b/src/menu/components/group/groupcomponents/index.scss
@@ -1,9 +1,6 @@
 .group-shell-inner {
-  margin: -8px;
+  margin: 0px;
 
-  >.ant-col {
-    padding: 8px;
-  }
   .anticon {
     cursor: unset;
   }
diff --git a/src/menu/components/group/groupsetting/settingform/index.jsx b/src/menu/components/group/groupsetting/settingform/index.jsx
index e8240e5..bfbacf7 100644
--- a/src/menu/components/group/groupsetting/settingform/index.jsx
+++ b/src/menu/components/group/groupsetting/settingform/index.jsx
@@ -13,6 +13,7 @@
 
   state = {
     roleList: [],
+    appType: sessionStorage.getItem('appType'),
     print: this.props.setting.print || 'false'
   }
 
@@ -55,7 +56,7 @@
   render() {
     const { setting, dict } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList, print } = this.state
+    const { roleList, print, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -108,7 +109,7 @@
                 })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit}/>)}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label="鎵撳嵃鎸夐挳">
                 {getFieldDecorator('print', {
                   initialValue: print
@@ -119,8 +120,8 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
-            {print === 'true' ? <Col span={12}>
+            </Col> : null}
+            {print === 'true' && appType !== 'mob' ? <Col span={12}>
               <Form.Item label="鎵撳嵃灏哄">
                 {getFieldDecorator('pageSize', {
                   initialValue: setting.pageSize || 'A4',
@@ -139,7 +140,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {print === 'true' ? <Col span={12}>
+            {print === 'true' && appType !== 'mob' ? <Col span={12}>
               <Form.Item label="鎵撳嵃甯冨眬">
                 {getFieldDecorator('pageLayout', {
                   initialValue: setting.pageLayout || 'vertical',
diff --git a/src/menu/components/group/normal-group/index.jsx b/src/menu/components/group/normal-group/index.jsx
index c6021fa..a0ac08f 100644
--- a/src/menu/components/group/normal-group/index.jsx
+++ b/src/menu/components/group/normal-group/index.jsx
@@ -6,7 +6,7 @@
 import MKEmitter from '@/utils/events.js'
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import './index.scss'
@@ -161,9 +161,15 @@
 
   render() {
     const { group } = this.state
+    let _style = resetStyle(group.style)
+
+    let paddingTop = true
+    if (group.style.paddingTop && parseInt(group.style.paddingTop) >= 28) {
+      paddingTop = false
+    }
 
     return (
-      <div className="menu-group-edit-box" style={group.style} onClick={this.clickComponent} id={group.uuid}>
+      <div className={'menu-group-edit-box' + (paddingTop ? ' padding' : '')} style={_style} onClick={this.clickComponent} id={group.uuid}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <SettingComponent config={group} updateConfig={this.updateComponent} />
diff --git a/src/menu/components/group/normal-group/index.scss b/src/menu/components/group/normal-group/index.scss
index 7af5313..54c6b75 100644
--- a/src/menu/components/group/normal-group/index.scss
+++ b/src/menu/components/group/normal-group/index.scss
@@ -26,7 +26,7 @@
     color: #bcbcbc;
   }
 }
-.menu-group-edit-box::before {
+.menu-group-edit-box.padding:before {
   content: ' ';
   display: block;
   float: right;
diff --git a/src/menu/components/search/main-search/dragsearch/card.jsx b/src/menu/components/search/main-search/dragsearch/card.jsx
index 47a7283..9a93ae5 100644
--- a/src/menu/components/search/main-search/dragsearch/card.jsx
+++ b/src/menu/components/search/main-search/dragsearch/card.jsx
@@ -3,12 +3,16 @@
 import { Icon, Select, DatePicker, Input, Popover, Form } from 'antd'
 import moment from 'moment'
 
+import asyncComponent from '@/utils/asyncComponent'
 import DateGroup from '../dategroup'
 import './index.scss'
 
 const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+const { Search } = Input
+const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard'))
+const appType = sessionStorage.getItem('appType')
 
-const Card = ({ id, card, moveCard, copyCard, findCard, editCard, delCard }) => {
+const Card = ({ id, card, showField, moveCard, copyCard, findCard, editCard, delCard }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'search', id, originalIndex },
@@ -55,6 +59,38 @@
     }
   }
 
+  let formItem = null
+  if (card.type === 'text') {
+    if (card.inputType === 'search') {
+      formItem = (<Search style={{marginTop: '4px'}} placeholder={card.labelShow === 'false' ? card.label : ''} value={card.initval} enterButton />)
+    } else {
+      formItem = (<Input style={{marginTop: '4px'}} placeholder={card.labelShow === 'false' ? card.label : ''} value={card.initval} />)
+    }
+  } else if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') {
+    formItem = (<Select value={_defaultValue}></Select>)
+  } else if (card.type === 'date' && appType === 'mob') {
+    formItem = (<div className="mob-list-item">{card.initval ? moment().subtract(card.initval, 'days').format('YYYY-MM-DD') : '璇烽�夋嫨'}<Icon type="right" /></div>)
+  } else if (card.type === 'datemonth' && appType === 'mob') {
+    formItem = (<div className="mob-list-item">{card.initval ? moment().subtract(card.initval, 'month').format('YYYY-MM') : '璇烽�夋嫨'}<Icon type="right" /></div>)
+  } else if (card.type === 'date') {
+    formItem = (<Input style={{marginTop: '4px'}} placeholder={card.labelShow === 'false' ? card.label : ''} value={card.initval} />)
+  } else if (card.type === 'dateweek') {
+    formItem = (<WeekPicker value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} />)
+  } else if (card.type === 'datemonth') {
+    formItem = (<MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} />)
+  } else if (card.type === 'daterange') {
+    formItem = (<RangePicker
+      className="data-range"
+      placeholder={['BeginTime', 'EndTime']}
+      renderExtraFooter={() => 'extra footer'}
+      value={_defaultValue}
+    />)
+  } else if (card.type === 'group') {
+    formItem = (<DateGroup card={card} />)
+  } else if (card.type === 'checkcard') {
+    formItem = <CheckCard config={card} />
+  }
+
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
@@ -63,38 +99,16 @@
         <Icon className="close" title="delete" type="close" onClick={() => delCard(id)} />
       </div>
     } trigger="hover">
-      <div className={'page-card ' + card.labelShow} style={{ opacity: opacity}}>
+      <div className={'page-card ' + card.labelShow + ' ' + card.type} style={{ opacity: opacity}}>
         <div ref={node => drag(drop(node))}>
           <Form.Item
             labelCol={{xs: { span: 24 }, sm: { span: 8 }}}
             wrapperCol = {{xs: { span: 24 }, sm: { span: 16 }}}
             label={card.labelShow !== 'false' ? card.label : ''}
             required={card.required === 'true'}
+            help={showField ? card.field + (card.datefield ? ', ' + card.datefield : '') : ''}
           >
-            {card.type === 'text' ?
-              <Input style={{marginTop: '4px'}} placeholder={card.labelShow === 'false' ? card.label : ''} value={card.initval} /> : null
-            }
-            {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
-              <Select value={_defaultValue}></Select> : null
-            }
-            {card.type === 'date' ?
-              <DatePicker value={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
-            }
-            {card.type === 'dateweek' ?
-              <WeekPicker value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
-            }
-            {card.type === 'datemonth' ?
-              <MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
-            }
-            {card.type === 'daterange' ?
-              <RangePicker
-                className="data-range"
-                placeholder={['BeginTime', 'EndTime']}
-                renderExtraFooter={() => 'extra footer'}
-                value={_defaultValue}
-              /> : null
-            }
-            {card.type === 'group' ? <DateGroup card={card} /> : null }
+            {formItem}
           </Form.Item>
         </div>
       </div>
diff --git a/src/menu/components/search/main-search/dragsearch/index.jsx b/src/menu/components/search/main-search/dragsearch/index.jsx
index 4193afa..ae6179e 100644
--- a/src/menu/components/search/main-search/dragsearch/index.jsx
+++ b/src/menu/components/search/main-search/dragsearch/index.jsx
@@ -7,7 +7,7 @@
 import Card from './card'
 import './index.scss'
 
-const Container = ({list, placeholder, handleList, handleMenu, deleteMenu }) => {
+const Container = ({list, showField, placeholder, handleList, handleMenu, deleteMenu }) => {
   const [cards, setCards] = useState(list)
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
@@ -77,13 +77,27 @@
     drop() {}
   })
 
+  const appType = sessionStorage.getItem('appType')
+
   return (
     <div ref={drop} className="ant-row">
+      {cards.length > 0 ? <Col key="preaction" className="action pre-action" span={6}>
+        <div className="ant-row ant-form-item" style={{lineHeight: '40px', height: '55px', marginBottom: 0}}>
+          <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
+          </div>
+          <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
+            <Button type="primary">鎼滅储</Button>
+            {appType !== 'mob' ? <Button style={{ marginLeft: 8 }}>閲嶇疆</Button> : null}
+            <div style={{position: 'absolute', top: 0, bottom: 0, left: 0, right: 0}}></div>
+          </div>
+        </div>
+      </Col> : null}
       {cards.map(card => (
         <Col key={card.uuid} span={card.ratio || 6}>
           <Card
             id={`${card.uuid}`}
             card={card}
+            showField={showField}
             moveCard={moveCard}
             copyCard={copyCard}
             editCard={editCard}
@@ -92,13 +106,13 @@
           />
         </Col>
       ))}
-      {cards.length > 0 ? <Col key="action" className="action" span={6}>
+      {cards.length > 0 ? <Col key="nextaction" className="action next-action" span={6}>
         <div className="ant-row ant-form-item" style={{lineHeight: '40px', height: '55px', marginBottom: 0}}>
           <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
           </div>
           <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
             <Button type="primary">鎼滅储</Button>
-            <Button style={{ marginLeft: 8 }}>閲嶇疆</Button>
+            {appType !== 'mob' ? <Button style={{ marginLeft: 8 }}>閲嶇疆</Button> : null}
             <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 0ab9015..2de3892 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, Icon } from 'antd'
+import { Modal, notification, Popover, Icon, Switch } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -9,9 +9,8 @@
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
 import { getSearchForm } from '@/templates/zshare/formconfig'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-import SearchForm from '@/templates/sharecomponent/searchcomponent/searchform'
 import DragElement from './dragsearch'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
@@ -19,6 +18,7 @@
 const { confirm } = Modal
 
 const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+const SearchForm = asyncIconComponent(() => import('@/templates/sharecomponent/searchcomponent/searchform'))
 const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
 const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
 
@@ -31,9 +31,11 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     searchlist: null,    // 鎼滅储鏉′欢闆�
     sqlVerifing: false,  // sql楠岃瘉涓�
     visible: false,      // 妯℃�佹鎺у埗
+    showField: false,
     editcard: null       // 缂栬緫涓厓绱�
   }
 
@@ -53,7 +55,7 @@
         width: 24,
         name: card.name,
         subtype: card.subtype,
-        wrap: { name: card.name, width: 24, show: 'true', float: 'left' },
+        wrap: { name: card.name, width: 24, show: this.state.appType === 'mob' ? 'false' : 'true', float: 'left' },
         style: {
           marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
         },
@@ -120,6 +122,20 @@
     component.name = component.wrap.name
 
     this.props.updateConfig(component)
+  }
+
+  checkComponent = (component) => {
+    this.updateComponent(component)
+
+    let _item = null
+    component.search.forEach(item => {
+      if (!_item && item.focus) {
+        _item = item
+      }
+    })
+    if (_item) {
+      this.handleSearch(_item)
+    }
   }
 
   /**
@@ -248,7 +264,7 @@
         return
       }
 
-      if (['select', 'multiselect', 'link'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
@@ -339,6 +355,14 @@
     })
   }
 
+  onFieldChange = () => {
+    const { showField } = this.state
+
+    this.setState({
+      showField: !showField
+    })
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -347,12 +371,15 @@
   }
 
   render() {
-    const { dict, card, visible, sqlVerifing } = this.state
+    const { dict, card, visible, sqlVerifing, showField } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className={`main-search-edit-list ${card.wrap.float} ${card.wrap.show || ''}`} onClick={this.clickComponent} id={card.uuid} style={card.style}>
+      <div className={`main-search-edit-list ${card.wrap.float} ${card.wrap.show || ''}`} onClick={this.clickComponent} id={card.uuid} style={_style}>
+        <Switch checkedChildren={dict['model.switch.open']} size="small" unCheckedChildren={dict['model.switch.close']} defaultChecked={showField} onChange={this.onFieldChange} />
         <DragElement
           list={card.search}
+          showField={showField}
           handleList={this.handleList}
           handleMenu={this.handleSearch}
           deleteMenu={this.deleteElement}
@@ -363,7 +390,7 @@
             <Icon className="plus" title="娣诲姞" onClick={this.addSearch} type="plus" />
             <WrapComponent config={card} updateConfig={this.updateComponent}/>
             <CopyComponent type="mainsearch" card={card}/>
-            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.updateComponent} />
+            <PasteComponent config={card} options={['search', 'form']} updateConfig={this.checkComponent} />
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
             <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
           </div>
diff --git a/src/menu/components/search/main-search/index.scss b/src/menu/components/search/main-search/index.scss
index 6d9928c..09caf96 100644
--- a/src/menu/components/search/main-search/index.scss
+++ b/src/menu/components/search/main-search/index.scss
@@ -2,7 +2,17 @@
   min-height: 50px;
   position: relative;
   background: #ffffff;
+  padding-bottom: 15px;
 
+  .ant-form-item-control {
+    line-height: 1.5;
+  }
+  >.ant-switch {
+    position: absolute;
+    z-index: 3;
+    right: 10px;
+    bottom: 5px;
+  }
   >.anticon-tool {
     position: absolute;
     z-index: 3;
@@ -15,9 +25,16 @@
   }
   > .ant-row {
     min-height: 65px;
+    > .ant-col {
+      padding: 0 12px!important;
+    }
   }
-  .ant-row .ant-col-6 {
-    padding: 0 12px!important;
+  >.ant-row:not(.ant-form-item) {
+    > .ant-col {
+      display: inline-block;
+      float: none;
+      vertical-align: top;
+    }
   }
   .ant-row.ant-form-item .ant-col {
     padding: 0;
@@ -73,14 +90,31 @@
     min-width: 100px!important;
     width: 100%;
   }
+  .check-card-edit-box {
+    margin-top: 5px!important;
+  }
+  .mob-list-item {
+    text-align: right;
+    line-height: 40px;
+    white-space: nowrap;
+    padding-right: 5px;
+    i {
+      margin-left: 5px;
+    }
+  }
+}
+.main-search-edit-list:not(.right) {
+  .pre-action {
+    display: none!important;
+  }
 }
 .main-search-edit-list.right {
+  .next-action {
+    display: none!important;
+  }
   >.ant-row {
     >.ant-col {
       float: right;
-    }
-    >.ant-col.action {
-      display: none;
     }
   }
 }
diff --git a/src/menu/components/search/main-search/wrapsetting/settingform/index.jsx b/src/menu/components/search/main-search/wrapsetting/settingform/index.jsx
index 9d728db..1789480 100644
--- a/src/menu/components/search/main-search/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/search/main-search/wrapsetting/settingform/index.jsx
@@ -12,8 +12,8 @@
   }
 
   state = {
-    float: this.props.wrap.float,
-    roleList: []
+    roleList: [],
+    appType: sessionStorage.getItem('appType')
   }
 
   UNSAFE_componentWillMount () {
@@ -55,7 +55,7 @@
   render() {
     const { wrap } = this.props
     const { getFieldDecorator } = this.props.form
-    const { float, roleList } = this.state
+    const { roleList, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -108,6 +108,18 @@
                 })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit}/>)}
               </Form.Item>
             </Col>
+            {appType !== 'mob' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="楂樼骇鎼滅储寮圭獥鐨勫搴︼紝娉細褰撳搴﹀�煎皬浜�100鏃惰〃绀哄崰绐楀彛鐨勭櫨鍒嗘瘮锛屽ぇ浜�100鏃惰〃绀哄搴︾殑缁濆鍊笺��">
+                  <Icon type="question-circle" />
+                  楂樼骇鎼滅储
+                </Tooltip>
+              }>
+                {getFieldDecorator('advanceWidth', {
+                  initialValue: wrap.advanceWidth || 1000
+                })(<InputNumber min={10} max={3000} precision={0}/>)}
+              </Form.Item>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="鍙冲榻愭椂锛岄殣钘忔悳绱㈡寜閽��">
@@ -118,14 +130,14 @@
                 {getFieldDecorator('float', {
                   initialValue: wrap.float || 'left'
                 })(
-                  <Radio.Group onChange={(e) => this.setState({float: e.target.value})}>
+                  <Radio.Group>
                     <Radio value="left">宸﹀榻�</Radio>
                     <Radio value="right">鍙冲榻�</Radio>
                   </Radio.Group>
                 )}
               </Form.Item>
             </Col>
-            {float !== 'right' ? <Col span={12}>
+            <Col span={12}>
               <Form.Item label="鎼滅储鎸夐挳">
                 {getFieldDecorator('show', {
                   initialValue: wrap.show || 'true'
@@ -136,7 +148,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col> : null}
+            </Col>
             <Col span={12}>
               <Form.Item label="榛戝悕鍗�">
                 {getFieldDecorator('blacklist', {
diff --git a/src/menu/components/share/actioncomponent/actionform/index.jsx b/src/menu/components/share/actioncomponent/actionform/index.jsx
index f7494bf..26122e5 100644
--- a/src/menu/components/share/actioncomponent/actionform/index.jsx
+++ b/src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -2,15 +2,17 @@
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
 import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Cascader } from 'antd'
-import { btnIcons, btnCustomClasses, formRule } from '@/utils/option.js'
+import { btnCustomClasses, formRule } from '@/utils/option.js'
 
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
 const { TextArea } = Input
+const MkIcon = asyncComponent(() => import('@/components/mkIcon'))
 const actionTypeOptions = {
-  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width'],
-  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width'],
-  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width'],
+  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width', 'openmenu', 'open'],
+  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width', 'openmenu', 'open'],
+  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width', 'openmenu', 'open'],
   excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'sheet', 'execSuccess', 'execError', 'resetPageIndex', 'syncComponent', 'width'],
   excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent', 'resetPageIndex', 'pagination', 'search', 'width'],
   popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'popClose', 'resetPageIndex', 'width'],
@@ -35,6 +37,8 @@
     interType: null, // 鎺ュ彛绫诲瀷锛氬唴閮ㄣ�佸閮�
     funcType: null,  // 鍔熻兘绫诲瀷
     procMode: null,  // 鍙傛暟鏂瑰紡
+    pageTemplate: null,
+    Ot: null,
     requireOptions: [{
       value: 'notRequired',
       text: this.props.dict['header.form.notRequired']
@@ -90,15 +94,19 @@
     let _opentype = card.OpenType                // 鎵撳紑鏂瑰紡
     let _intertype = card.intertype || 'system'  // 鎺ュ彛绫诲瀷
     let _funcType = card.funcType || ''          // 鍔熻兘鎸夐挳榛樿绫诲瀷
-    let _procMode = card.procMode || 'system'    // 鍙傛暟璇锋眰鏂瑰紡
+    let _procMode = card.procMode || 'system'
+    let _Ot = card.Ot || 'requiredSgl'
+    let _pageTemplate = card.pageTemplate || ''
 
-    let _options = this.getOptions(_opentype, _intertype, _funcType, card.pageTemplate, _procMode)
+    let _options = this.getOptions(_opentype, _intertype, _funcType, _pageTemplate, _procMode, _Ot)
 
     this.setState({
+      Ot: _Ot,
       openType: _opentype,
       interType: _intertype,
       procMode: _procMode,
       funcType: _funcType,
+      pageTemplate: _pageTemplate,
       formlist: this.props.formlist.map(item => {
         if (item.key === 'class') {
           item.options = btnCustomClasses
@@ -107,12 +115,10 @@
         } else if (item.key === 'intertype') {
           let iscustom = ['pop', 'prompt', 'exec'].includes(_opentype)
           item.options = this.state.interTypeOptions.filter(op => (iscustom || op.value !== 'custom'))
-        } else if (item.key === 'icon') {
-          item.options = btnIcons
         } else if (item.key === 'Ot') {
           if (type === 'card') {
             item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
-          } else if (card.pageTemplate === 'pay') { // 琛岀骇鎸夐挳銆佹敮浠樻寜閽紝鍙兘閫夊崟琛�
+          } else if (_pageTemplate === 'pay') { // 琛岀骇鎸夐挳銆佹敮浠樻寜閽紝鍙兘閫夊崟琛�
             item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value))
           } else if (['innerpage', 'tab', 'popview', 'excelIn'].includes(_opentype)) {
             item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
@@ -137,8 +143,8 @@
     })
   }
 
-  getOptions = (_opentype, _intertype, _funcType, _pageTemplate, _procMode) => {
-    let _options = fromJS(actionTypeOptions[_opentype]).toJS() // 閫夐」鍒楄〃
+  getOptions = (_opentype, _intertype, _funcType, _pageTemplate, _procMode, _Ot) => {
+    let _options = actionTypeOptions[_opentype] ? fromJS(actionTypeOptions[_opentype]).toJS() : [] // 閫夐」鍒楄〃
     
     if (_opentype === 'innerpage') {         // 鏂伴〉闈紝鍙�夋ā鏉�(鑷畾涔夋椂锛屽彲濉叆澶栭儴閾炬帴)
       if (_pageTemplate === 'custom') {
@@ -186,6 +192,13 @@
       }
     }
 
+    if (_Ot !== 'notRequired' && _opentype !== 'excelOut') {
+      _options.push('controlField', 'controlVal')
+    }
+    if (_Ot === 'requiredSgl' && ['pop', 'prompt', 'exec'].includes(_opentype)) {
+      _options.push('swipe')
+    }
+
     return _options
   }
 
@@ -210,13 +223,12 @@
    */
   optionChange = (key, value) => {
     const { card, type } = this.props
-    const { openType, procMode } = this.state
+    const { openType, procMode, Ot, pageTemplate } = this.state
 
     if (key === 'OpenType') {
-      let _options = this.getOptions(value, 'system', this.state.funcType, card.pageTemplate, 'system')
+      let _options = this.getOptions(value, 'system', this.state.funcType, '', 'system', Ot)
 
       let _fieldval = {}
-      
       let _formlist = this.state.formlist.map(item => {
         item.hidden = !_options.includes(item.key)
 
@@ -248,6 +260,8 @@
             item.options = this.state.insertUpdateOptions
           }
           _fieldval.sqlType = ''
+        } else if (item.key === 'pageTemplate') {
+          item.initVal = ''
         }
 
         return item
@@ -257,6 +271,7 @@
         openType: value,
         intertype: 'system',
         procMode: 'system',
+        pageTemplate: '',
         formlist: _formlist
       }, () => {
         if (value === 'excelIn') {
@@ -270,7 +285,7 @@
         this.props.form.setFieldsValue(_fieldval)
       })
     } else if (key === 'funcType') {
-      let _options = this.getOptions(openType, this.state.interType, value, card.pageTemplate, procMode)
+      let _options = this.getOptions(openType, this.state.interType, value, pageTemplate, procMode, Ot)
       let _fieldval = {}
 
       this.setState({
@@ -334,9 +349,10 @@
       })
     } else if (key === 'pageTemplate') {
       let _fieldval = {}
-      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, value, procMode)
+      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, value, procMode, Ot)
 
       this.setState({
+        pageTemplate: value,
         formlist: this.state.formlist.map(item => {
           item.hidden = !_options.includes(item.key)
 
@@ -357,7 +373,7 @@
         this.props.form.setFieldsValue(_fieldval)
       })
     } else if (key === 'intertype') {
-      let _options = this.getOptions(openType, value, this.state.funcType, '', procMode)
+      let _options = this.getOptions(openType, value, this.state.funcType, pageTemplate, procMode, Ot)
 
       this.setState({
         interType: value,
@@ -379,7 +395,7 @@
         })
       })
     } else if (key === 'procMode') {
-      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, '', value)
+      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, pageTemplate, value, Ot)
 
       this.setState({
         procMode: value,
@@ -389,6 +405,16 @@
           if (item.key === 'innerFunc') {
             item.required = true
           }
+          return item
+        })
+      })
+    } else if (key === 'Ot') {
+      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, pageTemplate, procMode, value)
+
+      this.setState({
+        Ot: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
           return item
         })
       })
@@ -503,7 +529,7 @@
             </Form.Item>
           </Col>
         )
-      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+      } else if (item.type === 'select') {
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.tooltip ?
@@ -523,13 +549,14 @@
               })(
                 <Select
                   showSearch
-                  filterOption={(input, option) => option.props.children[2].toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  allowClear={item.allowClear === true}
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                   onChange={(value) => {this.optionChange(item.key, value)}}
                   getPopupContainer={() => document.getElementById('winter')}
                 >
                   {item.options.map((option, index) =>
-                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
-                      {item.key === 'icon' && option.value && <Icon type={option.value} />} {option.text}
+                    <Select.Option key={index} value={(option.value || option.field)}>
+                      {(option.text || option.label)}
                     </Select.Option>
                   )}
                 </Select>
@@ -602,6 +629,24 @@
             </Form.Item>
           </Col>
         )
+      } else if (item.type === 'icon') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label}>
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal,
+                rules: [
+                  {
+                    required: !!item.required,
+                    message: this.props.dict['form.required.select'] + item.label + '!'
+                  }
+                ]
+              })(
+                <MkIcon allowClear/>
+              )}
+            </Form.Item>
+          </Col>
+        )
       } else if (item.type === 'mcascader') {
         fields.push(
           <Col span={12} key={index}>
@@ -627,6 +672,7 @@
         if (!err) {
           values.uuid = card.uuid
           values.verify = card.verify || null
+          values.modal = card.modal || null
 
           if (values.show === 'icon' && !values.icon) {
             notification.warning({
diff --git a/src/menu/components/share/actioncomponent/dragaction/card.jsx b/src/menu/components/share/actioncomponent/dragaction/card.jsx
index 8bdf734..d0af55e 100644
--- a/src/menu/components/share/actioncomponent/dragaction/card.jsx
+++ b/src/menu/components/share/actioncomponent/dragaction/card.jsx
@@ -1,6 +1,7 @@
 import React from 'react'
 import { useDrag, useDrop } from 'react-dnd'
 import { Icon, Button, Popover } from 'antd'
+import { resetStyle } from '@/utils/utils-custom.js'
 import './index.scss'
 
 const Card = ({ id, card, moveCard, findCard, editCard, delCard, copyCard, changeStyle, profileCard, doubleClickCard }) => {
@@ -36,12 +37,13 @@
   }
 
   let btnElement = null
+  let _style = resetStyle(card.style)
   if (card.show === 'icon') {
     btnElement = (
       <Button
         type="link"
         icon={card.icon}
-        style={card.btnstyle}
+        style={_style}
         onDoubleClick={() => doubleClickCard(id)}
       >{card.icon ? '' : card.label}</Button>
     )
@@ -49,7 +51,7 @@
     btnElement = (
       <Button
         type="link"
-        style={card.btnstyle}
+        style={_style}
         onDoubleClick={() => doubleClickCard(id)}
       >{card.label}{card.icon ? <Icon type={card.icon}/> : null}</Button>
     )
@@ -57,7 +59,7 @@
     btnElement = (
       <Button
         icon={card.icon}
-        style={card.btnstyle}
+        style={_style}
         onDoubleClick={() => doubleClickCard(id)}
       >
         {card.label}
diff --git a/src/menu/components/share/actioncomponent/formconfig.jsx b/src/menu/components/share/actioncomponent/formconfig.jsx
index 6d9fab1..b038d5c 100644
--- a/src/menu/components/share/actioncomponent/formconfig.jsx
+++ b/src/menu/components/share/actioncomponent/formconfig.jsx
@@ -11,7 +11,10 @@
  * @param {*} usefulFields   瀛樺偍杩囩▼鍙敤鐨勫紑濮嬪瓧娈�
  * @param {*} type           鎸夐挳绫诲瀷锛岀敤浜庡尯鍒嗗彲閫夌殑鎵撳紑鏂瑰紡
  */
-export function getActionForm (card, functip, setting, usefulFields, type, menulist = [], modules = []) {
+export function getActionForm (card, functip, config, usefulFields, type, menulist = [], modules = []) {
+  let appType = sessionStorage.getItem('appType')
+  let setting = config.setting || {}
+  let columns = config.columns || []
   let appMenus = []
   let opentypes = [
     {
@@ -49,7 +52,7 @@
     { value: 'pay', text: Formdict['model.pay'] },
     { value: 'custom', text: Formdict['header.form.custom'] }
   ]
-  const isApp = sessionStorage.getItem('appType') === 'pc'
+  const isApp = ['pc', 'mob'].includes(appType)
 
   let funTypes = [
     { value: 'changeuser', text: Formdict['header.form.func.changeuser'] },
@@ -57,9 +60,8 @@
   ]
   
   if (isApp) {
-    opentypes = opentypes.filter(item => item.value !== 'tab')
     pageTemps = [
-      { value: 'page', text: '鑿滃崟' },
+      // { value: 'page', text: '鑿滃崟' },
       { value: 'linkpage', text: '鍏宠仈鑿滃崟' },
       { value: 'billprint', text: '鍗曟嵁鎵撳嵃' },
       { value: 'pay', text: Formdict['model.pay'] },
@@ -79,9 +81,15 @@
     } else {
       appMenus = []
     }
+
+    if (appType === 'mob') {
+      opentypes = opentypes.filter(item => ['pop', 'prompt', 'exec', 'innerpage'].includes(item.value))
+    } else {
+      opentypes = opentypes.filter(item => item.value !== 'tab')
+    }
   }
   
-  if (type === 'chart') {
+  if (type === 'chart' && appType !== 'mob') {
     opentypes = opentypes.filter(item => item.value === 'excelIn' || item.value === 'excelOut')
   }
 
@@ -107,7 +115,7 @@
       type: 'radio',
       key: 'funcType',
       label: Formdict['header.form.funcType'],
-      initVal: card.funcType || (isApp ? 'changeuser' : ''),
+      initVal: card.funcType || '',
       required: true,
       options: funTypes
     },
@@ -193,34 +201,12 @@
       options: pageTemps
     },
     {
-      type: 'radio',
-      key: 'open',
-      label: '閾炬帴鏂瑰紡',
-      initVal: card.open || 'blank',
-      required: true,
-      forbid: !isApp,
-      options: [{
-        value: 'blank',
-        text: '鏂扮獥鍙�'
-      }, {
-        value: 'self',
-        text: '褰撳墠绐楀彛'
-      }]
-    },
-    {
       type: 'select',
       key: 'linkmenu',
       label: '鍏宠仈鑿滃崟',
       initVal: card.linkmenu || '',
       required: true,
-      options: appMenus
-    },
-    {
-      type: 'select',
-      key: 'copyMenuId',
-      label: '澶嶅埗鑿滃崟',
-      initVal: card.copyMenuId || '',
-      required: false,
+      forbid: !isApp,
       options: appMenus
     },
     {
@@ -430,21 +416,39 @@
       type: 'radio',
       key: 'show',
       label: "鏄剧ず涓�",
-      initVal: card.show || 'icon',
+      initVal: card.show || 'button',
       required: true,
       options: [{
         value: 'icon',
         text: '鍥炬爣'
       }, {
         value: 'button',
-        text: '鎸夐挳'
+        text: '鍥炬爣+鏂囧瓧'
       }, {
         value: 'link',
-        text: '閾炬帴'
+        text: '鏂囧瓧+鍥炬爣'
       }]
     },
     {
-      type: 'select',
+      type: 'radio',
+      key: 'swipe',
+      label: "婊戝姩鏄剧ず",
+      initVal: card.swipe || 'false',
+      required: false,
+      forbid: (type !== 'datacard' || appType !== 'mob'),
+      options: [{
+        value: 'false',
+        text: '鍚�'
+      }, {
+        value: 'left',
+        text: '宸︽粦'
+      }, {
+        value: 'right',
+        text: '鍙虫粦'
+      }]
+    },
+    {
+      type: 'icon',
       key: 'icon',
       label: Formdict['model.icon'],
       initVal: card.icon,
@@ -456,6 +460,7 @@
       key: 'class',
       label: Formdict['model.form.color'],
       initVal: card.class,
+      tooltip: '姝ら鑹蹭负鎸夐挳鍒濆鍖栭鑹诧紝鍙湪鏍峰紡璋冩暣涓慨鏀广��',
       required: false,
       options: []
     },
@@ -515,6 +520,50 @@
       initVal: card.syncComponent || [],
       required: false,
       options: modules
+    },
+    {
+      type: 'select',
+      key: 'controlField',
+      label: '鎺у埗瀛楁',
+      tooltip: '绂佺敤鎺у埗瀛楁锛屽彲鏍规嵁鏁版嵁鎺у埗鎸夐挳鏄惁绂佺敤銆�',
+      initVal: card.controlField || '',
+      required: false,
+      allowClear: true,
+      options: columns
+    },
+    {
+      type: 'text',
+      key: 'controlVal',
+      label: '鎺у埗鍊�',
+      tooltip: '褰撻�夋嫨鎺у埗瀛楁锛屼笖瀛楁鍊间笌鎺у埗鍊肩浉绛夋椂锛屾寜閽細绂佺敤锛屽涓�肩敤閫楀彿鍒嗛殧銆�',
+      initVal: card.controlVal || '',
+      required: false
+    },
+    {
+      type: 'select',
+      key: 'openmenu',
+      label: '鎵撳紑鑿滃崟',
+      tooltip: '鎵ц鎴愬姛鍚庨渶瑕佹墦寮�鐨勮彍鍗曘��',
+      initVal: card.openmenu || '',
+      forbid: appType !== 'pc' && appType !== 'mob',
+      required: false,
+      allowClear: true,
+      options: appMenus
+    },
+    {
+      type: 'radio',
+      key: 'open',
+      label: '鎵撳紑鏂瑰紡',
+      initVal: card.open || 'blank',
+      required: true,
+      forbid: appType !== 'pc',
+      options: [{
+        value: 'blank',
+        text: '鏂扮獥鍙�'
+      }, {
+        value: 'self',
+        text: '褰撳墠绐楀彛'
+      }]
     }
   ]
 
diff --git a/src/menu/components/share/actioncomponent/index.jsx b/src/menu/components/share/actioncomponent/index.jsx
index c6964ec..32764df 100644
--- a/src/menu/components/share/actioncomponent/index.jsx
+++ b/src/menu/components/share/actioncomponent/index.jsx
@@ -32,6 +32,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,          // 缂栬緫涓厓绱�
     formlist: null,      // 琛ㄥ崟淇℃伅
     actionlist: null,    // 鎸夐挳缁�
@@ -43,8 +44,20 @@
    * @description 鎼滅储鏉′欢鍒濆鍖�
    */
   UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    let actionlist = fromJS(config.action).toJS() || []
+
     this.setState({
-      actionlist: fromJS(this.props.config.action).toJS()
+      actionlist: actionlist.map(item => {
+        if (item.btnstyle) { // 鍏煎
+          item.style = item.style || {}
+          item.style = {...item.style, ...item.btnstyle}
+          delete item.btnstyle
+        }
+
+        return item
+      })
     })
   }
 
@@ -85,7 +98,7 @@
     if (comIds[0] !== config.uuid || comIds[1] !== 'actionlist') return
 
     let _card = fromJS(card).toJS()
-    _card.btnstyle = style
+    _card.style = style
 
     let _actionlist = actionlist.map(cell => {
       if (cell.uuid === _card.uuid) return _card
@@ -102,8 +115,8 @@
   changeBtnStyle = (element) => {
     const { config } = this.props
 
-    let _style = element.btnstyle ? fromJS(element.btnstyle).toJS() : {}
-    let options = ['font', 'border', 'background', 'margin']
+    let _style = element.style ? fromJS(element.style).toJS() : {}
+    let options = ['font', 'border', 'background', 'margin', 'padding']
 
     this.setState({
       card: element
@@ -175,7 +188,7 @@
     this.setState({
       visible: true,
       card: card,
-      formlist: getActionForm(card, functip, config.setting, usefulFields, this.props.type, menulist, modules)
+      formlist: getActionForm(card, functip, config, usefulFields, this.props.type, menulist, modules)
     })
   }
 
@@ -221,15 +234,15 @@
         }
 
         if (item.uuid === btn.uuid) {
-          btn.btnstyle = item.btnstyle || {}
+          btn.style = item.style || {}
 
-          if (btn.class !== item.class || btn.show !== item.show || !btn.btnstyle.color) {
+          if (btn.class !== item.class || btn.show !== item.show || !btn.style.color) {
             if (btn.show === 'link' || btn.show === 'icon') {
-              btn.btnstyle.color = color[btn.class]
-              btn.btnstyle.backgroundColor = 'transparent'
+              btn.style.color = color[btn.class]
+              btn.style.backgroundColor = 'transparent'
             } else {
-              btn.btnstyle.color = '#ffffff'
-              btn.btnstyle.backgroundColor = color[btn.class]
+              btn.style.color = '#ffffff'
+              btn.style.backgroundColor = color[btn.class]
             }
           }
           return btn
@@ -261,7 +274,7 @@
    */
   deleteElement = (card) => {
     const { config } = this.props
-    const { dict } = this.state
+    const { dict, appType } = this.state
     let _this = this
 
     confirm({
@@ -270,10 +283,6 @@
         let _actionlist = fromJS(_this.state.actionlist).toJS()
 
         _actionlist = _actionlist.filter(item => item.uuid !== card.uuid)
-
-        if (!card.origin) {
-          MKEmitter.emit('delButtons', [card.uuid])
-        }
 
         let btnlog = config.btnlog || []
         if (card.OpenType === 'popview' || card.verify || card.modal) {
@@ -285,6 +294,11 @@
         }, () => {
           _this.props.updateaction({...config, action: _actionlist, btnlog})
         })
+
+        if (card.origin || appType === 'mob') return
+        if (appType === 'pc' && card.OpenType !== 'popview') return
+
+        MKEmitter.emit('delButtons', [card.uuid])
       },
       onCancel() {}
     })
@@ -354,7 +368,7 @@
         let _param = {
           funcName: btn.innerFunc,
           name: _config.setting.tableName || '',
-          fields: btn.fields,
+          fields: btn.modal ? btn.modal.fields : [],
           menuNo: menu.MenuNo
         }
         newLText = Utils.formatOptions(FuncUtils.getfunc(_param, btn, menu, _config))
@@ -392,8 +406,8 @@
    * @description 鎸夐挳鍙屽嚮瑙﹀彂瀛愰厤缃�
    */
   btnDoubleClick = (element) => {
-    if (sessionStorage.getItem('style-control') && sessionStorage.getItem('style-control') !== 'false') return
-    
+    if (sessionStorage.getItem('style-control') && sessionStorage.getItem('style-control') === 'true') return
+
     if (element.OpenType === 'pop' || element.OpenType === 'popview' || element.execMode === 'pop') {
       this.props.setSubConfig(element)
     } else if (element.OpenType === 'innerpage' && element.pageTemplate === 'page') {
diff --git a/src/menu/components/share/actioncomponent/index.scss b/src/menu/components/share/actioncomponent/index.scss
index 79f0b8a..baca0f7 100644
--- a/src/menu/components/share/actioncomponent/index.scss
+++ b/src/menu/components/share/actioncomponent/index.scss
@@ -23,12 +23,19 @@
     }
     button {
       cursor: move;
+      height: auto;
+      min-height: 32px;
       .anticon-table {
         font-size: 10px;
         position: absolute;
         right: 1px;
         bottom: 0px;
       }
+      span {
+        font-style: inherit;
+        text-decoration: inherit;
+        font-weight: inherit;
+      }
     }
   }
 }
diff --git a/src/menu/components/share/logcomponent/index.jsx b/src/menu/components/share/logcomponent/index.jsx
index 570e93d..403d3bc 100644
--- a/src/menu/components/share/logcomponent/index.jsx
+++ b/src/menu/components/share/logcomponent/index.jsx
@@ -18,6 +18,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     visible: false,
     data: [],
     columns: [
@@ -69,11 +70,15 @@
   }
 
   revert = (item) => {
+    const { appType } = this.state
     const data = this.state.data.filter(d => d.uuid !== item.uuid)
 
     this.setState({data})
-    MKEmitter.emit('thawButtons', item.uuid)
     this.props.handlelog('revert', data, item)
+
+    if (appType === 'mob' || (appType === 'pc' && item.OpenType !== 'popview')) return
+
+    MKEmitter.emit('thawButtons', item.uuid)
   }
 
   handleDelete = (item) => {
diff --git a/src/menu/components/share/markcomponent/index.jsx b/src/menu/components/share/markcomponent/index.jsx
index af08d0c..4518ab6 100644
--- a/src/menu/components/share/markcomponent/index.jsx
+++ b/src/menu/components/share/markcomponent/index.jsx
@@ -13,6 +13,7 @@
 import '@/assets/css/table.scss'
 
 const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
+const { confirm } = Modal
 
 class MarkColumn extends Component {
   static propTpyes = {
@@ -128,8 +129,11 @@
   resetMark = () => {
     const { marks, columns, type } = this.props
     let markColumns = fromJS(this.state.markColumns).toJS()
+    let _columns = fromJS(columns).toJS()
 
-    let options = columns.map(col => {
+    _columns.unshift({field: '$Index', label: '搴忓彿'})
+
+    let options = _columns.map(col => {
       return {
         value: col.field,
         label: col.label,
@@ -142,7 +146,7 @@
           {
             value: 'dynamic',
             label: '鍔ㄦ�佸��',
-            children: columns.map(cell => {
+            children: _columns.map(cell => {
               return {
                 value: cell.field,
                 label: cell.label
@@ -250,7 +254,7 @@
       }
     ]
 
-    if (type === 'line') {
+    if (type === 'line' || type === 'sequence') {
       signs.pop()
     } else if (type === 'slider') {
       markColumns = markColumns.filter(col => {
@@ -278,9 +282,13 @@
   }
 
   markSubmit = () => {
-    this.setState({
-      visible: false
-    })
+    let save = false
+    let input = document.getElementById('contrastValue')
+    let val = input && input.value ? input.value : ''
+
+    if (!val) {
+      save = true
+    }
 
     let marks = this.state.marks.map(item => {
       if (item.signType && item.signType[0] === 'background') {
@@ -295,10 +303,28 @@
           item.fontColor = ''
         }
       }
+      if (val && item.contrastValue === val) {
+        save = true
+      }
       return item
     })
 
-    this.props.onSubmit(marks)
+    if (save) {
+      this.setState({
+        visible: false
+      })
+      this.props.onSubmit(marks)
+    } else {
+      const _this = this
+      confirm({
+        title: '瀛樺湪鏈繚瀛樻爣璁帮紝纭畾蹇界暐鍚楋紵',
+        onOk() {
+          _this.setState({ visible: false })
+          _this.props.onSubmit(marks)
+        },
+        onCancel() {}
+      })
+    }
   }
 
   render() {
diff --git a/src/menu/components/share/mobPagination/index.jsx b/src/menu/components/share/mobPagination/index.jsx
new file mode 100644
index 0000000..d46c722
--- /dev/null
+++ b/src/menu/components/share/mobPagination/index.jsx
@@ -0,0 +1,20 @@
+import React, {Component} from 'react'
+import { Icon, Pagination } from 'antd-mobile'
+
+import './index.scss'
+
+class MobPagination extends Component {
+  render () {
+    return (
+      <Pagination className="mob-pagination" total={5}
+        current={1}
+        locale={{
+          prevText: (<span><Icon type="left" />涓婁竴椤�</span>),
+          nextText: (<span>涓嬩竴椤�<Icon type="right" /></span>),
+        }}
+      />
+    )
+  }
+}
+
+export default MobPagination
\ No newline at end of file
diff --git a/src/menu/components/share/mobPagination/index.scss b/src/menu/components/share/mobPagination/index.scss
new file mode 100644
index 0000000..2537123
--- /dev/null
+++ b/src/menu/components/share/mobPagination/index.scss
@@ -0,0 +1,14 @@
+.mob-pagination {
+  .am-button::before {
+    display: none;
+  }
+  .am-button {
+    border: none;
+    font-size: 16px;
+    background: transparent;
+    .am-icon {
+      position: relative;
+      top: 5px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/share/normalheader/index.jsx b/src/menu/components/share/normalheader/index.jsx
index d5bc448..fca49ac 100644
--- a/src/menu/components/share/normalheader/index.jsx
+++ b/src/menu/components/share/normalheader/index.jsx
@@ -5,6 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import MKEmitter from '@/utils/events.js'
+import { resetStyle } from '@/utils/utils-custom.js'
 import './index.scss'
 
 const SearchComponent = asyncComponent(() => import('@/menu/components/share/searchcomponent'))
@@ -15,6 +16,10 @@
     hideSearch: PropTypes.any,       // 闅愯棌鎼滅储鏉′欢
     config: PropTypes.object,        // 閰嶇疆淇℃伅
     updateComponent: PropTypes.func  // 閰嶇疆鏇存柊
+  }
+
+  state = {
+    appType: sessionStorage.getItem('appType')
   }
 
   componentDidMount () {
@@ -48,22 +53,30 @@
   changeStyle = () => {
     const { config } = this.props
 
+    // MKEmitter.emit('changeStyle', [config.uuid, 'header'], ['font', 'height', 'border'], config.headerStyle)
     MKEmitter.emit('changeStyle', [config.uuid, 'header'], ['font', 'border'], config.headerStyle)
   }
 
   render() {
     const { config, defaultshow, hideSearch } = this.props
+    const { appType } = this.state
 
     let title = config.plot ? config.plot.title : config.wrap.title
     let show = true
+
+    if (!title && appType === 'mob' && config.type === 'card' && config.subtype === 'datacard' && config.action && config.action.length) {
+      title = ' '
+    }
+
     if (defaultshow === 'hidden') {
       if (!title && (!config.search || config.search.length === 0)) {
         show = false
       }
     }
+    let _style = resetStyle(config.headerStyle)
 
     return (
-      <div className={'normal-header' + (!show ? ' hidden' : '')} style={config.headerStyle}>
+      <div className={'normal-header' + (!show ? ' hidden' : '') + (config.wrap && config.wrap.searchable === 'true' ? ' tree-search' : '')} style={_style}>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
@@ -71,6 +84,7 @@
         } trigger="hover">
           <span className="title">{title}</span>
         </Popover>
+        {config.wrap && config.wrap.searchable === 'true' ? <span className="ant-input-search ant-input-affix-wrapper"><span className="ant-input-suffix"><Icon type="search" /></span></span> : null}
         {hideSearch !== 'true' && config.search ? <SearchComponent config={config} updatesearch={this.props.updateComponent}/> : null}
       </div>
     )
diff --git a/src/menu/components/share/normalheader/index.scss b/src/menu/components/share/normalheader/index.scss
index ceac790..ed805b2 100644
--- a/src/menu/components/share/normalheader/index.scss
+++ b/src/menu/components/share/normalheader/index.scss
@@ -3,19 +3,37 @@
   height: 45px;
   border-bottom: 1px solid #e8e8e8;
   overflow: hidden;
+  line-height: 45px;
 
   .title {
     text-decoration: inherit;
     font-weight: inherit;
     font-style: inherit;
     float: left;
-    line-height: 45px;
+    line-height: inherit;
     margin-left: 10px;
     position: relative;
     z-index: 1;
     min-height: 45px;
     min-width: 30px;
   }
+  .model-custom-header-search-list {
+    flex: 1;
+  }
+  .ant-input-search.ant-input-affix-wrapper {
+    width: calc(100% - 140px);
+    max-width: 130px;
+    margin-top: 8px;
+    margin-right: 25px;
+    float: right;
+    height: 28px;
+    border-radius: 20px;
+    border: 1px solid #d9d9d9;
+    opacity: 0.6;
+  }
+}
+.normal-header:not(.tree-search) {
+  display: flex;
 }
 .normal-header.hidden {
   display: none;
diff --git a/src/menu/components/share/pastecomponent/index.jsx b/src/menu/components/share/pastecomponent/index.jsx
index 2d12bb3..553d24d 100644
--- a/src/menu/components/share/pastecomponent/index.jsx
+++ b/src/menu/components/share/pastecomponent/index.jsx
@@ -24,7 +24,7 @@
     this.setState({visible: true})
   }
 
-  resetconfig = (item, copyBtns) => {
+  resetconfig = (item, copyBtns, config) => {
     let _uuid = Utils.getuuid()
 
     if (item.OpenType === 'popview') {
@@ -38,9 +38,33 @@
       item.uuid = _uuid
     }
 
-    if (item.copyType === 'cardcell') {
+    if (item.copyType === 'cardcell' && config.subtype === 'datacard') {
+      item.setting = item.setting || {}
+      item.$cardType = 'extendCard'
+      item.setting.width = item.setting.width || 6
+
+      if (item.elements) {
+        item.elements = item.elements.map(cell => {
+          if (cell.datatype === 'dynamic') {
+            cell.datatype = 'static'
+          }
+          cell.uuid = Utils.getuuid()
+          return cell
+        })
+      }
+      if (item.backElements) {
+        item.backElements = item.backElements.map(cell => {
+          if (cell.datatype === 'dynamic') {
+            cell.datatype = 'static'
+          }
+          cell.uuid = Utils.getuuid()
+          return cell
+        })
+      }
+    } else if (item.copyType === 'cardcell') {
       item.setting = item.setting || {}
       item.setting.width = item.setting.width || 6
+      delete item.$cardType
 
       if (item.elements) {
         item.elements = item.elements.map(cell => {
@@ -105,12 +129,9 @@
   pasteSubmit = () => {
     const { options } = this.props
     this.pasteFormRef.handleConfirm().then(res => {
+
       if (!options.includes(res.copyType)) {
-        notification.warning({
-          top: 92,
-          message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�',
-          duration: 5
-        })
+        notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
         return
       }
 
@@ -118,7 +139,7 @@
       let config = fromJS(this.props.config).toJS()
       let copyBtns = new Map()
 
-      res = this.resetconfig(res, copyBtns)
+      res = this.resetconfig(res, copyBtns, config)
       delete res.copyType
 
       copyBtns = [...copyBtns.values()]
@@ -127,10 +148,18 @@
         MKEmitter.emit('copyButtons', copyBtns)
       }
 
-      if (type === 'action') {
+      if (config.type === 'form' && config.subtype === 'stepform') {
+        this.props.updateConfig(res)
+        this.setState({visible: false})
+        return
+      } else if (type === 'action') {
         config.action = config.action || []
         config.action = config.action.filter(item => !item.origin)
 
+        if (['line', 'bar', 'scatter'].includes(config.type) && !['excelOut', 'excelIn'].includes(res.OpenType)) {
+          notification.warning({ top: 92, message: '鍥捐〃涓笉鏀寔姝ょ被鎸夐挳锛�', duration: 5 })
+          return
+        }
         MKEmitter.emit('addButton', config.uuid, res)
       } else if (type === 'search' || type === 'form') {
         config.search = config.search || []
@@ -139,7 +168,7 @@
         let keys = config.search.map(item => item.field.toLowerCase())
 
         if (type === 'form') {
-          if (['number', 'switch', 'textarea', 'checkcard', 'fileupload', 'hint', 'color', 'funcvar'].includes(res.type)) {
+          if (['number', 'switch', 'textarea', 'fileupload', 'hint', 'color', 'funcvar'].includes(res.type)) {
             res.type = 'text'
           } else if (res.type === 'radio') {
             res.type = 'select'
@@ -162,6 +191,8 @@
         config.search.push(res)
       } else if (type === 'cardcell') {
         config.subcards.push(res)
+      } else if (type === 'menucell') {
+        config.subMenus.push(res)
       } else if (type === 'cols') {
         config.cols = config.cols.filter(col => !col.origin)
 
diff --git a/src/menu/components/share/searchcomponent/dategroup/index.jsx b/src/menu/components/share/searchcomponent/dategroup/index.jsx
deleted file mode 100644
index 37b8769..0000000
--- a/src/menu/components/share/searchcomponent/dategroup/index.jsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Tag } from 'antd'
-import './index.scss'
-
-const { CheckableTag } = Tag
-
-class DateGroup extends Component {
-  static propTpyes = {
-    card: PropTypes.object    // 瀛楀吀椤�
-  }
-
-  render() {
-    const { card } = this.props
-    let tabs = {day: '鏃�', week: '鍛�', month: '鏈�', quarter: '瀛�', year: '骞�', customized: '鑷畾涔�'}
-
-    return (
-      <div className="model-date-group">
-        {card.items.map(tab => (
-          <CheckableTag
-            key={tab}
-            checked={card.initval && card.initval.includes(tab)}
-          >
-            {tabs[tab]}
-          </CheckableTag>
-        ))}
-      </div>
-    )
-  }
-}
-
-export default DateGroup
\ No newline at end of file
diff --git a/src/menu/components/share/searchcomponent/dategroup/index.scss b/src/menu/components/share/searchcomponent/dategroup/index.scss
deleted file mode 100644
index 6782732..0000000
--- a/src/menu/components/share/searchcomponent/dategroup/index.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-.model-date-group {
-  white-space: nowrap;
-  line-height: 40px;
-  position: relative;
-  z-index: 1;
-
-  .ant-tag-checkable {
-    border-color: #d1d5d9;
-    border-radius: 2px;
-    margin-right: 2px;
-    padding: 2px 6px;
-  }
-  .ant-tag-checkable-checked {
-    border-color: #1890ff;
-  }
-}
-
-@media screen and (min-width: 1440px) {
-  .model-date-group {
-    .ant-tag-checkable {
-      padding: 2px 7px;
-    }
-  }
-}
-@media screen and (min-width: 1600px) {
-  .model-date-group {
-    .ant-tag-checkable {
-      padding: 2px 9px;
-    }
-  }
-}
-@media screen and (min-width: 1920px) {
-  .model-date-group {
-    .ant-tag-checkable {
-      padding: 2px 11px;
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/menu/components/share/searchcomponent/dragsearch/card.jsx b/src/menu/components/share/searchcomponent/dragsearch/card.jsx
index ad010e7..d0d41c2 100644
--- a/src/menu/components/share/searchcomponent/dragsearch/card.jsx
+++ b/src/menu/components/share/searchcomponent/dragsearch/card.jsx
@@ -3,7 +3,7 @@
 import { Icon, Select, DatePicker, Input, Popover, Form } from 'antd'
 import moment from 'moment'
 
-import DateGroup from '../dategroup'
+import DateGroup from '@/menu/components/search/main-search/dategroup'
 import './index.scss'
 
 const { MonthPicker, WeekPicker, RangePicker } = DatePicker
diff --git a/src/menu/components/share/searchcomponent/dragsearch/index.scss b/src/menu/components/share/searchcomponent/dragsearch/index.scss
index 369ae98..e69de29 100644
--- a/src/menu/components/share/searchcomponent/dragsearch/index.scss
+++ b/src/menu/components/share/searchcomponent/dragsearch/index.scss
@@ -1,6 +0,0 @@
-.common-drawarea-placeholder {
-  width: 100%;
-  line-height: 65px;
-  text-align: center;
-  color: #bcbcbc;
-}
\ No newline at end of file
diff --git a/src/menu/components/share/searchcomponent/index.jsx b/src/menu/components/share/searchcomponent/index.jsx
index c123995..5aa9876 100644
--- a/src/menu/components/share/searchcomponent/index.jsx
+++ b/src/menu/components/share/searchcomponent/index.jsx
@@ -210,7 +210,7 @@
         return
       }
 
-      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
diff --git a/src/menu/components/share/sourcecomponent/index.jsx b/src/menu/components/share/sourcecomponent/index.jsx
index a5ed3e6..a5b88bc 100644
--- a/src/menu/components/share/sourcecomponent/index.jsx
+++ b/src/menu/components/share/sourcecomponent/index.jsx
@@ -14,12 +14,23 @@
   }
 
   state = {
-    url: this.props.value,
+    url: '',
     visible: ''
   }
 
   UNSAFE_componentWillMount () {
+    const { value } = this.props
+    let val = ''
 
+    if (value) {
+      val = value
+    } else if (this.props['data-__meta']) {
+      val = this.props['data-__meta'].initialValue || ''
+    }
+
+    this.setState({
+      url: val,
+    })
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -67,6 +78,8 @@
           width={visible !== 'system' ? 600 : 1000}
           closable={false}
           maskClosable={false}
+          okText="纭畾"
+          cancelText="鍙栨秷"
           onOk={this.popSubmit}
           onCancel={() => {this.setState({visible: ''})}}
           destroyOnClose
diff --git a/src/menu/components/share/sourcecomponent/inputform/index.jsx b/src/menu/components/share/sourcecomponent/inputform/index.jsx
index 0312024..f178a9e 100644
--- a/src/menu/components/share/sourcecomponent/inputform/index.jsx
+++ b/src/menu/components/share/sourcecomponent/inputform/index.jsx
@@ -27,7 +27,6 @@
     originlist: [],
     list: [],
     pagelist: [],
-    fileList: [],
     searchKey: '',
     pageSize: 12,
     pageIndex: 1,
@@ -79,7 +78,7 @@
     let list = originlist
     let pagelist = list.filter((item, index) => index < this.state.pageSize)
 
-    this.setState({originlist, list, url: '', searchKey: '', pageIndex: 1, fileList: [], pagelist})
+    this.setState({originlist, list, url: '', searchKey: '', pageIndex: 1, pagelist})
   }
 
   changeSearch = () => {
@@ -100,12 +99,8 @@
     this.setState({pageIndex: page, pagelist})
   }
 
-  changeFile = (vals) => {
-    this.setState({fileList: vals})
-
-    if (vals && vals[0] && vals[0].status === 'done' && vals[0].response) {
-      this.setState({url: vals[0].response})
-    }
+  changeFile = (val) => {
+    this.setState({url: val})
   }
 
   selectItem = (item) => {
@@ -162,7 +157,7 @@
 
   render () {
     const { type, keyword } = this.props
-    const { list, url, pagelist, fileList, searchKey, pageIndex, pageSize, selectId, editvisible, card } = this.state
+    const { list, url, pagelist, searchKey, pageIndex, pageSize, selectId, editvisible, card } = this.state
     
     return (
       <div className="mk-source-pop-wrap">
@@ -170,7 +165,12 @@
           <TextArea id="source-input" value={url} rows={4} onChange={this.changeValue}/>
         </Form.Item> : null}
         {keyword === 'upload' ? <Form.Item label="涓婁紶" labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={{xs: { span: 24 }, sm: { span: 20 }}}>
-          <FileUpload value={fileList} onChange={this.changeFile} accept={type === 'video' ? '.mp4,.webm,.ogg' : '.jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp'} maxFile={1} fileType={type === 'video' ? 'text' : 'picture'} />
+          <FileUpload config={{
+            initval: '',
+            suffix: type === 'video' ? '.mp4,.webm,.ogg' : '.jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp',
+            maxfile: 1,
+            fileType: type === 'video' ? 'text' : 'picture'
+          }} onChange={this.changeFile} />
         </Form.Item> : null}
         {keyword === 'system' ?
           <Search value={searchKey} placeholder="" onChange={(e) => this.setState({searchKey: e.target.value})} onSearch={this.changeSearch} enterButton/> : null}
diff --git a/src/menu/components/share/styleInput/index.jsx b/src/menu/components/share/styleInput/index.jsx
new file mode 100644
index 0000000..361265b
--- /dev/null
+++ b/src/menu/components/share/styleInput/index.jsx
@@ -0,0 +1,140 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Select, Input } from 'antd'
+
+import './index.scss'
+
+const { Option } = Select
+
+class StyleInput extends Component {
+  static propTpyes = {
+    defaultValue: PropTypes.any,
+    options: PropTypes.any,
+    value: PropTypes.any,
+    onChange: PropTypes.func,
+  }
+
+  state = {
+    value: '',
+    unit: '',
+    options: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { value, options } = this.props
+
+    let val = value || ''
+    let unit = options[0]
+
+    if (val) {
+      if (val.indexOf('px') > -1) {
+        unit = 'px'
+      } else if (val.indexOf('%') > -1) {
+        unit = '%'
+      } else if (val.indexOf('vw') > -1) {
+        unit = 'vw'
+      } else if (val.indexOf('vh') > -1) {
+        unit = 'vh'
+      }
+    }
+
+    let _val = parseFloat(val)
+
+    if (isNaN(_val)) {
+      _val = ''
+    }
+
+    this.setState({value: _val, options: options, unit})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  UNSAFE_componentWillReceiveProps(nextProps) {
+    if (nextProps.value === '' && this.state.value !== '') {
+      this.setState({value: ''})
+    } else if (nextProps.value && nextProps.value !== `${this.state.value}${this.state.unit}`) {
+      let val = nextProps.value
+      let unit = this.state.unit
+
+      if (val) {
+        if (val.indexOf('px') > -1) {
+          unit = 'px'
+        } else if (val.indexOf('%') > -1) {
+          unit = '%'
+        } else if (val.indexOf('vw') > -1) {
+          unit = 'vw'
+        } else if (val.indexOf('vh') > -1) {
+          unit = 'vh'
+        }
+      }
+
+      let _val = parseFloat(val)
+    
+      if (isNaN(_val)) {
+        _val = ''
+      }
+      this.setState({value: _val, unit})
+    }
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  changeValue = (e) => {
+    const { unit } = this.state
+    let val = e.target.value
+
+    if (/\d+\.$/.test(val)) {
+      this.setState({
+        value: val
+      })
+      return
+    }
+    let _val = parseFloat(val)
+    
+    if (isNaN(_val)) {
+      _val = ''
+    }
+
+    this.setState({
+      value: _val,
+    }, () => {
+      this.props.onChange(_val !== '' ? `${_val}${unit}` : '')
+    })
+  }
+
+  changeUnit = (val) => {
+    const { value } = this.state
+
+    this.setState({unit: val}, () => {
+      this.props.onChange(value !== '' ? `${value}${val}` : '')
+    })
+  }
+
+  render () {
+    const { value, options, unit } = this.state
+
+    return (
+      <div className="style-input-wrap">
+        <Input value={value} addonAfter={
+          options.length > 1 ?
+          <Select value={unit} onChange={this.changeUnit}>
+            {options.map(item => <Option key={item} value={item}>{item}</Option>)}
+          </Select> :
+          <div className="single-unit">{unit}</div>
+        } onChange={this.changeValue}/>
+      </div>
+    )
+  }
+}
+
+export default StyleInput
\ No newline at end of file
diff --git a/src/menu/components/share/styleInput/index.scss b/src/menu/components/share/styleInput/index.scss
new file mode 100644
index 0000000..b058a37
--- /dev/null
+++ b/src/menu/components/share/styleInput/index.scss
@@ -0,0 +1,11 @@
+.style-input-wrap {
+  line-height: 32px;
+  .ant-select {
+    width: 60px!important;
+  }
+  .single-unit {
+    width: 38px;
+    text-align: left;
+    color: rgba(255, 255, 255, 0.65);
+  }
+}
diff --git a/src/menu/components/share/usercomponent/index.jsx b/src/menu/components/share/usercomponent/index.jsx
index 30caa31..e10fa99 100644
--- a/src/menu/components/share/usercomponent/index.jsx
+++ b/src/menu/components/share/usercomponent/index.jsx
@@ -163,6 +163,7 @@
                 func: 's_custom_components_adduptdel',
                 c_id: config.uuid,
                 images: Utils.getcloudurl(result.Images),
+                typename: sessionStorage.getItem('appType') || '',
                 c_name: res.name,
                 long_param: window.btoa(window.encodeURIComponent(JSON.stringify(template))),
                 del_type: ''
diff --git a/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx b/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
index 46484ca..c362bd8 100644
--- a/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
+++ b/src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -6,9 +6,9 @@
 /**
  * @description 鑾峰彇鏄剧ず鍒楄〃鍗曢厤缃俊鎭�
  * @param {object} card       // 鎼滅储鏉′欢瀵硅薄
- * @param {Array}  menulist   // 鑿滃崟鍒楄〃-鐢ㄤ簬瀛楁閫忚
  */
-export function getColumnForm (card, menulist = [], fields = []) {
+export function getColumnForm (card, fields = []) {
+  let appType = sessionStorage.getItem('appType')
   let roleList = sessionStorage.getItem('sysRoles')
   if (roleList) {
     try {
@@ -18,6 +18,24 @@
     }
   } else {
     roleList = []
+  }
+
+  let menulist = []
+
+  if (appType === 'pc') {
+    menulist = sessionStorage.getItem('appMenus')
+  } else if (!appType) {
+    menulist = sessionStorage.getItem('fstMenuList')
+  }
+
+  if (menulist) {
+    try {
+      menulist = JSON.parse(menulist)
+    } catch {
+      menulist = []
+    }
+  } else {
+    menulist = []
   }
 
   let options = [{
@@ -41,6 +59,9 @@
   }, {
     value: 'colspan',
     text: '鍚堝苟鍒�'
+  }, {
+    value: 'index',
+    text: '搴忓彿'
   }]
 
   if (!card.isSub) {
@@ -243,21 +264,32 @@
       key: 'postfix',
       label: Formdict['header.form.postfix'],
       initVal: card.postfix || '',
-      tooltipClass: 'middle',
       required: false,
       readonly: false
     },
     {
-      type: 'radio',
+      type: 'select',
       key: 'lenWidRadio',
       label: '闀垮姣�',
       initVal: card.lenWidRadio || '1:1',
       required: true,
       options: [
         { value: '1:1', text: '1:1' },
-        { value: '3:2', text: '3:2' },
         { value: '4:3', text: '4:3' },
-        { value: '16:9', text: '16:9' }
+        { value: '3:2', text: '3:2' },
+        { value: '16:9', text: '16:9' },
+        { value: '2:1', text: '2:1' },
+        { value: '3:1', text: '3:1' },
+        { value: '4:1', text: '4:1' },
+        { value: '5:1', text: '5:1' },
+        { value: '6:1', text: '6:1' },
+        { value: '7:1', text: '7:1' },
+        { value: '8:1', text: '8:1' },
+        { value: '9:1', text: '9:1' },
+        { value: '10:1', text: '10:1' },
+        { value: '3:4', text: '3:4' },
+        { value: '2:3', text: '2:3' },
+        { value: '9:16', text: '9:16' },
       ]
     },
     {
@@ -309,22 +341,25 @@
       }, {
         value: 'linkurl',
         text: '閾炬帴'
-      }]
+      }],
+      forbidden: appType === 'mob'
     },
     {
-      type: 'cascader',
+      type: appType === 'pc' ? 'select' : 'cascader',
       key: 'linkmenu',
       label: Formdict['model.menu'],
-      initVal: card.linkmenu || [],
+      initVal: card.linkmenu || (appType === 'pc' ? '' : []),
       required: true,
-      options: menulist
+      options: menulist,
+      forbidden: appType === 'mob'
     },
     {
       type: 'textarea',
       key: 'linkurl',
       label: '閾炬帴鍦板潃',
       initVal: card.linkurl || '',
-      required: true
+      required: true,
+      forbidden: appType === 'mob'
     },
     {
       type: 'multiselect',
@@ -332,7 +367,20 @@
       label: '鍏宠仈瀛楁',
       initVal: card.linkfields || [],
       required: false,
-      options: fields
+      options: fields,
+      forbidden: appType === 'mob'
+    },
+    {
+      type: 'radio',
+      key: 'open',
+      label: '鎵撳紑鏂瑰紡',
+      initVal: card.open || 'blank',
+      required: false,
+      forbid: appType !== 'pc',
+      options: [
+        { value: 'blank', text: '鏂扮獥鍙�' },
+        { value: 'self', text: '褰撳墠绐楀彛' }
+      ]
     },
     {
       type: 'multiselect',
diff --git a/src/menu/components/table/normal-table/columns/editColumn/index.jsx b/src/menu/components/table/normal-table/columns/editColumn/index.jsx
index 43c63ac..d5450d3 100644
--- a/src/menu/components/table/normal-table/columns/editColumn/index.jsx
+++ b/src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -16,7 +16,8 @@
   picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'blacklist', 'scale', 'lenWidRadio', 'picSort'],
   colspan: ['label', 'type', 'Align', 'Hide', 'blacklist'],
   custom: ['label', 'type', 'Align', 'Hide', 'Width', 'blacklist'],
-  action: ['label', 'type', 'Align', 'Width']
+  action: ['label', 'type', 'Align', 'Width'],
+  index: ['label', 'type', 'Align', 'Width']
 }
 
 class MainSearch extends Component {
@@ -41,24 +42,13 @@
   }
 
   editColumn = (column) => {
-    let menulist = sessionStorage.getItem('fstMenuList')
-    if (menulist) {
-      try {
-        menulist = JSON.parse(menulist)
-      } catch {
-        menulist = []
-      }
-    } else {
-      menulist = []
-    }
-
-    let formlist = getColumnForm(column, menulist, this.props.fields)
+    let formlist = getColumnForm(column, this.props.fields)
     let _options = fromJS(columnTypeOptions[column.type]).toJS()
     if (column.type === 'text' || column.type === 'number') {
       if (column.perspective === 'linkmenu') {
-        _options.push('linkmenu', 'linkfields')
+        _options.push('linkmenu', 'linkfields', 'open')
       } else if (column.perspective === 'linkurl') {
-        _options.push('linkurl', 'linkfields')
+        _options.push('linkurl', 'linkfields', 'open')
       }
     }
 
@@ -103,13 +93,34 @@
         }
       })
     } else if (key === 'field') {
-      this.props.form.setFieldsValue({label: option.props.children})
-      if (this.state.type === 'number') {
+      let values = {label: option.props.children}
+      if (/Decimal|int/ig.test(option.props.datatype)) {
         let decimal = 0
         if (/Decimal/ig.test(option.props.datatype)) {
           decimal = +option.props.datatype.replace(/Decimal\(18,/ig, '').replace(')', '')
         }
-        this.props.form.setFieldsValue({decimal})
+        values.type = 'number'
+        values.decimal = decimal
+      } else if (/nvarchar/ig.test(option.props.datatype)) {
+        values.type = 'text'
+      }
+
+      if (values.type !== this.state.type) {
+        values.perspective = ''
+        let _options = fromJS(columnTypeOptions[values.type]).toJS()
+
+        this.setState({
+          type: values.type,
+          formlist: this.state.formlist.map(item => {
+            item.hidden = !_options.includes(item.key)
+
+            return item
+          })
+        }, () => {
+          this.props.form.setFieldsValue(values)
+        })
+      } else {
+        this.props.form.setFieldsValue(values)
       }
     } else if (key === 'format' && value === 'percent') {
       this.props.form.setFieldsValue({postfix: '%'})
@@ -121,9 +132,9 @@
       let _options = fromJS(columnTypeOptions[this.state.type]).toJS()
 
       if (value === 'linkmenu') {
-        _options.push('linkmenu', 'linkfields')
+        _options.push('linkmenu', 'linkfields', 'open')
       } else if (value === 'linkurl') {
-        _options.push('linkurl', 'linkfields')
+        _options.push('linkurl', 'linkfields', 'open')
       }
 
       this.setState({
@@ -157,7 +168,7 @@
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.tooltip ?
-              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+              <Tooltip placement="topLeft" title={item.tooltip}>
                 <Icon type="question-circle" />
                 {item.label}
               </Tooltip> : item.label
@@ -179,7 +190,7 @@
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.tooltip ?
-              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+              <Tooltip placement="topLeft" title={item.tooltip}>
                 <Icon type="question-circle" />
                 {item.label}
               </Tooltip> : item.label
@@ -197,7 +208,7 @@
             </Form.Item>
           </Col>
         )
-      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
+      } else if (item.type === 'select') {
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.label}>
@@ -217,8 +228,8 @@
                   getPopupContainer={() => document.getElementById('columnwinter')}
                 >
                   {item.options.map((option, index) =>
-                    <Select.Option key={`${option.value || option.field}${index}`} datatype={option.datatype || ''} value={option.value || option.field}>
-                      {option.text || option.label}
+                    <Select.Option key={index} datatype={option.datatype || ''} value={(option.value || option.field || option.MenuID)}>
+                      {(option.text || option.label || option.MenuName)}
                     </Select.Option>
                   )}
                 </Select>
@@ -230,7 +241,7 @@
         fields.push(
           <Col span={12} key={index}>
             <Form.Item label={item.tooltip ?
-              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+              <Tooltip placement="topLeft" title={item.tooltip}>
                 <Icon type="question-circle" />
                 {item.label}
               </Tooltip> : item.label
diff --git a/src/menu/components/table/normal-table/columns/index.jsx b/src/menu/components/table/normal-table/columns/index.jsx
index 2e38088..c88a996 100644
--- a/src/menu/components/table/normal-table/columns/index.jsx
+++ b/src/menu/components/table/normal-table/columns/index.jsx
@@ -37,17 +37,19 @@
 
   shouldComponentUpdate (nextProps, nextState) {
 
+    if (this.props.rowSpan !== nextProps.rowSpan || this.props.colSpan !== nextProps.colSpan) {
+      return true
+    }
+
     if (!nextProps.column) return false
 
     return !is(fromJS(this.props.column), fromJS(nextProps.column)) ||
       !is(fromJS(this.props.fields), fromJS(nextProps.fields)) ||
-      this.props.index !== nextProps.index ||
-      this.props.rowSpan !== nextProps.rowSpan ||
-      this.props.colSpan !== nextProps.colSpan
+      this.props.index !== nextProps.index
   }
 
   render() {
-    const { connectDragSource, connectDropTarget, moveCol, addElement, updateCol, editColumn, deleteCol, index, column, align, fields, children, ...restProps } = this.props
+    const { connectDragSource, connectDropTarget, moveCol, addElement, updateCol, editColumn, changeStyle, deleteCol, index, column, align, fields, children, ...restProps } = this.props
 
     if (index !== undefined) {
       return connectDragSource(
@@ -58,6 +60,7 @@
                 <Icon className="plus" title="娣诲姞" type="plus" onClick={() => this.props.addElement(column)} /> : null
               }
               <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.props.editColumn(column)} />
+              {column && column.type === 'custom' ? <Icon className="style" title="璋冩暣鏍峰紡" onClick={() => this.props.changeStyle(column)} type="font-colors" /> : null}
               <Icon className="close" title="鍒犻櫎" type="delete" onClick={this.deleteCol} />
               {column && ['text', 'number'].includes(column.type) ? <MarkColumn columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
             </div>
@@ -141,7 +144,7 @@
 
     if (column && column.type === 'custom') {
       return (
-        <td style={{padding: 0, minWidth: column.Width || 100}} className={className}>
+        <td style={{padding: 0, minWidth: column.Width || 100, ...(column.style || {})}} className={className}>
           <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
         </td>
       )
@@ -154,7 +157,7 @@
     } else if (column) {
       return (
         <td style={{...style, minWidth: column.Width || 100}} className={className}>
-          {column.field}
+          {column.field || (column.type === 'index' ? '$Index' : '')}
           {column.marks && column.marks.length ? <Icon className="profile" type="ant-design"/> : null}
         </td>
       )
@@ -176,11 +179,13 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     tableId: '',
     data: [{uuid: Utils.getuuid()}],
     refresh: false,    // 寮哄埗鍒锋柊
     columns: [],
     fields: [],
+    editStyleCard: null,
     lineMarks: []
   }
 
@@ -341,6 +346,24 @@
     this.updateCol(col)
   }
 
+  changeStyle = (col) => {
+    this.setState({
+      editStyleCard: fromJS(col).toJS()
+    })
+
+    MKEmitter.emit('changeStyle', [col.uuid], ['font', 'padding'], col.style || {})
+  }
+
+  getStyle = (comIds, style) => {
+    const { editStyleCard } = this.state
+
+    if (!editStyleCard || comIds[0] !== editStyleCard.uuid || comIds.length !== 1) return
+
+    let _card = {...editStyleCard, style}
+    
+    this.updateCol(_card)
+  }
+
   cancelCol = () => {
     const { card } = this.state
 
@@ -361,22 +384,29 @@
   }
 
   deleteCol = (col) => {
+    const { appType } = this.state
     let _columns = fromJS(this.state.columns).toJS()
-    _columns = this.loopDelCol(_columns, col)
 
-    if (col.type === 'action') {
-      let uuids = []
-      col.elements && col.elements.forEach(c => {
-        uuids.push(c.uuid)
-      })
-      MKEmitter.emit('delButtons', uuids)
-    }
+    _columns = this.loopDelCol(_columns, col)
 
     this.setState({
       columns: _columns
     }, () => {
       this.props.updatecolumn({...this.props.config, cols: _columns})
     })
+
+    if (col.type !== 'action' || appType === 'mob') return
+
+    let uuids = []
+    col.elements && col.elements.forEach(c => {
+      if (appType === 'pc' && c.OpenType !== 'popview') return
+
+      uuids.push(c.uuid)
+    })
+
+    if (uuids.length === 0) return
+    
+    MKEmitter.emit('delButtons', uuids)
   }
 
   updateLineMarks = (vals) => {
@@ -433,6 +463,7 @@
           updateCol: this.updateCol,
           addElement: this.addElement,
           editColumn: this.editColumn,
+          changeStyle: this.changeStyle,
           deleteCol: this.deleteCol,
         }),
         children: col.subcols && col.subcols.length ? this.handlecolumns(col.subcols, fields, config, true) : null,
@@ -480,6 +511,20 @@
     })
   }
 
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
   render() {
     const { config } = this.props
     const { fields, card, lineMarks, dict, tableId } = this.state
@@ -494,8 +539,16 @@
 
     const columns = this.handlecolumns(this.state.columns, fields, config)
 
+    let style = {}
+    if (config.wrap.color) {
+      style.color = config.wrap.color
+    }
+    if (config.wrap.fontSize) {
+      style.fontSize = config.wrap.fontSize
+    }
+
     return (
-      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType}`} id={tableId}>
+      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''}`} id={tableId}>
         <div className="col-control">
           <Icon title="澶嶅埗" type="copy" onClick={this.copycolumn} />
           <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
@@ -506,6 +559,7 @@
             rowKey="uuid"
             size={config.wrap.size || 'middle'}
             rowClassName="editable-row"
+            style={style}
             bordered={config.wrap.bordered !== 'false'}
             components={components}
             dataSource={this.state.data}
diff --git a/src/menu/components/table/normal-table/columns/index.scss b/src/menu/components/table/normal-table/columns/index.scss
index 41f4111..5c733b7 100644
--- a/src/menu/components/table/normal-table/columns/index.scss
+++ b/src/menu/components/table/normal-table/columns/index.scss
@@ -1,5 +1,9 @@
 .normal-table-columns {
   position: relative;
+  .ant-table {
+    color: inherit;
+    font-size: inherit;
+  }
   .ant-table-body {
     overflow-x: auto;
     tr {
@@ -89,3 +93,29 @@
     border-radius: 0;
   }
 }
+
+.normal-table-columns.ghost {
+  .ant-table-thead > tr {
+    > th {
+      color: inherit;
+      background: transparent;
+      .ant-table-column-sorter .ant-table-column-sorter-inner {
+        color: inherit;
+      }
+    }
+    > th:hover {
+      background: transparent;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto;
+    tr {
+      td {
+        background: transparent;
+      }
+    }
+    tr:hover td {
+      background: transparent!important;
+    }
+  }
+}
diff --git a/src/menu/components/table/normal-table/index.jsx b/src/menu/components/table/normal-table/index.jsx
index cd1a336..4bd4dd7 100644
--- a/src/menu/components/table/normal-table/index.jsx
+++ b/src/menu/components/table/normal-table/index.jsx
@@ -5,7 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
-
+import { resetStyle } from '@/utils/utils-custom.js'
 import MKEmitter from '@/utils/events.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
@@ -35,6 +35,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     card: null,
     back: false
   }
@@ -60,9 +61,9 @@
           { origin: true, uuid: Utils.getuuid(), label: 'label', type: 'date', match: 'greater' }
         ],
         action: [
-          { origin: true, uuid: Utils.getuuid(), label: '娣诲姞', intertype: 'system', OpenType: 'pop', icon: 'plus', class: 'green', btnstyle: {color: 'rgb(255, 255, 255)', background: 'rgb(38, 194, 129)', marginRight: '15px'} },
-          { origin: true, uuid: Utils.getuuid(), label: '淇敼', intertype: 'system', OpenType: 'pop', icon: 'form', class: 'purple', btnstyle: {color: 'rgb(255, 255, 255)', background: 'rgb(142, 68, 173)', marginRight: '15px'} },
-          { origin: true, uuid: Utils.getuuid(), label: '鍒犻櫎', intertype: 'system', OpenType: 'prompt', icon: 'delete', class: 'danger', btnstyle: {color: 'rgb(255, 255, 255)', background: 'rgb(255, 77, 79)', marginRight: '15px'} }
+          { origin: true, uuid: Utils.getuuid(), label: '娣诲姞', intertype: 'system', OpenType: 'pop', icon: 'plus', class: 'green', style: {color: 'rgb(255, 255, 255)', background: 'rgb(38, 194, 129)', marginRight: '15px'} },
+          { origin: true, uuid: Utils.getuuid(), label: '淇敼', intertype: 'system', OpenType: 'pop', icon: 'form', class: 'purple', style: {color: 'rgb(255, 255, 255)', background: 'rgb(142, 68, 173)', marginRight: '15px'} },
+          { origin: true, uuid: Utils.getuuid(), label: '鍒犻櫎', intertype: 'system', OpenType: 'prompt', icon: 'delete', class: 'danger', style: {color: 'rgb(255, 255, 255)', background: 'rgb(255, 77, 79)', marginRight: '15px'} }
         ],
         name: card.name,
         subtype: card.subtype,
@@ -88,8 +89,11 @@
         _card.style = config.style
         _card.headerStyle = config.headerStyle
 
+        let oriUids = {}
         _card.action = config.action.map(item => {
-          item.uuid = Utils.getuuid()
+          let _uuid = Utils.getuuid()
+          oriUids[item.uuid] = _uuid
+          item.uuid = _uuid
           return item
         })
         _card.search = config.search.map(item => {
@@ -113,6 +117,10 @@
           }
           return col
         })
+        
+        if (_card.wrap.doubleClick) {
+          _card.wrap.doubleClick = oriUids[_card.wrap.doubleClick] || ''
+        }
       }
       
       this.setState({
@@ -274,7 +282,7 @@
     newcard.errorTime = 10
     newcard.verify = null
     newcard.show = 'button'
-    newcard.btnstyle = {marginRight: '15px'}
+    newcard.style = {marginRight: '15px'}
 
     // 娉ㄥ唽浜嬩欢-娣诲姞鎸夐挳
     MKEmitter.emit('addButton', card.uuid, newcard)
@@ -291,13 +299,13 @@
   }
 
   setSubConfig = (item) => {
-    const { card } = this.state
+    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: 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
+          setting: { title: btn.label, width: appType === 'mob' ? 100 : 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
           tables: [],
           groups: [],
           fields: []
@@ -378,15 +386,16 @@
   }
 
   render() {
-    const { card } = this.state
+    const { card, appType } = this.state
+    let _style = resetStyle(card.style)
 
     return (
-      <div className="menu-normal-table-edit-box" style={{...card.style, height: card.wrap.height}} onClick={this.clickComponent} id={card.uuid}>
+      <div className="menu-normal-table-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
         <NormalHeader defaultshow="hidden" hideSearch="true" config={card} updateComponent={this.updateComponent}/>
         <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
           <div className="mk-popover-control">
             <Icon className="plus" title="娣诲姞鍒�" onClick={this.addColumns} type="plus" />
-            <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" />
+            {appType !== 'mob' ? <Icon className="plus" title="娣诲姞鎼滅储" onClick={this.addSearch} type="plus-circle" /> : null}
             <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
             <WrapComponent config={card} updateConfig={this.updateComponent} />
             <CopyComponent type="normaltable" card={card}/>
diff --git a/src/menu/components/table/normal-table/wrapsetting/index.jsx b/src/menu/components/table/normal-table/wrapsetting/index.jsx
index be1ea1b..d5772f8 100644
--- a/src/menu/components/table/normal-table/wrapsetting/index.jsx
+++ b/src/menu/components/table/normal-table/wrapsetting/index.jsx
@@ -60,7 +60,7 @@
           wrapClassName="popview-modal"
           title="琛ㄦ牸璁剧疆"
           visible={visible}
-          width={700}
+          width={750}
           maskClosable={false}
           okText={dict['model.submit']}
           onOk={this.verifySubmit}
diff --git a/src/menu/components/table/normal-table/wrapsetting/settingform/index.jsx b/src/menu/components/table/normal-table/wrapsetting/settingform/index.jsx
index 77ea6f9..f42f1a5 100644
--- a/src/menu/components/table/normal-table/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/table/normal-table/wrapsetting/settingform/index.jsx
@@ -14,7 +14,8 @@
   }
 
   state = {
-    roleList: []
+    roleList: [],
+    appType: sessionStorage.getItem('appType')
   }
 
   UNSAFE_componentWillMount () {
@@ -56,7 +57,7 @@
   render() {
     const { wrap, config } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList } = this.state
+    const { roleList, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -135,6 +136,18 @@
                 )}
               </Form.Item>
             </Col>
+            {appType !== 'mob' ? <Col span={12}>
+              <Form.Item label="鍙敹璧�">
+                {getFieldDecorator('collapse', {
+                  initialValue: wrap.collapse || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio key="true" value="true"> 鏄� </Radio>
+                    <Radio key="false" value="false"> 鍚� </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label="琛ㄦ牸澶у皬">
                 {getFieldDecorator('size', {
@@ -163,6 +176,39 @@
               </Form.Item>
             </Col>
             <Col span={12}>
+              <Form.Item label="妯″紡">
+                {getFieldDecorator('mode', {
+                  initialValue: wrap.mode || 'default'
+                })(
+                  <Radio.Group>
+                    <Radio key="default" value="default"> 甯歌 </Radio>
+                    <Radio key="ghost" value="ghost"> 閫忔槑 </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12} style={{height: '64px'}}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="榛樿鍊� rgba(0, 0, 0, 0.65)銆�">
+                  <Icon type="question-circle" />
+                  瀛椾綋棰滆壊
+                </Tooltip>
+              }>
+                {getFieldDecorator('color', {
+                  initialValue: wrap.color || 'rgba(0, 0, 0, 0.65)'
+                })(
+                  <ColorSketch />
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="瀛椾綋澶у皬">
+                {getFieldDecorator('fontSize', {
+                  initialValue: wrap.fontSize || 14
+                })(<InputNumber min={14} max={30} precision={0} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
                   <Icon type="question-circle" />
@@ -180,7 +226,19 @@
                 })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {appType !== 'mob' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="楂樼骇鎼滅储寮圭獥鐨勫搴︼紝娉細褰撳搴﹀�煎皬浜�100鏃惰〃绀哄崰绐楀彛鐨勭櫨鍒嗘瘮锛屽ぇ浜�100鏃惰〃绀哄搴︾殑缁濆鍊笺��">
+                  <Icon type="question-circle" />
+                  楂樼骇鎼滅储
+                </Tooltip>
+              }>
+                {getFieldDecorator('advanceWidth', {
+                  initialValue: wrap.advanceWidth || 1000
+                })(<InputNumber min={10} max={3000} precision={0} onPressEnter={this.handleSubmit}/>)}
+              </Form.Item>
+            </Col> : null}
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="鍙屽嚮琛ㄦ牸涓锛岃Е鍙戠殑鎸夐挳銆�">
                   <Icon type="question-circle" />
@@ -197,7 +255,7 @@
                   </Select>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label="榛戝悕鍗�">
                 {getFieldDecorator('blacklist', {
diff --git a/src/menu/components/tabs/antv-tabs/dragabletabs.jsx b/src/menu/components/tabs/antv-tabs/dragabletabs.jsx
index 74ef3ef..b2d7ef7 100644
--- a/src/menu/components/tabs/antv-tabs/dragabletabs.jsx
+++ b/src/menu/components/tabs/antv-tabs/dragabletabs.jsx
@@ -1,5 +1,6 @@
 import React, { Component } from 'react'
 import { Tabs } from 'antd'
+import { is, fromJS } from 'immutable'
 import { DndProvider, DragSource, DropTarget } from 'react-dnd'
 
 // Drag & Drop node
@@ -52,8 +53,6 @@
     const newOrder = this.state.order.slice()
     const { children } = this.props
 
-    if (dragKey === 'tool' || hoverKey === 'tool') return
-
     React.Children.forEach(children, c => {
       if (newOrder.indexOf(c.key) === -1) {
         newOrder.push(c.key)
@@ -65,12 +64,11 @@
 
     newOrder.splice(dragIndex, 1)
     newOrder.splice(hoverIndex, 0, dragKey)
-    let _order = newOrder.filter(item => item !== 'tool')
     
     this.setState({
-      order: [..._order, 'tool']
+      order: newOrder
     })
-    this.props.tabsMove(_order)
+    this.props.tabsMove(newOrder)
   }
 
   renderTabBar = (props, DefaultTabBar) => (
@@ -83,10 +81,16 @@
     </DefaultTabBar>
   )
 
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState)) ||
+      !is(fromJS(nextProps.children), fromJS(this.props.children)) ||
+      nextProps.tabPosition !== this.props.tabPosition ||
+      nextProps.type !== this.props.type
+  }
+
   render() {
     const { order } = this.state
     const { children } = this.props
-
     const tabs = []
     React.Children.forEach(children, c => {
       tabs.push(c)
diff --git a/src/menu/components/tabs/antv-tabs/index.jsx b/src/menu/components/tabs/antv-tabs/index.jsx
index 3879bea..0cb7d7d 100644
--- a/src/menu/components/tabs/antv-tabs/index.jsx
+++ b/src/menu/components/tabs/antv-tabs/index.jsx
@@ -7,7 +7,8 @@
 import asyncComponent from '@/utils/asyncComponent'
 import asyncIconComponent from '@/utils/asyncIconComponent'
 import DraggableTabs from './dragabletabs'
-
+import { resetStyle } from '@/utils/utils-custom.js'
+import MenuUtils from '@/utils/utils-custom.js'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/model.js'
 import enUS from '@/locales/en-US/model.js'
@@ -31,6 +32,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     tabs: null,
     editab: null,
     labelvisible: false
@@ -74,6 +76,7 @@
 
   componentDidMount () {
     MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('submitSearch', this.getSearch)
     MKEmitter.addListener('tabsChange', this.handleTabsChange)
     MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
   }
@@ -86,6 +89,7 @@
       return
     }
     MKEmitter.removeListener('submitStyle', this.getStyle)
+    MKEmitter.removeListener('submitSearch', this.getSearch)
     MKEmitter.removeListener('tabsChange', this.handleTabsChange)
     MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
   }
@@ -215,6 +219,7 @@
     this.tabLabelRef.handleConfirm().then(res => {
       editab.label = res.label
       editab.icon = res.icon
+      editab.hasSearch = res.hasSearch || ''
       editab.blacklist = res.blacklist
 
       if (editab.uuid) {
@@ -245,12 +250,18 @@
 
     tabs.subtabs = tabs.subtabs.filter(t => t.uuid !== tab.uuid)
 
+    let uuids = MenuUtils.getDelButtonIds({...tab, type: 'group'})
+
     confirm({
       title: '纭畾鍒犻櫎鏍囩锛�',
       content: '',
       onOk() {
         _this.setState({tabs})
         _this.props.updateConfig(tabs)
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -288,6 +299,45 @@
     this.props.updateConfig(tabs)
   }
 
+  getSearch = (config) => {
+    const { tabs } = this.state
+
+    if (tabs.uuid !== config.uuid) return
+
+    let _tabs = fromJS(tabs).toJS()
+
+    _tabs.subtabs = _tabs.subtabs.map(t => {
+      if (t.uuid === config.tabId) {
+        t.search = config.search
+      }
+      return t
+    })
+
+    this.setState({
+      tabs: _tabs
+    })
+    this.props.updateConfig(_tabs)
+  }
+
+  setSearch = (tab) => {
+    const { tabs } = this.state
+    let card = {
+      uuid: tabs.uuid,
+      tabId: tab.uuid,
+      search: tab.search
+    }
+
+    if (!card.search) {
+      card.search = {
+        floor: 1,
+        setting: { type: 'title', field: '', title: '', focus: 'true', btn: 'hidden' },
+        groups: [],
+        fields: []
+      }
+    }
+    MKEmitter.emit('changeSearch', card)
+  }
+
   clickComponent = (e) => {
     if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
       e.stopPropagation()
@@ -296,9 +346,11 @@
   }
 
   render() {
-    const { tabs, dict, labelvisible, editab } = this.state
+    const { tabs, dict, labelvisible, editab, appType } = this.state
+    let _style = resetStyle(tabs.style)
+
     return (
-      <div className="menu-tabs-edit-box" style={tabs.style} onClick={this.clickComponent} id={tabs.uuid}>
+      <div className={'menu-tabs-edit-box ' + tabs.setting.display} style={_style} onClick={this.clickComponent} id={tabs.uuid}>
         <DraggableTabs tabPosition={tabs.setting.position} type={tabs.setting.tabStyle} tabsMove={this.moveSwitch}>
           {tabs.subtabs.map(tab => (
             <TabPane tab={
@@ -312,24 +364,23 @@
                 <span>{tab.icon ? <Icon type={tab.icon} /> : null}{tab.label}</span>
               </Popover>
             } key={tab.uuid}>
+              {appType === 'mob' && tabs.setting.position === 'top' && tabs.setting.display === 'inline-block' && tab.hasSearch === 'icon' ?
+                <Icon className="search-icon" onDoubleClick={() => this.setSearch(tab)} type="search" /> : null}
               <TabComponents config={tab} handleList={this.updateTabComponent} deleteCard={this.deleteCard} />
             </TabPane>
           ))}
-          <TabPane disabled tab={
-            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
-              <div className="mk-popover-control">
-                <Icon className="plus" title="娣诲姞鏍囩" type="plus" onClick={this.tabAdd} />
-                <SettingComponent config={tabs} updateConfig={this.updateComponent} />
-                <CopyComponent type="tabs" card={tabs}/>
-                <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
-                <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(tabs.uuid)} />
-              </div>
-            } trigger="hover">
-              <Icon type="tool" />
-            </Popover>
-          } key="tool">
-          </TabPane>
         </DraggableTabs>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="plus" title="娣诲姞鏍囩" type="plus" onClick={this.tabAdd} />
+            <SettingComponent config={tabs} updateConfig={this.updateComponent} />
+            <CopyComponent type="tabs" card={tabs}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(tabs.uuid)} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
         <Modal
           wrapClassName="popview-modal"
           title={'鏍囩缂栬緫'}
@@ -344,6 +395,7 @@
           <TabLabelComponent
             dict={dict}
             tab={editab}
+            setting={tabs.setting}
             inputSubmit={this.tabLabelSubmit}
             wrappedComponentRef={(inst) => this.tabLabelRef = inst}
           />
diff --git a/src/menu/components/tabs/antv-tabs/index.scss b/src/menu/components/tabs/antv-tabs/index.scss
index ceee292..7ad16c9 100644
--- a/src/menu/components/tabs/antv-tabs/index.scss
+++ b/src/menu/components/tabs/antv-tabs/index.scss
@@ -6,6 +6,23 @@
   background-repeat: no-repeat;
   background-size: cover;
 
+  >.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);
+  }
+
+  .ant-tabs.ant-tabs-left, .ant-tabs.ant-tabs-bottom {
+    .tab-shell-inner {
+      padding-top: 25px;
+    }
+  }
+
   .ant-tabs-tabpane-active {
     min-height: 200px;
   }
@@ -20,41 +37,25 @@
   }
   
   .ant-tabs .ant-tabs-left-bar .ant-tabs-tab {
-    padding: 0px;
     text-align: right;
     > span {
       display: inline-block;
       padding: 8px 24px;
     }
-    .anticon-tool {
-      padding: 8px 24px;
-    }
   }
   .ant-tabs .ant-tabs-right-bar .ant-tabs-tab {
-    padding: 0px;
     text-align: left;
     > span {
       display: inline-block;
       padding: 8px 24px;
     }
-    .anticon-tool {
-      padding: 8px 24px;
-    }
   }
   .ant-tabs-tab {
-    padding: 0px;
+    padding: 0px!important;
     text-align: center;
     > span {
       display: inline-block;
       padding: 12px 16px;
-    }
-    .anticon-tool {
-      color: rgba(0, 0, 0, 0.65);
-      font-size: 16px;
-      padding: 12px 16px;
-      margin-right: 0px;
-      min-width: 100%;
-      cursor: pointer;
     }
   }
   .ant-tabs-bottom .ant-tabs-bottom-bar .ant-tabs-ink-bar {
@@ -66,9 +67,6 @@
         > span {
           padding: 0px 16px;
         }
-        .anticon-tool {
-          padding: 0px 16px;
-        }
       }
       .ant-tabs-tab-active {
         padding-left: 0px!important;
@@ -78,24 +76,47 @@
     
     .ant-tabs-card-bar {
       .ant-tabs-tab {
-        padding: 0px;
         > span {
           display: inline-block;
           padding: 0px 16px;
         }
       }
-      .ant-tabs-tab:last-child {
-        padding: 0px;
-        border: 0px;
-        background: transparent;
-        .anticon-tool {
-          padding: 12px 16px;
-        }
-      }
     }
+  }
+  .search-icon {
+    position: absolute;
+    top: 10px;
+    right: 40px;
+    font-size: 18px;
+    cursor: pointer;
+    padding: 3px;
   }
 }
 .menu-tabs-edit-box:hover {
   z-index: 1;
   box-shadow: 0px 0px 4px #1890ff;
 }
+
+.mob-shell {
+  .menu-tabs-edit-box.flex {
+    >.ant-tabs.ant-tabs-top, >.ant-tabs.ant-tabs-bottom {
+      >.ant-tabs-bar {
+        >.ant-tabs-nav-container {
+          >.ant-tabs-nav-wrap {
+            >.ant-tabs-nav-scroll {
+              >.ant-tabs-nav {
+                display: block;
+                >div {
+                  display: flex;
+                  >.ant-tabs-tab {
+                    flex: 1;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx
index ca9c1fe..32d1080 100644
--- a/src/menu/components/tabs/tabcomponents/card.jsx
+++ b/src/menu/components/tabs/tabcomponents/card.jsx
@@ -7,15 +7,20 @@
 const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
 const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
+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 PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
+const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
+const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
+const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -57,6 +62,14 @@
       return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'dashboard') {
+      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'tree') {
+      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'scatter') {
+      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'form') {
+      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'tabs') {
       return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard} />)
     } else if (card.type === 'card' && card.subtype === 'datacard') {
@@ -75,6 +88,8 @@
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'editor') {
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'code') {
+      return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
 
diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx
index 7a913bc..412a698 100644
--- a/src/menu/components/tabs/tabcomponents/index.jsx
+++ b/src/menu/components/tabs/tabcomponents/index.jsx
@@ -54,8 +54,11 @@
       title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
-        MKEmitter.emit('delButtons', uuids)
         handleList({...config, components: cards.filter(item => item.uuid !== card.uuid)})
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -89,7 +92,7 @@
 
       let name = ''
       let names = {
-        bar: '鏌辩姸鍥�',
+        bbar: '鏌辩姸鍥�',
         line: '鎶樼嚎鍥�',
         tabs: '鏍囩缁�',
         pie: '楗煎浘',
@@ -97,7 +100,12 @@
         table: '琛ㄦ牸',
         group: '鍒嗙粍',
         editor: '瀵屾枃鏈�',
+        code: '鑷畾涔�',
         carousel: '杞挱',
+        form: '琛ㄥ崟',
+        dashboard: '浠〃鐩�',
+        scatter: '鏁g偣鍥�',
+        tree: '鏍戝舰鍒楄〃',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/components/tabs/tabcomponents/index.scss b/src/menu/components/tabs/tabcomponents/index.scss
index b65895c..f21f784 100644
--- a/src/menu/components/tabs/tabcomponents/index.scss
+++ b/src/menu/components/tabs/tabcomponents/index.scss
@@ -1,9 +1,6 @@
 .tab-shell-inner {
-  margin: -8px;
+  margin: 0px;
 
-  >.ant-col {
-    padding: 8px;
-  }
   .anticon {
     cursor: unset;
   }
diff --git a/src/menu/components/tabs/tablabelform/index.jsx b/src/menu/components/tabs/tablabelform/index.jsx
index 784a9f9..335976a 100644
--- a/src/menu/components/tabs/tablabelform/index.jsx
+++ b/src/menu/components/tabs/tablabelform/index.jsx
@@ -1,18 +1,18 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Icon, Select } from 'antd'
+import { Form, Row, Col, Input, Icon, Select, Radio } from 'antd'
 
-// import { formRule } from '@/utils/option.js'
 import './index.scss'
 
 class SettingForm extends Component {
   static propTpyes = {
-    dict: PropTypes.object,        // 瀛楀吀椤�
-    tab: PropTypes.object,         // 鏁版嵁婧愰厤缃�
-    inputSubmit: PropTypes.func    // 鍥炶溅浜嬩欢
+    dict: PropTypes.object,
+    setting: PropTypes.object,
+    tab: PropTypes.object,
+    inputSubmit: PropTypes.func
   }
 
-  state = {roleList: []}
+  state = {roleList: [], appType: sessionStorage.getItem('appType')}
 
   UNSAFE_componentWillMount () {
     let roleList = sessionStorage.getItem('sysRoles')
@@ -51,9 +51,9 @@
   }
 
   render() {
-    const { tab } = this.props
+    const { tab, setting } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList } = this.state
+    const { roleList, appType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -97,6 +97,18 @@
               )}
             </Form.Item>
           </Col>
+          {appType === 'mob' && setting.position === 'top' && setting.display === 'inline-block' ? <Col span={24}>
+            <Form.Item label="鎼滅储">
+              {getFieldDecorator('hasSearch', {
+                initialValue: tab.hasSearch || 'false'
+              })(
+                <Radio.Group>
+                  <Radio value="false">鏃�</Radio>
+                  <Radio value="icon">鏈�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
           <Col span={24}>
             <Form.Item label="榛戝悕鍗�">
               {getFieldDecorator('blacklist', {
diff --git a/src/menu/components/tabs/tabsetting/settingform/index.jsx b/src/menu/components/tabs/tabsetting/settingform/index.jsx
index 6362d5a..a8190c2 100644
--- a/src/menu/components/tabs/tabsetting/settingform/index.jsx
+++ b/src/menu/components/tabs/tabsetting/settingform/index.jsx
@@ -12,6 +12,8 @@
   }
 
   state = {
+    appType: sessionStorage.getItem('appType'),
+    position: this.props.setting.position,
     roleList: []
   }
 
@@ -54,7 +56,7 @@
   render() {
     const { setting } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList } = this.state
+    const { roleList, appType, position } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -112,7 +114,7 @@
                 {getFieldDecorator('position', {
                   initialValue: setting.position || 'top'
                 })(
-                  <Select>
+                  <Select onChange={(val) => this.setState({position: val})}>
                     <Select.Option key="top" value="top"> top </Select.Option>
                     <Select.Option key="bottom" value="bottom"> bottom </Select.Option>
                     <Select.Option key="left" value="left"> left </Select.Option>
@@ -121,7 +123,7 @@
                 )}
               </Form.Item>
             </Col>
-            <Col span={12}>
+            {appType !== 'mob' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="鏍囩浣嶇疆涓簍op鏃舵湁鏁堬紝榛樿鍊间负line銆�">
                   <Icon type="question-circle" />
@@ -137,7 +139,19 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
+            {appType === 'mob' && (position === 'top' || position === 'bottom') ? <Col span={12}>
+              <Form.Item label="鏍囩鏄剧ず">
+                {getFieldDecorator('display', {
+                  initialValue: setting.display || 'flex'
+                })(
+                  <Radio.Group>
+                    <Radio value="flex">寮规�у竷灞�</Radio>
+                    <Radio value="inline-block">瀹氬</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label="榛戝悕鍗�">
                 {getFieldDecorator('blacklist', {
diff --git a/src/menu/components/tree/antd-tree/index.jsx b/src/menu/components/tree/antd-tree/index.jsx
new file mode 100644
index 0000000..18f83e7
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/index.jsx
@@ -0,0 +1,188 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, Tree } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+import './index.scss'
+
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+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 WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+
+const { TreeNode } = Tree
+
+class AntdTree extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        dataName: card.dataName || '',
+        format: 'array',    // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: true,   // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        width: card.width || 12,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, title: '', width: card.width || 12, showIcon: 'false', showLine: 'false', searchable: 'false' },
+        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        columns: [],
+        scripts: [],
+      }
+
+      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
+      }
+      
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid || comIds.length !== 1) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  /**
+   * @description 鏇存柊鎼滅储鏉′欢閰嶇疆淇℃伅
+   */
+  updateconfig = (config) => {
+    this.setState({
+      card: config
+    })
+    this.props.updateConfig(config)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card } = this.state
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-editor-sand-box" 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">
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <CopyComponent type="normaltable" card={card}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            <SettingComponent config={card} updateConfig={this.updateComponent} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <div className="tree-box">
+          <Tree defaultExpandAll={true} blockNode showIcon={card.wrap.showIcon === 'true'} showLine={card.wrap.showLine === 'true'} >
+            <TreeNode icon={<Icon type="folder-open" />} title="parent 0" key="0-0">
+              <TreeNode icon={<Icon type="file" />} title="leaf 0-0" key="0-0-0" isLeaf />
+              <TreeNode icon={<Icon type="file" />} title="leaf 0-1" key="0-0-1" isLeaf />
+            </TreeNode>
+            <TreeNode icon={<Icon type="folder-open" />} title="parent 1" key="0-1">
+              <TreeNode icon={<Icon type="file" />} title="leaf 1-0" key="0-1-0" isLeaf />
+              <TreeNode icon={<Icon type="file" />} title="leaf 1-1" key="0-1-1" isLeaf />
+            </TreeNode>
+          </Tree>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default AntdTree
\ No newline at end of file
diff --git a/src/menu/components/tree/antd-tree/index.scss b/src/menu/components/tree/antd-tree/index.scss
new file mode 100644
index 0000000..c096ca8
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/index.scss
@@ -0,0 +1,36 @@
+.menu-editor-sand-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 30px;
+
+  .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);
+  }
+  .empty-content {
+    text-align: center;
+    font-size: 30px;
+    margin: 0;
+    line-height: 90px;
+    color: #bcbcbc;
+  }
+}
+.menu-editor-sand-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-editor-sand-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/tree/antd-tree/wrapsetting/index.jsx b/src/menu/components/tree/antd-tree/wrapsetting/index.jsx
new file mode 100644
index 0000000..595cb9e
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/wrapsetting/index.jsx
@@ -0,0 +1,83 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="鍩烘湰璁剧疆"
+          visible={visible}
+          width={700}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            config={config}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/menu/components/tree/antd-tree/wrapsetting/index.scss b/src/menu/components/tree/antd-tree/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.jsx b/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..d1a1479
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.jsx
@@ -0,0 +1,262 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    roleList: [],
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    this.setState({roleList})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { wrap, config } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { roleList } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="鏍囬">
+                {getFieldDecorator('title', {
+                  initialValue: wrap.title || ''
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏁版嵁鍊煎瓧娈点��">
+                  <Icon type="question-circle" />
+                  Value
+                </Tooltip>
+              }>
+                {getFieldDecorator('valueField', {
+                  initialValue: wrap.valueField || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + 'Value瀛楁!'
+                    }
+                  ]
+                })(
+                  <Select>
+                    {config.columns.map(option =>
+                      <Select.Option key={option.uuid} value={option.field}>{option.label}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏄剧ず鏂囧瓧瀛楁銆�">
+                  <Icon type="question-circle" />
+                  Label
+                </Tooltip>
+              }>
+                {getFieldDecorator('labelField', {
+                  initialValue: wrap.labelField || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + 'Label瀛楁!'
+                    }
+                  ]
+                })(
+                  <Select>
+                    {config.columns.map(option =>
+                      <Select.Option key={option.uuid} value={option.field}>{option.label}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐖剁骇瀛楁銆�">
+                  <Icon type="question-circle" />
+                  Parent
+                </Tooltip>
+              }>
+                {getFieldDecorator('parentField', {
+                  initialValue: wrap.parentField || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + 'Parent瀛楁!'
+                    }
+                  ]
+                })(
+                  <Select>
+                    {config.columns.map(option =>
+                      <Select.Option key={option.uuid} value={option.field}>{option.label}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title={'鐖剁骇瀛楁鍊间笌椤剁骇鏍囪瘑鐩稿悓鏃讹紝瑙嗕负椤剁骇鑺傜偣銆�'}>
+                  <Icon type="question-circle" />
+                  椤剁骇鏍囪瘑
+                </Tooltip>
+              }>
+                {getFieldDecorator('mark', {
+                  initialValue: wrap.mark || ''
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鍥炬爣">
+                {getFieldDecorator('showIcon', {
+                  initialValue: wrap.showIcon || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鍒嗗壊绾�">
+                {getFieldDecorator('showLine', {
+                  initialValue: wrap.showLine || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="杩囨护鏉′欢">
+                {getFieldDecorator('searchable', {
+                  initialValue: wrap.searchable || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.blacklist || []
+                })(
+                  <Select
+                    showSearch
+                    mode="multiple"
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {roleList.map(option =>
+                      <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.scss b/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..c530b18
--- /dev/null
+++ b/src/menu/components/tree/antd-tree/wrapsetting/settingform/index.scss
@@ -0,0 +1,15 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .color-sketch-block {
+    position: relative;
+    top: 7px;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/datasource/index.jsx b/src/menu/datasource/index.jsx
index 9732b5a..8115d65 100644
--- a/src/menu/datasource/index.jsx
+++ b/src/menu/datasource/index.jsx
@@ -16,6 +16,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     sourcelist: [],
     mainSearch: [],
     visible: false,
@@ -35,42 +36,129 @@
 
   editDataSource = () => {
     const { config } = this.props
+    const { appType } = this.state
 
     let search = []
-    let parents = []
-    let _conf = config
-    let getParents = (box) => {
-      box.components.forEach(item => {
-        if (item.type !== 'tabs') return
+    let menu = fromJS(window.GLOB.customMenu).toJS()
 
-        item.subtabs.forEach(tab => {
-          if (_conf.parentId === tab.parentId && _conf.tabId === tab.uuid) {
-            parents.unshift(tab)
-            _conf = item
-
-            if (_conf.parentId && _conf.tabId) {
-              getParents(tab)
-            }
-          } else {
-            getParents(tab)
-          }
-        })
-      })
-    }
-
-    if (config.parentId && config.tabId) {
-      getParents(window.GLOB.customMenu)
-    }
-
-    parents.unshift(window.GLOB.customMenu)
-
-    parents.forEach(parent => {
-      parent.components.forEach(item => {
-        if (item.type === 'search') {
-          search = item.search
+    if (appType === 'mob') {
+      let ms = null
+      menu.components.forEach(item => {
+        if (item.type === 'topbar' && (item.wrap.type === 'search' || (item.wrap.type === 'navbar' && item.wrap.search === 'true'))) {
+          ms = item.search
         }
       })
-    })
+
+      if (config.floor > 1) {
+        let _search = null
+        let filterComponent = (box) => {
+          box.components.forEach(item => {
+            if (_search) return
+
+            if (item.uuid === config.uuid) {
+              _search = box.slist.pop()
+            } else if (item.type === 'group') {
+              item.components.forEach(m => {
+                if (m.uuid !== config.uuid) return
+                _search = box.slist.pop()
+              })
+            } else if (item.type === 'tabs') {
+              let able = item.setting.display === 'inline-block' && item.setting.position === 'top'
+              item.subtabs.forEach(tab => {
+                if (able && tab.hasSearch === 'icon' && tab.search) {
+                  tab.slist = [...box.slist, tab.search]
+                } else {
+                  tab.slist = [...box.slist]
+                }
+                
+                filterComponent(tab)
+              })
+            }
+          })
+        }
+        menu.slist = []
+        filterComponent(menu)
+
+        if (_search) {
+          ms = _search
+        }
+      }
+
+      if (ms) {
+        if (ms.setting.type === 'search') {
+          search.push({
+            type: 'text',
+            label: '鎼滅储鏍�',
+            field: ms.setting.field,
+            match: ms.setting.match,
+            required: ms.setting.required,
+            value: ms.setting.initval || ''
+          })
+        }
+        ms.fields.forEach(item => {
+          if (item.type === 'range') {
+            item.initval = `${item.minValue},${item.maxValue}`
+          }
+          search.push(item)
+        })
+
+        ms.groups.forEach(group => {
+          if (group.setting.type === 'search') {
+            search.push({
+              type: 'text',
+              label: group.wrap.name,
+              field: group.setting.field,
+              match: group.setting.match,
+              required: group.setting.required,
+              value: group.setting.initval || ''
+            })
+          }
+
+          group.fields.forEach(item => {
+            if (item.type === 'range') {
+              item.initval = `${item.minValue},${item.maxValue}`
+            }
+            search.push(item)
+          })
+        })
+      }
+    } else {
+      if (config.floor > 1) {
+        let _search = null
+        let filterComponent = (box) => {
+          box.components.forEach(item => {
+            if (_search) return
+
+            if (item.type === 'search') {
+              box.slist = [...box.slist, item.search]
+            } else if (item.uuid === config.uuid) {
+              _search = box.slist.pop()
+            } else if (item.type === 'group') {
+              item.components.forEach(m => {
+                if (m.uuid !== config.uuid) return
+                _search = box.slist.pop()
+              })
+            } else if (item.type === 'tabs') {
+              item.subtabs.forEach(tab => {
+                tab.slist = [...box.slist]
+                filterComponent(tab)
+              })
+            }
+          })
+        }
+        menu.slist = []
+        filterComponent(menu)
+
+        if (_search) {
+          search = _search
+        }
+      } else {
+        menu.components.forEach(item => {
+          if (item.type !== 'search') return
+          search = item.search
+        })
+      }
+    }
 
     this.setState({
       visible: true,
@@ -100,7 +188,19 @@
           return item
         })
       }
-      
+
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          if (res.setting.dataresource) {
+            res.setting.dataresource = res.setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+        })
+      }
+
       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 24e92d2..27fb640 100644
--- a/src/menu/datasource/verifycard/customscript/index.jsx
+++ b/src/menu/datasource/verifycard/customscript/index.jsx
@@ -32,9 +32,7 @@
       if (!item.field) return
 
       if (item.type === 'group') {
-        if (item.transfer === 'true') {
-          _usefulFields.push(item.field)
-        }
+        _usefulFields.push(item.field)
         _usefulFields.push(item.datefield)
         _usefulFields.push(item.datefield + '1')
       } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
@@ -60,9 +58,7 @@
         if (!item.field) return
 
         if (item.type === 'group') {
-          if (item.transfer === 'true') {
-            _usefulFields.push(item.field)
-          }
+          _usefulFields.push(item.field)
           _usefulFields.push(item.datefield)
           _usefulFields.push(item.datefield + '1')
         } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
@@ -220,7 +216,7 @@
           </Col>
           <Col span={24} className="sqlfield">
             <Form.Item label={'鍙敤瀛楁'}>
-              id, bid, loginuid, sessionuid, userid, username, fullname, login_city, appkey, time_id, orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}
+              id, bid, loginuid, sessionuid, userid, username, fullname, login_city, appkey, time_id, orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}{window.GLOB.urlFields && window.GLOB.urlFields.length > 0 ? ', ' + window.GLOB.urlFields.join(', ') : ''}
             </Form.Item>
           </Col>
           <Col span={10} style={{width: '43%'}}>
diff --git a/src/menu/datasource/verifycard/index.jsx b/src/menu/datasource/verifycard/index.jsx
index 18aba05..2e247f9 100644
--- a/src/menu/datasource/verifycard/index.jsx
+++ b/src/menu/datasource/verifycard/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Form, Tabs, Popconfirm, Icon, notification, Modal, Typography, Spin } from 'antd'
+import { Form, Tabs, Popconfirm, Icon, notification, Modal, Typography, Spin, message } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -34,6 +34,7 @@
     initsql: '',          // sql楠岃瘉鏃跺彉閲忓0鏄庡強璧嬪��
     usefulfields: '',
     defaultsql: '',       // 榛樿Sql
+    defaultSearch: '',
     systemScripts: [],
     colColumns: [
       {
@@ -49,6 +50,7 @@
         inputType: 'input',
         editable: true,
         unique: true,
+        copy: true,
         width: '28%'
       },
       {
@@ -193,12 +195,32 @@
     getcomponentmarks(menu, config)
 
     let _setting = fromJS(config.setting).toJS()
+    let scripts = fromJS(config.scripts).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+        scripts && scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+      })
+    }
+
+    let _search = this.formatSearch(search)
+    _search = Utils.joinMainSearchkey(_search)
+
+    _search = _search.replace(/@\$@/ig, '')
+    _search = _search ? 'where ' + _search : ''
 
     this.setState({
+      scripts,
       columns: fromJS(config.columns).toJS(),
       setting: _setting,
-      scripts: fromJS(config.scripts).toJS(),
       searches: search,
+      defaultSearch: _search,
       varMarks: Marks
     })
 
@@ -372,8 +394,15 @@
           return
         }
 
+        let _search = this.formatSearch(search)
+        _search = Utils.joinMainSearchkey(_search)
+
+        _search = _search.replace(/@\$@/ig, '')
+        _search = _search ? 'where ' + _search : ''
+
         this.setState({
           searches: search,
+          defaultSearch: _search,
           setting: res
         }, () => {
           this.sqlverify(() => { // 楠岃瘉鎴愬姛
@@ -427,15 +456,9 @@
   }
 
   getdefaultSql = () => {
-    const { columns, searches, setting } = this.state
+    const { columns, setting, defaultSearch } = this.state
     let defaultsql = ''
     let arr_field = columns.map(col => col.field).join(',')
-
-    let _search = this.formatSearch(searches)
-    _search = Utils.joinMainSearchkey(_search)
-
-    _search = _search.replace(/@\$@/ig, '')
-    _search = _search ? 'where ' + _search : ''
 
     if (setting.dataresource) {
       let _dataresource = setting.dataresource
@@ -444,7 +467,7 @@
         _dataresource = '(' + _dataresource + ') tb'
       }
 
-      defaultsql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${_search}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
+      defaultsql = `select top @pageSize@ ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by @orderBy@) as rows from ${_dataresource} ${defaultSearch}) tmptable where rows > (@pageSize@ * (@pageIndex@ - 1)) order by tmptable.rows`
     }
 
     this.setState({defaultsql})
@@ -455,7 +478,7 @@
    * @param {Array} searches 鎼滅储鏉′欢鏁扮粍
    */
   formatSearch (searches) {
-    if (!searches || searches.length === 0) return []
+    if (!searches) return []
 
     let newsearches = []
     searches.forEach(search => {
@@ -470,37 +493,32 @@
         required: search.required === 'true'
       }
       if (item.type === 'group') {
-        let copy = fromJS(item).toJS()
-        copy.key = search.datefield
+        item.key = search.datefield
+        item.type = 'daterange'
+        item.match = 'between'
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
 
-        item.value = search.initval && search.initval[0] ? search.initval[0] : '@$@'
-        item.match = '='
-        
-        copy.type = 'daterange'
-        copy.match = 'between'
-        copy.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
-
-        if (search.transfer === 'true') {
-          newsearches.push(item)
-        }
-        newsearches.push(copy)
+        newsearches.push(item)
         return
       } else if (item.type === 'date') {
         item.value = moment().format('YYYY-MM-DD')
       } else if (item.type === 'datemonth') {
         item.value = moment().format('YYYY-MM')
       } else if (item.type === 'dateweek') {
-        item.value = [moment().startOf('week').format('YYYY-MM-DD'), moment().endOf('week').format('YYYY-MM-DD')]
+        item.value = moment().format('YYYY-MM-DD')
       } else if (item.type === 'daterange') {
-        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
-      } else if (item.type === 'multiselect') {
-        item.value = ['@$@']
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
+      } else if (item.type === 'range') {
+
+      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
+        item.type = 'multi'
+        item.value = '@$@'
       } else {
         item.value = '@$@'
       }
       newsearches.push(item)
     })
-    
+
     return newsearches
   }
 
@@ -527,8 +545,15 @@
             return
           }
 
+          let _search = this.formatSearch(search)
+          _search = Utils.joinMainSearchkey(_search)
+
+          _search = _search.replace(/@\$@/ig, '')
+          _search = _search ? 'where ' + _search : ''
+
           this.setState({
             searches: search,
+            defaultSearch: _search,
             setting: res
           }, () => {
             this.sqlverify(() => { resolve({setting: res, columns, scripts }) }, reject, false)
@@ -562,7 +587,7 @@
   }
 
   sqlverify = (resolve, reject, change = false, testScripts) => {
-    const { columns, setting, scripts, searches } = this.state
+    const { columns, setting, scripts, searches, defaultSearch } = this.state
 
     let _scripts = scripts.filter(item => item.status !== 'false')
 
@@ -580,7 +605,7 @@
     }
 
     if ((setting.interType === 'system' && setting.execute !== 'false') || _scripts.length > 0) {
-      let result = SettingUtils.getDebugSql(setting, _scripts, columns, searches)
+      let result = SettingUtils.getDebugSql(setting, _scripts, columns, searches, defaultSearch)
 
       if (result.error) {
         notification.warning({
@@ -622,6 +647,27 @@
     })
   }
 
+  copyColumns = () => {
+    const { columns } = this.state
+    let m = []
+    let n = []
+
+    columns.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鏇存柊
    */
@@ -657,6 +703,7 @@
               type="fields"
               updatefield={this.updatefields}
             />
+            <Icon type="copy" onClick={this.copyColumns} style={{position: 'absolute', cursor: 'pointer', zIndex: 1, top: '-35px', right: '0px', color: '#1890ff'}} />
             <EditTable actions={['edit', 'move', 'copy', 'del']} type="datasourcefield" data={columns} columns={colColumns} onChange={(columns) => this.setState({columns})}/>
           </TabPane>
           <TabPane tab={
diff --git a/src/menu/datasource/verifycard/settingform/index.jsx b/src/menu/datasource/verifycard/settingform/index.jsx
index c114793..d7916a3 100644
--- a/src/menu/datasource/verifycard/settingform/index.jsx
+++ b/src/menu/datasource/verifycard/settingform/index.jsx
@@ -8,6 +8,8 @@
 import CodeMirror from '@/templates/zshare/codemirror'
 import './index.scss'
 
+const { TextArea } = Input
+
 class SettingForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,       // 瀛楀吀椤�
@@ -182,6 +184,10 @@
                       required: true,
                       message: this.props.dict['form.required.input'] + '琛ㄥ悕!'
                     },
+                    {
+                      max: 50,
+                      message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
+                    }
                   ]
                 })(<Input placeholder={''} autoComplete="off" />)}
               </Form.Item>
@@ -245,7 +251,7 @@
                 })(<Input placeholder={''} autoComplete="off" />)}
               </Form.Item>
             </Col> : null}
-            {interType === 'outer' ? <Col span={8}>
+            {interType === 'outer' ? <Col className="outer-interface" span={24}>
               <Form.Item label="鎺ュ彛鍦板潃">
                 {getFieldDecorator('interface', {
                   initialValue: setting.interface || '',
@@ -255,7 +261,18 @@
                       message: this.props.dict['form.required.input'] + '鎺ュ彛鍦板潃!'
                     }
                   ]
-                })(<Input placeholder={''} autoComplete="off" />)}
+                })(<TextArea rows={2}/>)}
+              </Form.Item>
+            </Col> : null}
+            {interType === 'outer' ? <Col className="outer-interface" span={24}>
+              <Form.Item label={<Tooltip placement="topLeft" title="姝e紡绯荤粺鎺ュ彛鍦板潃锛屼负绌烘椂浣跨敤鎺ュ彛鍦板潃">
+                  <Icon type="question-circle" />
+                  姝e紡鍦板潃
+                </Tooltip>
+              }>
+                {getFieldDecorator('proInterface', {
+                  initialValue: setting.proInterface || ''
+                })(<TextArea rows={2}/>)}
               </Form.Item>
             </Col> : null}
             {interType === 'outer' ? <Col span={8}>
@@ -270,7 +287,7 @@
             </Col> : null}
             {interType === 'system' ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
               <Form.Item labelCol={{xs: { span: 24 }, sm: { span: 2 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 22 }} } label={
-                <Tooltip placement="topLeft" title={'浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\''}>
+                <Tooltip placement="topLeft" title={`浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� ''銆� @$ -> */ 鎴� ''锛涙煡璇㈡浛鎹㈢ $select@ -> /* 鎴� ''銆� @select$ -> */ 鎴� ''锛涚粺璁℃浛鎹㈢ $sum@ -> /* 鎴� ''銆� @sum$ -> */ 鎴� ''銆俙}>
                   <Icon type="question-circle" />
                   鏁版嵁婧�
                 </Tooltip>
@@ -336,7 +353,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'璇ョ粍浠跺鏋滃彈鍏朵粬缁勪欢鎺у埗锛岃閫夐」鐩稿簲鐨勭粍浠讹紝娌℃湁鏃堕�夆�滄棤鈥濄��'}>
                   <Icon type="question-circle" />
@@ -355,7 +372,7 @@
                   <Cascader options={modules} onChange={this.changeSupModule} expandTrigger="hover" placeholder="" />
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
             {config.pageable ? <Col span={8}>
               <Form.Item label="鍒嗛〉">
                 {getFieldDecorator('laypage', {
@@ -387,7 +404,7 @@
               </Form.Item>
             </Col> : null}
             {/* 1銆佷笉鍒嗛〉涓斾笉瀛樺湪涓婄骇妯″潡 */}
-            {(!config.pageable || (config.pageable && laypage === 'false')) && (!supModule || supModule.length === 0 || supModule[0] === 'empty') ? <Col span={8}>
+            {config.type !== 'navbar' && (!config.pageable || (config.pageable && laypage === 'false')) && (!supModule || supModule.length === 0 || supModule[0] === 'empty') ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'鍒濆鍖栧姞杞芥椂锛屾槸鍚︿笌鍏朵粬缁勪欢涓�鍚屽姞杞芥暟鎹紝娉細浠呭湪浣跨敤绯荤粺鍑芥暟锛屼笖鍒濆鍖栧姞杞芥暟鎹椂鏈夋晥锛屽垎椤佃姹傛椂鏃犳晥銆�'}>
                   <Icon type="question-circle" />
@@ -404,7 +421,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'浼樺厛浣跨敤鍚岀骇鐨勬悳绱㈡潯浠剁粍浠讹紝鍚岀骇鎼滅储涓嶅瓨鍦ㄦ椂锛屼緷娆″悜涓婇�夊彇锛屼笌褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵竴鍚岀敤浣滄暟鎹繃婊わ紙褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵紭鍏堬級銆�'}>
                   <Icon type="question-circle" />
@@ -420,8 +437,8 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
-            {useMSearch === 'true' ? <Col span={8}>
+            </Col> : null}
+            {config.type !== 'navbar' && config.type !== 'balcony' && useMSearch === 'true' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'澶栧眰鎼滅储鏉′欢鏀瑰彉鏃讹紝鏄惁鍒锋柊褰撳墠缁勪欢鏁版嵁銆�'}>
                   <Icon type="question-circle" />
@@ -438,7 +455,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label="鍒濆鍖栨暟鎹�">
                 {getFieldDecorator('onload', {
                   initialValue: setting.onload || 'true'
@@ -449,7 +466,7 @@
                   </Radio.Group>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
           </Row>
         </Form>
       </div>
diff --git a/src/menu/datasource/verifycard/settingform/index.scss b/src/menu/datasource/verifycard/settingform/index.scss
index 5bd14b5..d0943f6 100644
--- a/src/menu/datasource/verifycard/settingform/index.scss
+++ b/src/menu/datasource/verifycard/settingform/index.scss
@@ -24,4 +24,12 @@
   .ant-radio-group {
     white-space: nowrap;
   }
+  .outer-interface {
+    .ant-form-item-label {
+      width: 10.5%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 89.5%;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/menu/datasource/verifycard/utils.jsx b/src/menu/datasource/verifycard/utils.jsx
index 9bb5840..fa55bc3 100644
--- a/src/menu/datasource/verifycard/utils.jsx
+++ b/src/menu/datasource/verifycard/utils.jsx
@@ -7,7 +7,7 @@
    * @return {Object}  setting       椤甸潰璁剧疆
    * @return {Array}   columns       鏄剧ず瀛楁
    */
-  static getDebugSql (setting, scripts, columns, searches = []) {
+  static getDebugSql (setting, scripts, columns, searches = [], defSearch) {
     let sql = ''
     let error = ''
     let _dataresource = ''
@@ -26,8 +26,20 @@
       _dataresource = setting.dataresource || ''
     }
     
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
+
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
+    _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
+    _customScript = _customScript.replace(/@select\$|\$select@/ig, '')
+    _dataresource = _dataresource.replace(/@sum\$|\$sum@/ig, '')
+    _customScript = _customScript.replace(/@sum\$|\$sum@/ig, '')
 
     if (_customScript) {
       _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50) select @ErrorCode='',@retmsg =''
@@ -48,8 +60,7 @@
         _customScript = _customScript.replace(reg, '0')
       })
     }
-    
-    
+
     // 姝e垯鏇挎崲
     let _regoptions = []
     let _fields = []
@@ -66,7 +77,7 @@
           reg: new RegExp('@' + item.datefield + '1@', 'ig')
         })
       }
-      if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
+      if (['dateweek', 'datemonth', 'daterange', 'range'].includes(item.type)) {
         _regoptions.push({
           var: new RegExp('@' + item.field, 'ig'),
           reg: new RegExp('@' + item.field + '@', 'ig')
@@ -103,7 +114,7 @@
       }
     })
 
-    let _search = ''
+    let _search = defSearch
 
     if (setting.queryType === 'statistics' && _dataresource) {
       _regoptions.forEach(item => {
@@ -125,7 +136,7 @@
       }, {
         reg: new RegExp('@FullName@', 'ig'),
       })
-      if (setting.laypage !== 'false') {
+      if (setting.laypage === 'true') {
         _regoptions.push({
           reg: new RegExp('@pageSize@', 'ig'),
         }, {
@@ -140,6 +151,9 @@
       if (setting.varMark) {
         originscript = originscript.replace(/@ErrorCode/ig, '')
         originscript = originscript.replace(/@retmsg/ig, '')
+        originscript = originscript.replace(/@UserName@/ig, '').replace(/@UserName/ig, '')
+        originscript = originscript.replace(/@FullName@/ig, '').replace(/@FullName/ig, '')
+        originscript = originscript.replace(/@login_city@/ig, '').replace(/@login_city/ig, '')
         originscript = originscript.replace(/@id@/ig, '').replace(/@id/ig, '')
         originscript = originscript.replace(/@bid@/ig, '').replace(/@bid/ig, '')
         originscript = originscript.replace(/@loginuid@/ig, '').replace(/@loginuid/ig, '')
@@ -162,7 +176,11 @@
         _dataresource = '(' + _dataresource + ') tb'
       }
 
-      _dataresource = `select${setting.laypage !== 'false' ?  ' top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage !== 'false' ?  'where rows > 0' : ''} order by tmptable.rows`
+      if (setting.order) {
+        _dataresource = `select${setting.laypage === 'true' ?  ' top 10' : ''} ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable ${setting.laypage === 'true' ?  'where rows > 0' : ''} order by tmptable.rows`
+      } else {
+        _dataresource = `select${setting.laypage === 'true' ?  ' top 10' : ''} ${arr_field} from ${_dataresource} ${_search}`
+      }
     }
 
     if (_customScript) {
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index b89e539..b12b583 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -7,9 +7,13 @@
 const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
 const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
+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 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'))
 const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
@@ -59,6 +63,12 @@
       return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'dashboard') {
+      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'tree') {
+      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'scatter') {
+      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'form') {
       return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'tabs') {
@@ -81,6 +91,8 @@
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
   return (
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index 6ac5ace..7e03f6c 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -19,6 +19,10 @@
     handleList({...menu, components: _cards})
     setCards(_cards)
   }
+
+  if (menu.components.length > cards.length) {
+    setCards(menu.components)
+  }
   
   const findCard = id => {
     const card = cards.filter(c => `${c.uuid}` === id)[0]
@@ -53,9 +57,12 @@
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
         const _cards = cards.filter(item => item.uuid !== card.uuid)
-        MKEmitter.emit('delButtons', uuids)
         handleList({...menu, components: _cards})
         setCards(_cards)
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -93,6 +100,10 @@
         code: '鑷畾涔�',
         carousel: '杞挱',
         form: '琛ㄥ崟',
+        dashboard: '浠〃鐩�',
+        scatter: '鏁g偣鍥�',
+        tree: '鏍戝舰鍒楄〃',
+        balcony: '娴姩鍗�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/modalconfig/controller.jsx b/src/menu/modalconfig/controller.jsx
index 6cae222..881883d 100644
--- a/src/menu/modalconfig/controller.jsx
+++ b/src/menu/modalconfig/controller.jsx
@@ -48,12 +48,6 @@
   handleSave = (modal) => {
     const { config, btn } = this.state
     MKEmitter.emit('submitModal', config, btn, modal)
-
-    this.setState({
-      visible: false,
-      config: null,
-      btn: null
-    })
   }
 
   render () {
diff --git a/src/menu/modalconfig/index.jsx b/src/menu/modalconfig/index.jsx
index 6f3cd48..cf6bab2 100644
--- a/src/menu/modalconfig/index.jsx
+++ b/src/menu/modalconfig/index.jsx
@@ -12,7 +12,6 @@
 import enUS from '@/locales/en-US/model.js'
 import { getModalForm } from '@/templates/zshare/formconfig'
 
-import ModalForm from '@/templates/zshare/modalform'
 import SourceElement from '@/templates/modalconfig/dragelement/source'
 import SettingForm from '@/templates/modalconfig/settingform'
 import asyncComponent from '@/utils/asyncComponent'
@@ -22,6 +21,7 @@
 const { Panel } = Collapse
 const { confirm } = Modal
 const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
 const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
 const DragElement = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
 const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -37,20 +37,11 @@
     dict: CommonDict,      // 瀛楀吀
     config: null,          // 椤甸潰閰嶇疆锛屽寘鎷ā鏉跨被鍨嬨�佹ā鎬佹璁剧疆銆佹坊鍔犺〃鍚嶃�佽〃鍗曞垪琛�
     visible: false,        // 琛ㄥ崟缂栬緫妯℃�佹锛屾樉绀烘帶鍒�
-    tableVisible: false,   // 鏁版嵁琛ㄥ瓧娈靛垪琛ㄦā鎬佹锛屾樉绀烘帶鍒�
-    tableColumns: [],      // 琛ㄦ牸瀛楁鍚嶅垪琛�
-    fields: null,          // 琛ㄥ崟锛屽彲閫夊瓧娈碉紙鍘婚噸鍚庯級
     formlist: null,        // 琛ㄥ崟缂栬緫妯℃�佹锛屽彲缂栬緫瀛楁
     card: null,            // 缂栬緫鍏冪礌
-    closeloading: false,   // 鑿滃崟淇濆瓨涓�
     settingVisible: false, // 鍏ㄥ眬閰嶇疆妯℃�佹
-    closeVisible: false,   // 鍏抽棴妯℃�佹
-    tables: [],            // 鍙敤琛ㄥ悕
-    selectedTables: [],    // 宸查�夎〃鍚�
     originConfig: null,    // 鍘熷鑿滃崟
-    sources: null,         // 琛ㄥ崟绫诲瀷
     sqlVerifing: false,    // sql楠岃瘉
-    openEdition: '',       // 缂栬緫鐗堟湰鏍囪锛岄槻姝㈠浜烘搷浣�
     showField: false,      // 鏄剧ず琛ㄥ崟瀛楁鍊�
     standardform: null
   }
@@ -132,7 +123,7 @@
       if (card.uuid === item.uuid) {
         index = i
       }
-      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
+      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
       if (item.field && !uniq.has(item.field)) {
         uniq.set(item.field, true)
 
@@ -227,7 +218,7 @@
 
       _config.fields = _config.fields.filter(item => !item.origin)
 
-      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
@@ -297,15 +288,26 @@
   submitConfig = () => {
     const { config } = this.state
 
+    this.setState({originConfig: fromJS(config).toJS()})
     this.props.handleSave(config)
+    notification.success({
+      top: 92,
+      message: '淇濆瓨鎴愬姛銆�',
+      duration: 2
+    })
   }
 
   cancelConfig = () => {
     const { config, originConfig } = this.state
 
     if (!is(fromJS(config), fromJS(originConfig))) {
-      this.setState({
-        closeVisible: true
+      let _this = this
+      confirm({
+        content: '閰嶇疆淇℃伅鏈繚瀛橈紝纭畾杩斿洖鍚楋紵',
+        onOk() {
+          _this.props.handleBack()
+        },
+        onCancel() {}
       })
     } else {
       this.props.handleBack()
@@ -423,8 +425,8 @@
             <Card title={dict['header.menu.form.configurable']} bordered={false} extra={
               <div>
                 <EditComponent dict={dict} options={['form']} config={this.state.config} refresh={(res) => this.updateConfig(res.config)}/>
-                <Button type="primary" onClick={this.submitConfig}>{dict['model.confirm']}</Button>
-                <Button onClick={this.cancelConfig}>{dict['model.cancel']}</Button>
+                <Button type="primary" onClick={this.submitConfig}>淇濆瓨</Button>
+                <Button onClick={this.cancelConfig}>杩斿洖</Button>
               </div>
             } style={{ width: '100%' }}>
               <Icon type="setting" onClick={this.changeSetting} />
@@ -486,7 +488,7 @@
         <Modal
           title={this.state.dict['model.edit']}
           visible={this.state.settingVisible}
-          width={700}
+          width={850}
           maskClosable={false}
           onOk={this.settingSave}
           onCancel={() => { this.setState({ settingVisible: false }) }}
@@ -499,21 +501,6 @@
             inputSubmit={this.settingSave}
             wrappedComponentRef={(inst) => this.settingRef = inst}
           />
-        </Modal>
-        <Modal
-          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
-          closable={false}
-          maskClosable={false}
-          visible={this.state.closeVisible}
-          onCancel={() => { this.setState({closeVisible: false}) }}
-          footer={[
-            <Button key="save" className="mk-btn mk-green" loading={this.state.closeloading} onClick={this.submitConfig}>{this.state.dict['model.save']}</Button>,
-            <Button key="confirm" className="mk-btn mk-yellow" onClick={this.props.handleBack}>{this.state.dict['model.notsave']}</Button>,
-            <Button key="cancel" onClick={() => { this.setState({closeVisible: false}) }}>{this.state.dict['model.cancel']}</Button>
-          ]}
-          destroyOnClose
-        >
-          {this.state.dict['header.menu.config.placeholder']}
         </Modal>
       </div>
     )
diff --git a/src/menu/modalconfig/index.scss b/src/menu/modalconfig/index.scss
index 163f1e6..19fe376 100644
--- a/src/menu/modalconfig/index.scss
+++ b/src/menu/modalconfig/index.scss
@@ -127,6 +127,20 @@
     .ant-card-body {
       position: relative;
       padding: 0;
+
+      .modal-fields-row.up_down {
+        .ant-form-item {
+          display: block!important;
+          .ant-form-item-label {
+            width: 100%!important;
+            text-align: left;
+          }
+          .ant-form-item-control-wrapper {
+            width: 100%!important;
+          }
+        }
+      }
+
       .ant-modal-content {
         max-width: 95%;
         margin: 0 auto;
@@ -292,6 +306,7 @@
   }
 }
 
+
 .modal-fields {
   .ant-modal {
     top: 50px;
diff --git a/src/menu/modulesource/index.jsx b/src/menu/modulesource/index.jsx
index 03f268a..2233f75 100644
--- a/src/menu/modulesource/index.jsx
+++ b/src/menu/modulesource/index.jsx
@@ -55,6 +55,7 @@
             c_id: item.uuid,
             images: '',
             c_name: item.title,
+            typename: sessionStorage.getItem('appType') || '',
             long_param: '',
             del_type: 'Y'
           }).then(result => {
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index e88ceca..e9e1833 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -12,11 +12,16 @@
 import Editor from '@/assets/mobimg/editor.png'
 import SandBox from '@/assets/mobimg/sandbox.png'
 import Pie1 from '@/assets/mobimg/ring.png'
+import Pie3 from '@/assets/mobimg/nest.png'
 import Pie2 from '@/assets/mobimg/nightingale.png'
 import Mainsearch from '@/assets/mobimg/mainsearch.png'
 import Carousel from '@/assets/mobimg/carousel.png'
 import Carousel1 from '@/assets/mobimg/carousel1.png'
 import form from '@/assets/mobimg/form.png'
+import dashboard from '@/assets/mobimg/dashboard.png'
+import ratioboard from '@/assets/mobimg/ratioboard.png'
+import scatter from '@/assets/mobimg/scatter.png'
+import tree from '@/assets/mobimg/tree.png'
 
 // 缁勪欢閰嶇疆淇℃伅
 export const menuOptions = [
@@ -24,19 +29,25 @@
   { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24, forbid: ['billPrint'] },
   { 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: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟', width: 24 },
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
   { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 },
+  { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '鏍戝舰鍒楄〃', width: 12 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
   { 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 },
   { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '鐜浘', width: 12 },
+  { type: 'menu', url: Pie3, component: 'pie', subtype: 'nest', title: '宓屽楗煎浘', width: 12 },
+  { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
+  { type: 'menu', url: dashboard, component: 'dashboard', subtype: 'dashboard', title: '浠〃鐩�', width: 12 },
+  { type: 'menu', url: ratioboard, component: 'dashboard', subtype: 'ratioboard', title: '鍗犳瘮鍥�', width: 12 },
+  { type: 'menu', url: scatter, component: 'scatter', subtype: 'scatter', title: '鏁g偣鍥�', width: 24 },
   { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
   { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
-  { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24, forbid: ['billPrint'] },
 ]
diff --git a/src/menu/pastecontroller/index.jsx b/src/menu/pastecontroller/index.jsx
index 9df7a55..7b3153c 100644
--- a/src/menu/pastecontroller/index.jsx
+++ b/src/menu/pastecontroller/index.jsx
@@ -60,8 +60,13 @@
         cell = this.resetconfig(cell, item, true, copyBtns)
         return cell
       })
+    } else if (item.type === 'menubar') {
+      item.subMenus = item.subMenus.map(cell => {
+        cell.uuid = Utils.getuuid()
+        return cell
+      })
     } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
-      item.subcards.forEach(card => {
+      item.subcards && item.subcards.forEach(card => {
         card.uuid = Utils.getuuid()
         if (card.elements) {
           if (sessionStorage.getItem('editMenuType') === 'popview') {
@@ -149,12 +154,16 @@
       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 = Utils.getuuid()
+
+        oriUids[cell.uuid] = _uuid
+
         if (cell.OpenType === 'popview') {
           let _cell = fromJS(cell).toJS()
           _cell.$originUuid = _cell.uuid
@@ -177,6 +186,13 @@
         return cell
       })
     }
+    if (item.setting && item.setting.supModule) {
+      item.setting.supModule = ''
+    }
+    
+    if (item.wrap && item.wrap.doubleClick) {
+      item.wrap.doubleClick = oriUids[item.wrap.doubleClick] || ''
+    }
 
     return item
   }
@@ -185,16 +201,20 @@
     const { Tab } = this.props
 
     let isgroup = Tab && Tab.type === 'group' ? true : false
+    let options = ['tabs', 'datacard', 'propcard', 'mainsearch', 'group', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'dashboard', 'scatter']
 
+    if (sessionStorage.getItem('appType') === 'mob') {
+      options.push('menubar')
+    }
     this.pasteFormRef.handleConfirm().then(res => {
-      if (!isgroup && !['tabs', 'datacard', 'propcard', 'mainsearch', 'group', 'normaltable', 'tablecard', 'line', 'bar', 'pie'].includes(res.copyType)) {
+      if (!isgroup && !options.includes(res.copyType)) {
         notification.warning({
           top: 92,
           message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�',
           duration: 5
         })
         return
-      } else if (isgroup && !['datacard', 'propcard', 'normaltable', 'tablecard', 'line', 'bar', 'pie'].includes(res.copyType)) {
+      } else if (isgroup && !['datacard', 'propcard', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'dashboard', 'scatter'].includes(res.copyType)) {
         notification.warning({
           top: 92,
           message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�',
diff --git a/src/menu/picturecontroller/editform/index.jsx b/src/menu/picturecontroller/editform/index.jsx
index e12d46d..934ebd7 100644
--- a/src/menu/picturecontroller/editform/index.jsx
+++ b/src/menu/picturecontroller/editform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, notification } from 'antd'
+import { Form, Row, Col, Input, Radio } from 'antd'
 
 import FileUpload from '@/tabviews/zshare/fileupload'
 import './index.scss'
@@ -14,7 +14,6 @@
   }
 
   state = {
-    urls: [],
     linkurl: '',
     plusType: 'upload'
   }
@@ -24,29 +23,8 @@
     return new Promise((resolve, reject) => {
       this.props.form.validateFieldsAndScroll((err, values) => {
         if (!err) {
-          if (values.urls && values.urls[0].status === 'error') {
-            notification.warning({
-              top: 92,
-              message: '璇烽噸鏂颁笂浼犳枃浠讹紒',
-              duration: 5
-            })
-            return
-          } else if (values.urls && values.urls[0] && values.urls[0].status !== 'done') {
-            notification.warning({
-              top: 92,
-              message: '鏂囦欢涓婁紶涓紝璇风◢鍚庯紒',
-              duration: 5
-            })
-            return
-          } else if (values.urls && values.urls[0] && values.urls[0].response) {
-            values.linkurl = values.urls[0].response
-          } else {
-            notification.warning({
-              top: 92,
-              message: '鏈幏鍙栧埌鏂囦欢璺緞锛�',
-              duration: 5
-            })
-            return
+          if (values.urls) {
+            values.linkurl = values.urls
           }
           resolve(values)
         } else {
@@ -57,28 +35,19 @@
   }
 
   changeType = (val) => {
-    const { linkurl, urls } = this.state
-    let _urls = this.props.form.getFieldValue('urls') || ''
-    let _url = this.props.form.getFieldValue('linkurl') || ''
+    let _url = ''
 
     if (val === 'input') {
-      if (_urls && _urls[0] && _urls[0].status === 'done' && (_urls[0].url || _urls[0].response)) {
-        _url = _urls[0].url || _urls[0].response
-      } else {
-        _url = linkurl || ''
-      }
-    } else {
-      _urls = urls.filter(item => item.status === 'done')
-      _url = linkurl
+      _url = this.props.form.getFieldValue('urls') || ''
     }
     
-    this.setState({plusType: val, urls: _urls, linkurl: _url})
+    this.setState({plusType: val, linkurl: _url})
   }
 
   render() {
     const { getFieldDecorator } = this.props.form
     const { card } = this.props
-    const { urls, linkurl, plusType } = this.state
+    const { linkurl, plusType } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -103,7 +72,7 @@
           {!card.id && card.typecharone === 'image' && plusType === 'upload' ? <Col span={24}>
             <Form.Item label="鍥剧墖涓婁紶">
               {getFieldDecorator('urls', {
-                initialValue: urls,
+                initialValue: '',
                 rules: [
                   {
                     required: true,
@@ -111,14 +80,19 @@
                   }
                 ]
               })(
-                <FileUpload accept=".jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp" maxFile={1} fileType={'picture'} />
+                <FileUpload config={{
+                  initval: '',
+                  suffix: '.jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp',
+                  maxfile: 1,
+                  fileType: 'picture'
+                }} />
               )}
             </Form.Item>
           </Col> : null}
           {!card.id && card.typecharone === 'video' && plusType === 'upload' ? <Col span={24}>
             <Form.Item label="瑙嗛涓婁紶">
               {getFieldDecorator('urls', {
-                initialValue: urls,
+                initialValue: '',
                 rules: [
                   {
                     required: true,
@@ -126,7 +100,12 @@
                   }
                 ]
               })(
-                <FileUpload accept=".mp4,.webm,.ogg" maxFile={1} fileType={'text'} />
+                <FileUpload config={{
+                  initval: '',
+                  suffix: '.mp4,.webm,.ogg',
+                  maxfile: 1,
+                  fileType: 'text'
+                }}/>
               )}
             </Form.Item>
           </Col> : null}
diff --git a/src/menu/popview/index.jsx b/src/menu/popview/index.jsx
index 59da6e1..55a0f13 100644
--- a/src/menu/popview/index.jsx
+++ b/src/menu/popview/index.jsx
@@ -19,8 +19,10 @@
 const { confirm } = Modal
 
 const MenuForm = asyncComponent(() => import('./menuform'))
+const Header = asyncComponent(() => import('@/menu/header'))
 const SourceWrap = asyncComponent(() => import('@/menu/modulesource'))
 const MenuShell = asyncComponent(() => import('@/menu/menushell'))
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const BgController = asyncComponent(() => import('@/menu/bgcontroller'))
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const PaddingController = asyncComponent(() => import('@/menu/padcontroller'))
@@ -84,6 +86,7 @@
   updateCustomComponent = () => {
     Api.getSystemConfig({
       func: 's_get_custom_components',
+      typename: sessionStorage.getItem('appType'),
       typecharone: ''
     }).then(res => {
       let coms = []
@@ -245,7 +248,7 @@
             buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
             _sort++
           })
-          item.subcards.forEach(card => {
+          item.subcards && item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
@@ -527,6 +530,18 @@
     window.GLOB.customMenu = config
   }
 
+  resetConfig = (config) => {
+    this.setState({
+      config: {...config, components: []},
+    }, () => {
+      this.setState({
+        config: config
+      })
+    })
+
+    window.GLOB.customMenu = config
+  }
+
   /**
    * @description 鏇存柊甯哥敤琛ㄤ俊鎭紝蹇嵎娣诲姞鍚庢洿鏂伴厤缃俊鎭�
    */
@@ -550,49 +565,53 @@
     const { activeKey, MenuType, dict, config, menuloading, customComponents } = this.state
 
     return (
-      <DndProvider backend={HTML5Backend}>
-        <div className="menu-body">
-          <div className="menu-setting">
-            <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
-              {/* 鍩烘湰淇℃伅 */}
-              <Panel header={dict['mob.basemsg']} key="basedata">
-                {/* 鑿滃崟淇℃伅 */}
-                {config ? <MenuForm dict={dict} config={config} btn={btn} updateConfig={this.updateConfig}/> : null}
-                {/* 琛ㄥ悕娣诲姞 */}
-                {config ? <TableComponent config={config} updatetable={this.updatetable}/> : null}
-              </Panel>
-              {/* 缁勪欢娣诲姞 */}
-              <Panel header={dict['mob.component']} key="component">
-                <SourceWrap MenuType={MenuType} />
-              </Panel>
-              {customComponents && customComponents.length ? <Panel header="鑷畾涔夌粍浠�" key="cuscomponent">
-                <SourceWrap components={customComponents} MenuType={MenuType} />
-              </Panel> : null}
-              <Panel header={'椤甸潰鑳屾櫙'} key="background">
-                {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
-              </Panel>
-              <Panel header={'椤甸潰鍐呰竟璺�'} key="padding">
-                {config ? <PaddingController config={config} updateConfig={this.updateConfig} /> : null}
-              </Panel>
-            </Collapse>
+      <div className="pc-poper-view">
+        <Header />
+        <DndProvider backend={HTML5Backend}>
+          <div className="menu-body">
+            <div className="menu-setting">
+              <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
+                {/* 鍩烘湰淇℃伅 */}
+                <Panel header={dict['mob.basemsg']} key="basedata">
+                  {/* 鑿滃崟淇℃伅 */}
+                  {config ? <MenuForm dict={dict} config={config} btn={btn} updateConfig={this.updateConfig}/> : null}
+                  {/* 琛ㄥ悕娣诲姞 */}
+                  {config ? <TableComponent config={config} updatetable={this.updatetable}/> : null}
+                </Panel>
+                {/* 缁勪欢娣诲姞 */}
+                <Panel header={dict['mob.component']} key="component">
+                  <SourceWrap MenuType={MenuType} />
+                </Panel>
+                {customComponents && customComponents.length ? <Panel header="鑷畾涔夌粍浠�" key="cuscomponent">
+                  <SourceWrap components={customComponents} MenuType={MenuType} />
+                </Panel> : null}
+                <Panel header={'椤甸潰鑳屾櫙'} key="background">
+                  {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
+                </Panel>
+                <Panel header={'椤甸潰鍐呰竟璺�'} key="padding">
+                  {config ? <PaddingController config={config} updateConfig={this.updateConfig} /> : null}
+                </Panel>
+              </Collapse>
+            </div>
+            <div className={'menu-view ' + (menuloading ? 'saving' : '')}>
+              <Card title={
+                <div> {config && config.MenuName} </div>
+              } bordered={false} extra={
+                <div>
+                  <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
+                  <StyleCombControlButton menu={config} />
+                  <PasteController type="menu" Tab={null} insert={this.insert} />
+                  {config ? <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config.enabled} onChange={this.onEnabledChange} /> : null}
+                  <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
+                  <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
+                </div>
+              } style={{ width: '100%' }}>
+                {config && config.components ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
+              </Card>
+            </div>
           </div>
-          <div className={'menu-view ' + (menuloading ? 'saving' : '')}>
-            <Card title={
-              <div> {config && config.MenuName} </div>
-            } bordered={false} extra={
-              <div>
-                <StyleCombControlButton menu={config} />
-                <PasteController type="menu" Tab={null} insert={this.insert} />
-                {config ? <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config.enabled} onChange={this.onEnabledChange} /> : null}
-                <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
-                <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
-              </div>
-            } style={{ width: '100%' }}>
-              {config && config.components ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
-            </Card>
-          </div>
-        </div>
-      </DndProvider>
+        </DndProvider>
+      </div>
     )
   }
 }
diff --git a/src/menu/popview/index.scss b/src/menu/popview/index.scss
index e69de29..d1a7fda 100644
--- a/src/menu/popview/index.scss
+++ b/src/menu/popview/index.scss
@@ -0,0 +1,162 @@
+.pc-poper-view {
+  background: #000;
+  min-height: 100vh;
+  >.menu-body {
+    width: 100vw;
+    height: 100vh;
+    overflow-x: hidden;
+    position: relative;
+    background: #ffffff;
+    padding: 50px 0px 0px 0px;
+
+    .menu-setting {
+      position: fixed;
+      left: 0;
+      top: 48px;
+      z-index: 10;
+      height: calc(100vh - 48px);
+      width: 300px;
+      background: #ffffff;
+      box-shadow: 0px 2px 5px #bcbcbc;
+      overflow-y: auto;
+      overflow-x: hidden;
+
+      > .ant-collapse {
+        background-color: #ffffff;
+        .ant-collapse-item.ant-collapse-item-active {
+          border-bottom: 1px solid #d9d9d9;
+        }
+        .ant-collapse-header {
+          padding: 11px 16px 10px 40px;
+          border-bottom: 1px solid #d9d9d9;
+          background: #1890ff;
+          color: #ffffff;
+        }
+        .ant-collapse-content-box {
+          .ant-form-item {
+            margin-bottom: 10px;
+          }
+          .model-table-tablemanage-view {
+            >.ant-list {
+              margin-top: 20px;
+              .ant-list-item {
+                display: -webkit-box;
+                padding-right: 20px;
+                position: relative;
+                padding-left: 5px;
+                overflow: hidden;
+                text-overflow: ellipsis;
+                -webkit-line-clamp: 2;
+                -webkit-box-orient: vertical;
+                min-height: 55px;
+                width: 100%;
+                .anticon {
+                  position: absolute;
+                  top: 0px;
+                  right: 0px;
+                  padding: 3px 3px 10px 10px;
+                  cursor: pointer;
+                }
+              }
+            }
+            >.tables {
+              width: 66.66666667%!important;
+            }
+            >.ant-form-item-label {
+              width: 33.33333333%;
+            }
+          }
+        }
+      }
+
+      >.ant-tabs {
+        >.ant-tabs-bar {
+          border-bottom: 1px solid #181F29;
+          margin-bottom: 0px;
+          min-height: 48px;
+          .ant-tabs-tab {
+            padding: 14px 16px;
+            color: rgba(255, 255, 255, 0.85);
+          }
+          .ant-tabs-tab-active.ant-tabs-tab {
+            color: #1890ff;
+          }
+        }
+      }
+    }
+    .menu-setting::-webkit-scrollbar {
+      width: 4px;
+    }
+    .menu-setting::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+      background: rgba(0, 0, 0, 0.08);
+    }
+    .menu-setting::-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-view {
+      position: relative;
+      width: calc(100vw - 300px);
+      margin-left: 300px;
+      height: calc(100vh - 50px);
+      overflow-y: auto;
+
+      > .ant-card {
+        >.ant-card-head {
+          margin-bottom: 0px;
+          position: relative;
+          .ant-card-head-title {
+            color: #1890ff;
+            padding: 5px 0;
+          }
+          .ant-card-extra {
+            padding: 5px 0;
+            button {
+              margin-left: 20px;
+            }
+            .ant-switch.big {
+              min-width: 60px;
+              height: 28px;
+              line-height: 28px;
+              margin-top: -2px;
+              .ant-switch-inner {
+                font-size: 14px;
+              }
+            }
+            .ant-switch.big:after {
+              width: 24px;
+              height: 24px;
+            }
+          }
+        }
+        >.ant-card-body {
+          padding: 0px;
+        }
+      }
+    }
+    .menu-view.saving {
+      .anticon-tool {
+        display: none;
+      }
+    }
+    .menu-view::-webkit-scrollbar {
+      width: 7px;
+    }
+    .menu-view::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+      background: rgba(0, 0, 0, 0.08);
+    }
+    .menu-view::-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);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/replaceField/index.jsx b/src/menu/replaceField/index.jsx
new file mode 100644
index 0000000..d965cba
--- /dev/null
+++ b/src/menu/replaceField/index.jsx
@@ -0,0 +1,381 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, Button, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import options from '@/store/options.js'
+import Utils from '@/utils/utils.js'
+import SettingForm from './settingform'
+import { queryTableSql } from '@/utils/option.js'
+import './index.scss'
+
+class ReplaceField extends Component {
+  static propTpyes = {
+    type: PropTypes.string,
+    config: PropTypes.object,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false,
+    loadingTable: false,
+    confirming: false,
+    tables: [],
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  trigger = () => {
+    const { tables } = this.state
+
+    if (tables.length === 0) {
+      let param = {
+        func: 'sPC_Get_SelectedList',
+        LText: queryTableSql,
+        obj_name: 'data',
+        arr_field: 'TbName,Remark'
+      }
+  
+      param.LText = Utils.formatOptions(param.LText)
+      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) // 浜戠鏁版嵁楠岃瘉
+  
+      if (options.cloudServiceApi) { // 涓斿瓨鍦ㄤ簯绔湴鍧�
+        param.rduri = options.cloudServiceApi
+        param.userid = sessionStorage.getItem('CloudUserID') || ''
+        param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
+      }
+
+      this.setState({
+        loadingTable: true
+      })
+  
+      Api.getSystemCacheConfig(param).then(res => {
+        if (res.status) {
+          this.setState({
+            visible: true,
+            confirming: false,
+            tables: res.data,
+            loadingTable: false
+          })
+        } else {
+          this.setState({
+            confirming: false,
+            loadingTable: false
+          })
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
+        }
+      })
+    } else {
+      this.setState({
+        confirming: false,
+        visible: true
+      })
+    }
+  }
+
+  submit = () => {
+    let config = fromJS(this.props.config).toJS()
+
+    this.settingRef.handleConfirm().then(res => {
+      this.setState({confirming: true})
+
+      let param = {func: 'sPC_Get_FieldName', TBName: res.table}
+      if (options.cloudServiceApi) { // 涓斿瓨鍦ㄤ簯绔湴鍧�
+        param.rduri = options.cloudServiceApi
+        param.userid = sessionStorage.getItem('CloudUserID') || ''
+        param.LoginUID = sessionStorage.getItem('CloudLoginUID') || ''
+      }
+
+      Api.getSystemCacheConfig(param).then(result => {
+        if (!result.status) {
+          this.setState({
+            confirming: false
+          })
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+          return
+        }
+
+        let map = {}
+
+        result.FDName.forEach(item => {
+          if (/NVARCHAR|INT|Decimal/ig.test(item.FieldType)) {
+            item.datatype = item.FieldType
+          }
+          map[item.FieldDec] = item
+        })
+
+        if (this.props.type === 'custom') {
+          let _replace = (components) => {
+            return components.map(item => {
+              if (item.type === 'tabs') {
+                item.subtabs.forEach(tab => {
+                  tab.components = _replace(tab.components)
+                })
+                return item
+              } else if (item.type === 'group') {
+                item.components = _replace(item.components)
+                return item
+              }
+              
+              if (item.columns) {
+                item.columns = item.columns.map(col => {
+                  if (map[col.field]) {
+                    col.field = map[col.field].FieldName
+                    if (map[col.field].datatype) {
+                      col.datatype = map[col.field].datatype
+                    }
+                  }
+                  return col
+                })
+              }
+              if (item.search) {
+                item.search = item.search.map(col => {
+                  if (map[col.field]) {
+                    col.field = map[col.field].FieldName
+                  }
+                  return col
+                })
+              }
+  
+              if (item.action) {
+                item.action.forEach(m => {
+                  if (m.modal && m.modal.fields) {
+                    m.modal.fields = m.modal.fields.map(col => {
+                      if (map[col.field]) {
+                        col.field = map[col.field].FieldName
+                      }
+                      return col
+                    })
+                  }
+                })
+              }
+  
+              if (item.subcards) {
+                item.subcards.forEach(card => {
+                  if (card.elements) { // 鍗$墖
+                    card.elements = card.elements.map(m => {
+                      if (m.datatype === 'dynamic' && map[m.field]) {
+                        m.field = map[m.field].FieldName
+                      }
+                      if (m.modal && m.modal.fields) {
+                        m.modal.fields = m.modal.fields.map(col => {
+                          if (map[col.field]) {
+                            col.field = map[col.field].FieldName
+                          }
+                          return col
+                        })
+                      }
+                      return m
+                    })
+                  }
+  
+                  if (card.backElements) { // 鍗$墖
+                    card.backElements = card.backElements.map(m => {
+                      if (m.datatype === 'dynamic' && map[m.field]) {
+                        m.field = map[m.field].FieldName
+                      }
+                      if (m.modal && m.modal.fields) {
+                        m.modal.fields = m.modal.fields.map(col => {
+                          if (map[col.field]) {
+                            col.field = map[col.field].FieldName
+                          }
+                          return col
+                        })
+                      }
+                      return m
+                    })
+                  }
+
+                  if (card.fields) { // 琛ㄥ崟
+                    card.fields = card.fields.map(m => {
+                      if (map[m.field]) {
+                        m.field = map[m.field].FieldName
+                      }
+                      return m
+                    })
+                  }
+                })
+              }
+  
+              if (item.elements) {
+                item.elements = item.elements.map(m => {
+                  if (m.datatype === 'dynamic' && map[m.field]) {
+                    m.field = map[m.field].FieldName
+                  }
+                  if (m.modal && m.modal.fields) {
+                    m.modal.fields = m.modal.fields.map(col => {
+                      if (map[col.field]) {
+                        col.field = map[col.field].FieldName
+                      }
+                      return col
+                    })
+                  }
+                  return m
+                })
+              }
+  
+              if (item.plot) {
+                if (item.plot.Xaxis && map[item.plot.Xaxis]) {
+                  item.plot.Xaxis = map[item.plot.Xaxis].FieldName
+                }
+                // 缁熻鍥�
+                if (item.plot.InfoValue && map[item.plot.InfoValue]) {
+                  item.plot.InfoValue = map[item.plot.InfoValue].FieldName
+                }
+                if (item.plot.InfoType && map[item.plot.InfoType]) {
+                  item.plot.InfoType = map[item.plot.InfoType].FieldName
+                }
+                // 鍗犳瘮鍥�
+                if (item.plot.valueField && map[item.plot.valueField]) {
+                  item.plot.valueField = map[item.plot.valueField].FieldName
+                }
+                if (item.plot.labelField && map[item.plot.labelField]) {
+                  item.plot.labelField = map[item.plot.labelField].FieldName
+                }
+                // 楗煎浘
+                if (item.plot.type && map[item.plot.type]) {
+                  item.plot.type = map[item.plot.type].FieldName
+                }
+                // 鏁g偣鍥�
+                if (item.plot.gender && map[item.plot.gender]) {
+                  item.plot.gender = map[item.plot.gender].FieldName
+                }
+                if (item.Yaxis) {
+                  if (Array.isArray(item.Yaxis)) {
+                    item.Yaxis = item.Yaxis.map(m => {
+                      if (map[m]) {
+                        return map[m].FieldName
+                      }
+                      return m
+                    })
+                  } else {
+                    if (map[item.Yaxis]) {
+                      item.Yaxis = map[item.Yaxis].FieldName
+                    }
+                  }
+                }
+              }
+  
+              if (item.cols) {
+                let _update = (cols) => {
+                  return cols.map(col => {
+                    if (col.type === 'action' && col.elements) {
+                      col.elements = col.elements.map(m => {
+                        if (m.modal && m.modal.fields) {
+                          m.modal.fields = m.modal.fields.map(col => {
+                            if (map[col.field]) {
+                              col.field = map[col.field].FieldName
+                            }
+                            return col
+                          })
+                        }
+    
+                        return m
+                      })
+                    } else if (col.type === 'custom' && col.elements) {
+                      col.elements = col.elements.map(m => {
+                        if (m.datatype === 'dynamic' && map[m.field]) {
+                          m.field = map[m.field].FieldName
+                        }
+    
+                        return m
+                      })
+                    } else if (col.type === 'colspan') {
+                      col.subcols = _update(col.subcols)
+                    } else if (col.field) {
+                      if (map[col.field]) {
+                        col.field = map[col.field].FieldName
+                      }
+                    }
+                    
+                    return col
+                  })
+                }
+    
+                item.cols = _update(item.cols)
+              }
+  
+              return item
+            })
+          }
+      
+          config.components = _replace(config.components)
+        } else if (this.props.type === 'table') {
+          config.columns = config.columns.map(col => {
+            if (col.field && map[col.field]) {
+              col.field = map[col.field].FieldName
+            }
+            return col
+          })
+          config.search = config.search.map(col => {
+            if (col.field && map[col.field]) {
+              col.field = map[col.field].FieldName
+            }
+            if (col.datefield && map[col.datefield]) {
+              col.datefield = map[col.datefield].FieldName
+            }
+            return col
+          })
+        } else if (this.props.type === 'form') {
+          config.fields = config.fields.map(col => {
+            if (col.field && map[col.field]) {
+              col.field = map[col.field].FieldName
+            }
+            return col
+          })
+        }
+
+        this.setState({
+          confirming: false,
+          visible: false
+        })
+
+        notification.success({
+          top: 92,
+          message: '鏇存柊宸插畬鎴愩��',
+          duration: 3
+        })
+        this.props.updateConfig(config)
+      })
+    })
+  }
+
+  render() {
+    const { visible, loadingTable, tables, confirming } = this.state
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Button className="mk-border-yellow" icon="swap" loading={loadingTable} onClick={this.trigger}>瀛楁鏇挎崲</Button>
+        <Modal
+          title="瀛楁鏇挎崲"
+          wrapClassName="replace-field-modal"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.submit}
+          onCancel={() => { this.setState({ visible: false })}}
+          confirmLoading={confirming}
+          destroyOnClose
+        >
+          <SettingForm tables={tables} wrappedComponentRef={(inst) => this.settingRef = inst}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ReplaceField
\ No newline at end of file
diff --git a/src/menu/replaceField/index.scss b/src/menu/replaceField/index.scss
new file mode 100644
index 0000000..de57aff
--- /dev/null
+++ b/src/menu/replaceField/index.scss
@@ -0,0 +1,9 @@
+.replace-field-modal {
+  .ant-modal {
+    top: 70px;
+  }
+  .ant-modal-body {
+    min-height: 150px;
+    padding-top: 40px;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/replaceField/settingform/index.jsx b/src/menu/replaceField/settingform/index.jsx
new file mode 100644
index 0000000..bbbea31
--- /dev/null
+++ b/src/menu/replaceField/settingform/index.jsx
@@ -0,0 +1,78 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Tooltip, Icon, Select } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    tables: PropTypes.object
+  }
+
+  state = {}
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const { tables } = this.props
+    const { getFieldDecorator } = this.props.form
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout}>
+        <Row gutter={24}>
+          <Col span={20}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鐢ㄤ簬瀛楁鏇挎崲鐨勮〃鍚嶃��">
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}} />
+                琛ㄥ悕
+              </Tooltip>
+            }>
+              {getFieldDecorator('table', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: '璇烽�夋嫨琛ㄥ悕'
+                  }
+                ]
+              })(
+                <Select
+                  showSearch
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {tables.map((option, i) =>
+                    <Select.Option key={i} title={option.Remark + ' (' + option.TbName + ')'} value={option.TbName}>{option.Remark + ' (' + option.TbName + ')'}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/menu/replaceField/settingform/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/menu/replaceField/settingform/index.scss
diff --git a/src/menu/stylecombcontrolbutton/index.jsx b/src/menu/stylecombcontrolbutton/index.jsx
index 19f3454..b644e5b 100644
--- a/src/menu/stylecombcontrolbutton/index.jsx
+++ b/src/menu/stylecombcontrolbutton/index.jsx
@@ -12,7 +12,7 @@
   }
 
   state = {
-    label: '璋冩暣',
+    label: '鎵归噺璋冩暣',
     parent: null,
     type: '',
     components: []
@@ -127,7 +127,7 @@
   triggerStyleChange = () => {
     const { label, components } = this.state
 
-    if (label === '璋冩暣') {
+    if (label === '鎵归噺璋冩暣') {
       document.body.className = 'style-control'
       sessionStorage.setItem('style-control', 'true')
       this.setState({label: '閫�鍑�'})
@@ -141,14 +141,14 @@
 
       MKEmitter.emit('closeCombineStyle')
 
-      this.setState({label: '璋冩暣', parent: null, components: []})
+      this.setState({label: '鎵归噺璋冩暣', parent: null, components: []})
     }
   }
   
   render() {
     const { label } = this.state
     return (
-      <Button className="style-control-button" icon="font-colors" title="璋冩暣鏍峰紡" onClick={this.triggerStyleChange}>{label}</Button>
+      <Button className="style-control-button" icon="font-colors" title="鎵归噺璋冩暣鏍峰紡" onClick={this.triggerStyleChange}>{label}</Button>
     )
   }
 }
diff --git a/src/menu/stylecombcontrolbutton/index.scss b/src/menu/stylecombcontrolbutton/index.scss
index 09668c2..3732704 100644
--- a/src/menu/stylecombcontrolbutton/index.scss
+++ b/src/menu/stylecombcontrolbutton/index.scss
@@ -15,11 +15,19 @@
     bottom: 0;
     right: 0;
     z-index: 12;
-    background:rgba(0, 0, 0, 0.3);
+    background:rgba(0, 0, 0, 0.2);
   }
   .menu-body .menu-view >.ant-card >.ant-card-body {
     position: relative;
     z-index: 13;
+    background:#ffffff;
+  }
+  .menu-view {
+    .anticon-tool {
+      display: none;
+    }
+  }
+  .mk-mob-view .mob-shell {
     .anticon-tool {
       display: none;
     }
diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx
index 595e8ff..69d11e7 100644
--- a/src/menu/stylecontroller/index.jsx
+++ b/src/menu/stylecontroller/index.jsx
@@ -194,6 +194,27 @@
   }
 
   /**
+   * @description 淇敼鑳屾櫙澶у皬
+   */
+  changeBackgroundSize = (val) => {
+    this.updateStyle({backgroundSize: val})
+  }
+
+  /**
+   * @description 淇敼鑳屾櫙浣嶇疆
+   */
+  changeBackgroundPositon= (val) => {
+    this.updateStyle({backgroundPositon: val})
+  }
+
+  /**
+   * @description 淇敼鑳屾櫙閲嶅璁剧疆
+   */
+  changeBackgroundRepeat = (val) => {
+    this.updateStyle({backgroundRepeat: val})
+  }
+
+  /**
    * @description 淇敼闃村奖棰滆壊 锛岄鑹叉帶浠�
    */
   changeShadowColor = (val) => {
@@ -329,7 +350,7 @@
                     label={<Icon title="瀹藉害" type="column-width" />}
                     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', '%']} onChange={this.changeWidth}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -448,6 +469,48 @@
                     <SourceComponent value={backgroundImage} type="" placement="right" onChange={this.imgChange}/>
                   </Form.Item>
                 </Col> : null}
+                {!options.includes('backgroundColor') ? <Col span={24}>
+                  <Form.Item
+                    colon={false}
+                    label="姣斾緥"
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <Select defaultValue={card.backgroundSize || 'cover'} onChange={this.changeBackgroundSize}>
+                      <Option value="100%">100%</Option>
+                      <Option value="100% 100%">100% 100%</Option>
+                      <Option value="auto 100%">auto 100%</Option>
+                      <Option value="contain">contain</Option>
+                      <Option value="cover">cover</Option>
+                    </Select>
+                  </Form.Item>
+                </Col> : null}
+                {!options.includes('backgroundColor') ? <Col span={24}>
+                  <Form.Item
+                    colon={false}
+                    label="閲嶅"
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <Select defaultValue={card.backgroundRepeat || 'no-repeat'} onChange={this.changeBackgroundRepeat}>
+                      <Option value="repeat">repeat</Option>
+                      <Option value="no-repeat">no-repeat</Option>
+                      <Option value="repeat-x">repeat-x</Option>
+                      <Option value="repeat-y">repeat-y</Option>
+                    </Select>
+                  </Form.Item>
+                </Col> : null}
+                {!options.includes('backgroundColor') ? <Col span={24}>
+                  <Form.Item
+                    colon={false}
+                    label="浣嶇疆"
+                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
+                  >
+                    <Select defaultValue={card.backgroundPositon || 'center'} onChange={this.changeBackgroundPositon}>
+                      <Option value="center">center</Option>
+                      <Option value="top">top</Option>
+                      <Option value="bottom">bottom</Option>
+                    </Select>
+                  </Form.Item>
+                </Col> : null}
               </Panel> : null}
               {options.includes('border') ? <Panel header="杈规" key="border">
                 <Col span={24}>
@@ -557,7 +620,7 @@
                     label={<Icon title="涓婅竟璺�" type="arrow-up"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.marginTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
+                    <StyleInput defaultValue={card.marginTop || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -566,7 +629,7 @@
                     label={<Icon title="涓嬭竟璺�" type="arrow-down"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.marginBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
+                    <StyleInput defaultValue={card.marginBottom || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -575,7 +638,7 @@
                     label={<Icon title="宸﹁竟璺�" type="arrow-left"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.marginLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
+                    <StyleInput defaultValue={card.marginLeft || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -584,7 +647,7 @@
                     label={<Icon title="鍙宠竟璺�" type="arrow-right"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.marginRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
+                    <StyleInput defaultValue={card.marginRight || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -595,7 +658,7 @@
                     label={<Icon title="涓婅竟璺�" type="arrow-up"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.paddingTop || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
+                    <StyleInput defaultValue={card.paddingTop || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -604,7 +667,7 @@
                     label={<Icon title="涓嬭竟璺�" type="arrow-down"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.paddingBottom || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
+                    <StyleInput defaultValue={card.paddingBottom || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -613,7 +676,7 @@
                     label={<Icon title="宸﹁竟璺�" type="arrow-left"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.paddingLeft || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
+                    <StyleInput defaultValue={card.paddingLeft || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
                   </Form.Item>
                 </Col>
                 <Col span={24}>
@@ -622,7 +685,7 @@
                     label={<Icon title="鍙宠竟璺�" type="arrow-right"/>}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <StyleInput defaultValue={card.paddingRight || '0px'} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
+                    <StyleInput defaultValue={card.paddingRight || '0px'} options={['px', 'vh', 'vw', '%']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
                   </Form.Item>
                 </Col>
               </Panel> : null}
@@ -633,7 +696,7 @@
                     label={<Icon title="娴姩" type="swap" />}
                     labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                   >
-                    <Radio.Group defaultValue={card.float || 'left'} onChange={(e) => this.changeNormalStyle(e.target.value, 'float')}>
+                    <Radio.Group style={{whiteSpace: 'nowrap'}} defaultValue={card.float || 'left'} onChange={(e) => this.changeNormalStyle(e.target.value, 'float')}>
                       <Radio value="left">宸︽诞鍔�</Radio>
                       <Radio value="right">鍙虫诞鍔�</Radio>
                       <Radio value="none">涓嶆诞鍔�</Radio>
diff --git a/src/menu/sysinterface/settingform/baseform/index.jsx b/src/menu/sysinterface/settingform/baseform/index.jsx
index fbb22d6..431a905 100644
--- a/src/menu/sysinterface/settingform/baseform/index.jsx
+++ b/src/menu/sysinterface/settingform/baseform/index.jsx
@@ -242,8 +242,8 @@
                       message: dict['form.required.input'] + '鍥炶皟琛ㄥ悕!'
                     },
                     {
-                      max: formRule.input.max,
-                      message: formRule.input.message
+                      max: 50,
+                      message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
                     }
                   ]
                 })(<Input placeholder={''} autoComplete="off" />)}
diff --git a/src/mob/colorsketch/index.jsx b/src/mob/colorsketch/index.jsx
index 753a443..7eb42c9 100644
--- a/src/mob/colorsketch/index.jsx
+++ b/src/mob/colorsketch/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 // import { is, fromJS } from 'immutable'
 import { SketchPicker } from 'react-color'
-import { Popover } from 'antd'
+import { Popover, Icon } from 'antd'
 
 import './index.scss'
 
@@ -20,10 +20,11 @@
   }
   state = {
     color: '',
+    allowClear: false
   }
 
   UNSAFE_componentWillMount () {
-    const { defaultValue, value } = this.props
+    const { defaultValue, value, allowClear } = this.props
     let initVal = ''
 
     if (this.props['data-__meta']) {
@@ -34,7 +35,7 @@
       initVal = value
     }
     
-    this.setState({color: initVal})
+    this.setState({color: initVal, allowClear: allowClear === true})
   }
 
   handleChange = (color) => {
@@ -45,6 +46,12 @@
     })
   }
 
+  clear = () => {
+    this.setState({ color: '' }, () => {
+      this.props.onChange && this.props.onChange('')
+    })
+  }
+
   UNSAFE_componentWillReceiveProps(nextProps) {
     if (nextProps.value !== undefined && nextProps.value !== this.state.color) {
       this.setState({ color: nextProps.value })
@@ -52,7 +59,7 @@
   }
 
   render() {
-    const { color } = this.state
+    const { color, allowClear } = this.state
     return (
       <div className="color-sketch-block">
         <Popover content={
@@ -62,7 +69,7 @@
             <div className="color-sketch-block-inner" style={ {background: color} }></div>
           </div>
         </Popover>
-        <div className="color-sketch-value">{color}</div>
+        <div className="color-sketch-value">{color}{allowClear && color ? <Icon onClick={this.clear} type="close"/> : null}</div>
       </div>
     )
   }
diff --git a/src/mob/colorsketch/index.scss b/src/mob/colorsketch/index.scss
index b6aec44..ce226de 100644
--- a/src/mob/colorsketch/index.scss
+++ b/src/mob/colorsketch/index.scss
@@ -18,6 +18,7 @@
     height: 100%;
   }
   .color-sketch-value {
+    position: relative;
     display: inline-block;
     font-size: 13px;
     width: 160px;
@@ -27,6 +28,23 @@
     vertical-align: top;
     white-space: nowrap;
     overflow: visible;
+
+    .anticon-close {
+      position: relative;
+      right: -10px;
+      font-size: 10px;
+      padding: 3px;
+      background: #eeeeee;
+      border-radius: 50%;
+      cursor: pointer;
+      opacity: 0;
+      transition: opacity 0.3s;
+    }
+  }
+}
+.color-sketch-block:hover {
+  .anticon-close {
+    opacity: 1;
   }
 }
 
diff --git a/src/mob/components/formdragelement/card.jsx b/src/mob/components/formdragelement/card.jsx
new file mode 100644
index 0000000..7447e32
--- /dev/null
+++ b/src/mob/components/formdragelement/card.jsx
@@ -0,0 +1,200 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Button, Popover, Switch, Checkbox, Form } from 'antd'
+import moment from 'moment'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard'))
+
+const Card = ({ id, card, moveCard, findCard, editCard, closeCard, copyCard, showField }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'form', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'form',
+    canDrop: () => true,
+    drop: (item) => {
+      const { id: draggedId, originalIndex } = item
+
+      if (originalIndex === undefined) {
+        item.dropTargetId = id
+      } else if (draggedId && draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    }
+  })
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+
+  const close = () => {
+    closeCard(id)
+  }
+
+  const copy = () => {
+    copyCard(id)
+  }
+
+  let selectval = ''
+  if (card.type === 'select' || card.type === 'link') {
+    if (card.initval) {
+      let _option = card.options.filter(option => option.Value === card.initval)[0]
+      if (_option) {
+        selectval = _option.Text || ''
+      } else {
+        selectval = ''
+      }
+    } else if (card.setAll === 'true') {
+      selectval = card.emptyText || '绌�'
+    }
+  }
+
+  let formItem = null
+  if (card.type === 'text' || card.type === 'number') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className={'am-input-control ' + card.cursor}>{card.initval}</div>{card.scan && card.scan !== 'false' ? <div className="am-list-extra"><Icon type="scan" /></div> : null}</div></div>)
+  } else if (card.type === 'number') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className={'am-input-control ' + card.cursor}>{card.initval}</div></div></div>)
+  } else if (card.type === 'select' || card.type === 'link') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control">{selectval || '璇烽�夋嫨'}</div><div className="am-list-extra"><Icon type="right" /></div></div></div>)
+  } else if (card.type === 'date') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control">{card.initval ? moment().subtract(card.initval, 'days').format('YYYY-MM-DD') : '璇烽�夋嫨'}</div><div className="am-list-extra"><Icon type="right" /></div></div></div>)
+  } else if (card.type === 'datemonth') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control">{card.initval ? moment().subtract(card.initval, 'month').format('YYYY-MM') : '璇烽�夋嫨'}</div><div className="am-list-extra"><Icon type="right" /></div></div></div>)
+  } else if (card.type === 'datetime') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control">{card.initval ? moment().subtract(card.initval, 'days').format('YYYY-MM-DD HH:mm') : '璇烽�夋嫨'}</div><div className="am-list-extra"><Icon type="right" /></div></div></div>)
+  } else if (card.type === 'textarea') {
+    let height = (card.maxRows || 2) * 25
+    formItem = (<div className="am-list-item check-card">
+      <div className="am-list-line">
+        <div className="am-input-label">{card.label}</div>
+        <div className="am-input-control">
+          <div style={{textAlign: 'left', position: 'relative', height, lineHeight: 1.5}}>
+            {card.initval ? card.initval : <span style={{color: '#bcbcbc'}}>璇疯緭鍏�</span> }
+            {card.count === 'true' ? <span style={{position: 'absolute', right: 0, bottom: 0}}>0/{card.fieldlength}</span> : null}
+          </div>
+        </div>
+      </div>
+    </div>)
+  } else if (card.type === 'fileupload') {
+    formItem = (
+      <div className="am-list-item checkbox">
+        <div className="am-list-line">
+          <div className="am-input-label">{card.label}</div>
+          <div className="am-input-control" style={{textAlign: 'left'}}>
+            {card.fileType !== 'picture-card' ? <Icon type="upload" style={{position: 'absolute', right: '10px', top: '10px'}} /> : null}
+            {card.fileType === 'picture-card' ? <Button style={{width: '100px', marginBottom: '10px', height: '100px', fontSize: '50px', color: '#d9d9d9'}}><Icon type="plus" /></Button> : null}
+          </div>
+        </div>
+      </div>
+    )
+  } else if (card.type === 'funcvar') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control">{card.linkfield}</div></div></div>)
+  } else if (card.type === 'switch') {
+    formItem = (<div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-list-switch"><Switch checked={card.initval}/></div></div></div>)
+  } else if (card.type === 'radio') {
+    let options = null
+    if (card.options && card.options.length > 0) {
+      options = card.options
+    } else {
+      options = [
+        {key: 'A', Value: 'A', Text: 'A'},
+        {key: 'B', Value: 'B', Text: 'B'},
+        {key: 'C', Value: 'C', Text: 'C'}
+      ]
+    }
+
+    formItem = (
+    <div className={'am-list-item checkbox mk-radio ' + (card.arrange || '')}>
+      <div className="am-list-line">
+        <div className="am-input-label">{card.label}</div>
+        <div className="am-input-control">
+          {card.arrange !== 'line' ? <Checkbox.Group value={[card.initval]}>
+            {options.map(cell => <Checkbox key={cell.key} value={cell.Value}>{cell.Text}</Checkbox>)}
+          </Checkbox.Group> : <div className="mk-radio-group">
+            {options.map(cell => (<div key={cell.key} className="mk-radio-wrapper">
+              <span className="radio-value">{cell.Text}</span>
+              <span className={'radio-check ' + (card.initval === cell.Value ? 'checked' : '')}></span>
+            </div>))}
+          </div>}
+        </div>
+      </div>
+    </div>)
+  } else if (card.type === 'checkbox') {
+    let _val = card.initval ? card.initval.split(',') : []
+    let options = null
+    if (card.options && card.options.length > 0) {
+      options = card.options
+    } else {
+      options = [
+        {key: 'A', Value: 'A', Text: 'A'},
+        {key: 'B', Value: 'B', Text: 'B'},
+        {key: 'C', Value: 'C', Text: 'C'}
+      ]
+    }
+
+    formItem = (
+      <div className={'am-list-item checkbox ' + (card.arrange || '')}>
+        <div className="am-list-line">
+          <div className="am-input-label">{card.label}</div>
+          <div className="am-input-control">
+            {<Checkbox.Group value={_val}>
+              {options.map(cell => <Checkbox key={cell.key} value={cell.Value}>{cell.Text}</Checkbox>)}
+            </Checkbox.Group>}
+          </div>
+        </div>
+      </div>
+    )
+    
+  } else if (card.type === 'hint') {
+    formItem = <div className="am-list-item hint">
+      <div className="am-list-line">
+        <div className="am-input-label">{card.label}</div>
+        <div className="am-input-control">
+          {card.message}  
+        </div>
+      </div>
+    </div>
+  } else if (card.type === 'split') {
+    formItem = <div className="split-line">{card.label}</div>
+  } else if (card.type === 'checkcard') {
+    formItem = (<div className="am-list-item check-card">
+      <div className="am-list-line">
+        {card.hidelabel !== 'true' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">
+          <CheckCard config={card} />
+        </div>
+      </div>
+    </div>)
+  }
+
+  return (
+    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+      <div className="mk-popover-control">
+        <Icon className="edit" type="edit" onClick={edit} />
+        <Icon className="copy" type="copy" onClick={copy} />
+        <Icon className="close" type="close" onClick={close} />
+      </div>
+    } trigger="hover">
+      <div className="page-card" style={{ opacity: opacity}}>
+        <div ref={node => drag(drop(node))}>
+          {card.type === 'split' ? formItem : <Form.Item
+            className={'ant-form-item' + (card.required === 'true' ? ' required' : '') + (card.splitline === 'false' ? ' no-boder' : '')}
+          >
+            {formItem}
+            {showField ? <div className="field-name">{card.field}{card.hidden === 'true' ? '(闅愯棌)' : ''}</div> : ''}
+          </Form.Item>}
+        </div>
+      </div>
+    </Popover>
+  )
+}
+export default Card
diff --git a/src/mob/components/formdragelement/index.jsx b/src/mob/components/formdragelement/index.jsx
new file mode 100644
index 0000000..38485bc
--- /dev/null
+++ b/src/mob/components/formdragelement/index.jsx
@@ -0,0 +1,132 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, setting, handleList, handleForm, closeForm, showField }) => {
+  const [cards, setCards] = useState(list)
+  const moveCard = (id, atIndex) => {
+    const { card, index } = findCard(id)
+
+    if (!card) return
+
+    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
+
+    handleList(_cards)
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
+  }
+
+  const findCard = id => {
+    const card = cards.filter(c => `${c.uuid}` === id)[0]
+    return {
+      card,
+      index: cards.indexOf(card),
+    }
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+    delete card.focus
+    handleForm(card)
+  }
+
+  const closeCard = id => {
+    const { card } = findCard(id)
+    closeForm(card)
+  }
+
+  const copyCard = id => {
+    const { card, index: overIndex } = findCard(id)
+
+    let _card = fromJS(card).toJS()
+    _card.uuid = Utils.getuuid()
+    _card.focus = true
+
+    // 澶嶅埗鍒板壀鍒囨澘
+    let oInput = document.createElement('input')
+    let val = JSON.parse(JSON.stringify(_card))
+    val.copyType = 'form'
+
+    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display = 'none'
+    document.body.removeChild(oInput)
+
+    const _cards = update(cards, { $splice: [[overIndex + 1, 0, _card]] })
+
+    setCards(_cards)
+
+    handleList(_cards, _card)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'form',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.label = 'label'
+      newcard.type = item.subType
+      newcard.resourceType = '0'
+      newcard.options = []
+      newcard.readonly = 'false'
+      newcard.required = 'true'
+      newcard.focus = true
+
+      let targetId = ''
+
+      if (item.dropTargetId) {
+        targetId = item.dropTargetId
+        delete item.dropTargetId
+      } else if (cards.length > 0) {
+        targetId = cards[cards.length - 1].uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`) // cards涓虹┖鏃� overIndex 涓� -1
+      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
+
+      setCards(_cards)
+
+      handleList(_cards, newcard)
+    }
+  })
+
+  let style = {}
+  if (setting.paddingLeft) {
+    style.paddingLeft = setting.paddingLeft
+  }
+  if (setting.paddingRight) {
+    style.paddingRight = setting.paddingRight
+  }
+
+  return (
+    <div ref={drop} className="ant-row modal-fields-row mob-form" style={style}>
+      {cards.map(card => {
+        return <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          showField={showField}
+          moveCard={moveCard}
+          editCard={editCard}
+          closeCard={closeCard}
+          copyCard={copyCard}
+          findCard={findCard}
+        />
+      })}
+    </div>
+  )
+}
+export default Container
diff --git a/src/mob/components/formdragelement/index.scss b/src/mob/components/formdragelement/index.scss
new file mode 100644
index 0000000..28a32dc
--- /dev/null
+++ b/src/mob/components/formdragelement/index.scss
@@ -0,0 +1,245 @@
+
+.modal-fields-row {
+  padding-bottom: 35px;
+  .mob-col.ant-col {
+    display: inline-block;
+    float: none;
+    vertical-align: top;
+    padding-left: 1.2%;
+    padding-right: 1.2%;
+  }
+  .am-list-item {
+    font-size: 16px;
+    padding-left: 10px;
+    position: relative;
+    display: flex;
+    height: 44px;
+    min-height: 44px;
+    background-color: #fff;
+    vertical-align: middle;
+    overflow: hidden;
+    transition: background-color 200ms;
+    align-items: center;
+
+    .am-list-line {
+      border-bottom: 1px solid #ddd;
+      align-items: center;
+      position: relative;
+      display: flex;
+      flex: 1 1;
+      align-self: stretch;
+      padding-right: 15px;
+      overflow: hidden;
+      .am-input-label {
+        width: 28%;
+        color: #000;
+        font-size: 16px;
+        margin-left: 0;
+        margin-right: 5px;
+        text-align: left;
+        white-space: nowrap;
+        overflow: hidden;
+        padding: 2px 0;
+        text-overflow: ellipsis;
+      }
+      .am-list-switch {
+        flex: 1;
+        text-align: right;
+      }
+      .am-input-control {
+        font-size: 16px;
+        flex: 1 1;
+        text-align: right;
+      }
+      .am-input-control.left {
+        text-align: left;
+      }
+      .am-list-extra {
+        display: block;
+        width: 15px;
+        height: 15px;
+        margin-left: 8px;
+        i {
+          vertical-align: top;
+        }
+      }
+    }
+  }
+  .am-list-item.check-card {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+      .check-card-edit-box {
+        margin-top: 0!important;
+      }
+    }
+  }
+  .am-list-item.hint {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+      .am-input-label {
+        line-height: 2;
+      }
+      .am-input-control {
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: left;
+        padding-bottom: 5px;
+      }
+    }
+  }
+  .am-list-item.checkbox {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+    }
+    .mk-radio-group {
+      padding-left: 10px;
+      text-align: left;
+
+      .mk-radio-wrapper:not(:last-child) {
+        border-bottom: 1px solid #ddd;
+      }
+      span {
+        display: inline-block;
+      }
+      .radio-value {
+        width: calc(100% - 50px);
+        white-space: nowrap;
+        overflow: hidden;
+        padding: 2px 0;
+        text-overflow: ellipsis;
+        vertical-align: top;
+      }
+      .radio-check {
+        position: relative;
+        width: 50px;
+        height: 30px;
+        top: 8px;
+      }
+      .radio-check.checked::after {
+        content: ' ';
+        position: absolute;
+        display: table;
+        border: 1px solid #1890ff;
+        border-top: 0;
+        border-left: 0;
+        top: 50%;
+        left: 22%;
+        width: 12px;
+        height: 20px;
+        transform: rotate(45deg) scale(1) translate(-50%, -50%);
+      }
+    }
+    .ant-checkbox-group {
+      display: block;
+      padding-left: 10px;
+      .ant-checkbox-wrapper {
+        display: flex;
+        text-align: left;
+        font-size: 16px;
+        .ant-checkbox {
+          display: block;
+          width: 30px;
+          .ant-checkbox-inner {
+            width: 22px;
+            height: 22px;
+            top: 12px;
+          }
+          .ant-checkbox-inner::after {
+            width: 9px;
+            height: 14px;
+          }
+        }
+        .ant-checkbox + span {
+          display: block;
+          flex: 1 1;
+          border-bottom: 1px solid #ddd;
+        }
+      }
+      .ant-checkbox-wrapper:last-child {
+        .ant-checkbox + span {
+          border-bottom: none;
+        }
+      }
+    }
+  }
+  .am-list-item.checkbox.mk-radio {
+    .ant-checkbox-inner {
+      border-radius: 50%;
+    }
+  }
+  .am-list-item.checkbox:not(.line) {
+    .ant-checkbox-group {
+      .ant-checkbox-wrapper {
+        float: left;
+        margin-right: 15px;
+        .ant-checkbox + span {
+          border-bottom: none;
+        }
+      }
+    }
+    .mk-radio-group {
+      .mk-radio-wrapper {
+        float: left;
+        margin-right: 15px;
+      }
+    }
+  }
+  .split-line {
+    color: #1890ff;
+    font-size: 16px;
+    padding-left: 10px;
+    padding-top: 10px;
+    border-bottom: 1px solid #e9e9e9;
+  }
+  .check-card-edit-box .card-cell span {
+    line-height: 1.5;
+  }
+  .ant-form-item {
+    cursor: move;
+    display: flex;
+    margin-bottom: 0px;
+    .ant-form-item-control-wrapper::after {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      opacity: 0;
+      z-index: 1;
+    }
+    .field-name {
+      margin-left: 10px;
+    }
+    .ant-form-item-children {
+      vertical-align: top;
+    }
+  }
+  .ant-form-item.required {
+    .am-input-label::before {
+      display: inline-block;
+      margin-right: 4px;
+      color: #f5222d;
+      font-size: 14px;
+      font-family: SimSun, sans-serif;
+      line-height: 1;
+      content: '*';
+    }
+  }
+  .ant-form-item.no-boder {
+    .am-list-line {
+      border-bottom: none;
+    }
+  }
+}
+.mob-form.modal-fields-row {
+  .page-card {
+    margin-bottom: 10px;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/login/mob-login-1/index.jsx b/src/mob/components/login/mob-login-1/index.jsx
deleted file mode 100644
index e0b2891..0000000
--- a/src/mob/components/login/mob-login-1/index.jsx
+++ /dev/null
@@ -1,228 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { InputItem, Icon, Checkbox, List, Button } from 'antd-mobile'
-// import { createForm } from 'rc-form'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import Utils from '@/utils/utils.js'
-import ContentUpdate from '@/mob/contupdate'
-import mklogo from '@/assets/mobimg/mklogo.png'
-import './index.scss'
-
-const CheckboxItem = Checkbox.CheckboxItem
-
-class MobLogin extends Component {
-  static propTpyes = {
-    card: PropTypes.object,
-    editId: PropTypes.any,
-    triggerEdit: PropTypes.func,
-    updateConfig: PropTypes.func,
-    onDoubleClick: PropTypes.func
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    rember: true,
-    param: {
-      type: 'login',
-      subtype: 'mob-login-1',
-      box: { uuid: Utils.getuuid(), eleType: 'box', style: {color: '#ffffff', backgroundImage: 'linear-gradient(#378DBE, #46C29E, #48A9D6)'}},
-      logo: { uuid: Utils.getuuid(), eleType: 'img', content: mklogo, style: {marginTop: '17vh', marginBottom: '15px'} },
-      title: { uuid: Utils.getuuid(), eleType: 'text', content: '鏄庣鍟嗕笟鏅鸿兘寮�鏀惧钩鍙�', style: {fontSize: '20px', fontWeight: 'bold', color: '#ffffff', textAlign: 'center', marginTop: '15px', marginBottom: '30px'}},
-      login: { uuid: Utils.getuuid(), eleType: 'button', content: '鐧诲綍', style: {fontSize: '18px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, borderRadius: '25px', marginBottom: '15vh'}},
-      copyright: { uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright漏2017  鎵�鏈夌浉鍏崇増鏉冨綊  鍖椾含鏄庣鏅崕淇℃伅鎶�鏈湁闄愬叕鍙�', style: {fontSize: '12px', color: '#ffffff', textAlign: 'center'} }
-    }
-  }
-
-  UNSAFE_componentWillMount () {
-    const { card } = this.props
-    const { param } = this.state
-
-    if (!card.box) {
-      this.props.updateConfig({...param, ...card})
-    }
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  onChange = (e) => {
-    const { rember } = this.state
-    e.stopPropagation()
-
-    this.setState({
-      rember: !rember
-    })
-  }
-
-  onChangeLang = (value) => {
-    this.setState({
-      lang: value
-    })
-  }
-
-  editLogo = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.logo.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.logo.uuid,
-      items: ['margin']
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editTitle = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.title.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.title.uuid,
-      items: ['font', 'margin'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editMsg = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.copyright.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.copyright.uuid,
-      items: ['font'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editLogin = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.login.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.login.uuid,
-      items: ['font', 'background', 'border', 'margin']
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editBox = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.box.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.box.uuid,
-      items: ['font', 'padding', 'background'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  updateContent = (card) => {
-    Object.keys(card).forEach(key => {
-      if (card[key] === null) {
-        delete card[key]
-      }
-    })
-    this.props.updateConfig(card)
-  }
-
-  render () {
-    const { card, editId } = this.props
-    // const { getFieldProps } = this.props.form
-    const { rember } = this.state
-
-    if (!card.box) return null
-
-    let logoStyle = card.logo && card.logo.style ? fromJS(card.logo.style).toJS() : null
-    if (logoStyle && logoStyle.marginTop && /vh$/ig.test(logoStyle.marginTop)) {
-      let percent = parseInt(logoStyle.marginTop)
-      logoStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (logoStyle && logoStyle.marginBottom && /vh$/ig.test(logoStyle.marginBottom)) {
-      let percent = parseInt(logoStyle.marginBottom)
-      logoStyle.marginBottom = `calc(${(percent / 100) * 625}px)`
-    }
-
-    let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null
-    if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) {
-      let percent = parseInt(titleStyle.marginTop)
-      titleStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) {
-      let percent = parseInt(titleStyle.marginBottom)
-      titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
-    }
-    
-    let loginStyle = fromJS(card.login.style).toJS()
-    if (loginStyle.marginTop && /vh$/ig.test(loginStyle.marginTop)) {
-      let percent = parseInt(loginStyle.marginTop)
-      loginStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (loginStyle.marginBottom && /vh$/ig.test(loginStyle.marginBottom)) {
-      let percent = parseInt(loginStyle.marginBottom)
-      loginStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
-    }
-
-    return (
-      <div className="mob-login-1" onClick={this.editBox} style={card.box.style}>
-        {card.logo ? <div className={'logo ' + (editId === card.logo.uuid ? 'editing' : '')} style={logoStyle} onClick={this.editLogo}>
-          <ContentUpdate element={card.logo} updateContent={(ele) => this.updateContent({...card, logo: ele})}/>
-          <img src={card.logo.content} alt=""/>
-        </div> : null}
-        {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
-          <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
-          {card.title.content}
-        </div> : null}
-        <InputItem
-          placeholder={"UserName"}
-          prefixListCls="mk-login-item am-list"
-          disabled={true}
-        >
-          <Icon type="check-circle-o" />
-        </InputItem>
-        <InputItem
-          placeholder="Password"
-          prefixListCls="mk-login-item am-list"
-          type={'password'}
-          disabled={true}
-        >
-          <Icon type="check-circle" />
-        </InputItem>
-        <div className="other-setting">
-          <CheckboxItem checked={rember} onChange={this.onChange}>
-            <span onClick={this.onChange}>璁颁綇瀵嗙爜</span>
-          </CheckboxItem>
-          {/* <Picker data={langs} value={lang} cols={1} onChange={this.onChangeLang} className="forss">
-            <List.Item>{lang}</List.Item>
-          </Picker> */}
-          <List.Item className="lang">涓枃绠�浣�</List.Item>
-          <div className="clear-both"></div>
-        </div>
-        <Button 
-          type="primary"
-          className={'login ' + (editId === card.login.uuid ? 'editing' : '')} 
-          onDoubleClick={() => this.props.doubleClickCard(card.login)}
-          style={loginStyle}
-          onClick={this.editLogin}
-        >
-          <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
-          {card.login.content}
-        </Button>
-        {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
-          <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
-          {card.copyright.content}
-        </div> : null}
-      </div>
-    )
-  }
-}
-
-// export default createForm()(MobLogin)
-export default MobLogin
\ No newline at end of file
diff --git a/src/mob/components/login/mob-login-1/index.scss b/src/mob/components/login/mob-login-1/index.scss
deleted file mode 100644
index 4ce0042..0000000
--- a/src/mob/components/login/mob-login-1/index.scss
+++ /dev/null
@@ -1,192 +0,0 @@
-.mob-login-1 {
-  position: relative;
-  width: 100%;
-  min-height: 100%;
-  overflow-x: hidden;
-  background-repeat: no-repeat;
-  background-size: cover;
-  background-position: center center;
-  border-top: 1px solid transparent;
-
-  .logo {
-    position: relative;
-    font-size: 14px;
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    text-align: center;
-    line-height: 1.5;
-    border: 1px dotted transparent;
-    img {
-      max-width: 100%;
-    }
-  }
-  .logo.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .logo:not(.editing):hover {
-    border-color: #535353;
-  }
-
-  .plat-name {
-    position: relative;
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    margin-top: 15px;
-    margin-bottom: 30px;
-    text-align: center;
-    line-height: 1.5;
-    font-size: 20px;
-    color: #ffffff;
-    font-weight: bold;
-    letter-spacing: 0px;
-    border: 1px dotted transparent;
-  }
-  .plat-name.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .plat-name:not(.editing):hover {
-    border-color: #535353;
-  }
-
-  .mk-login-item.am-list-item {
-    position: relative;
-    z-index: 1;
-    width: 245px;
-    font-size: 14px;
-    max-width: 270px;
-    line-height: 1.5;
-    margin: 0 auto;
-    margin-bottom: 10px;
-    border-radius: 30px;
-    background-color: rgba(255, 255, 255, 0.3);
-    .am-input-label {
-      width: 30px;
-      color: inherit;
-      padding-top: 10px;
-    }
-    input {
-      color: inherit;
-    }
-    input::-webkit-input-placeholder {
-      color: inherit;
-    }
-    input:-moz-placeholder {
-      color: inherit;
-    }
-    input::-moz-placeholder {
-      color: inherit;
-    }
-    input:-ms-input-placeholder {
-      color: inherit;
-    }
-
-    .am-input-control input:disabled {
-      background-color: transparent;
-    }
-  }
-  .am-list-item:not(:last-child) .am-list-line {
-    border: none;
-  }
-  .other-setting {
-    position: relative;
-    z-index: 1;
-    font-size: 14px;
-    width: 245px;
-    max-width: 270px;
-    line-height: 1.5;
-    margin: 0 auto;
-    margin-bottom: 10px;
-    .am-list-item {
-      float: left;
-      background: transparent;
-      width: 50%;
-      padding: 0;
-      .am-list-thumb:first-child {
-        margin-right: 5px;
-        cursor: pointer;
-
-        .am-checkbox-inner {
-          width: 18px;
-          height: 18px;
-        }
-        .am-checkbox-inner:after {
-          width: 5px;
-          height: 9px;
-        }
-      }
-      .am-list-line .am-list-content {
-        font-size: 14px;
-        color: inherit;
-        cursor: pointer;
-      }
-      .am-list-extra {
-        display: none;
-      }
-    }
-    
-    .am-list-item.lang {
-      float: right;
-      .am-list-line {
-        padding-right: 10px;
-        .am-list-content {
-          text-align: right;
-          cursor: default;
-        }
-      }
-    }
-  }
-  .am-button {
-    position: relative;
-    z-index: 1;
-    width: 245px;
-    max-width: 270px;
-    margin: 0 auto;
-    border: 1px dotted transparent;
-    overflow: visible;
-    letter-spacing: 0px;
-    background-repeat: no-repeat;
-    background-size: cover;
-    background-position: center center;
-    
-    span {
-      font-style: inherit;
-      font-weight: inherit;
-    }
-  }
-  .am-button:hover {
-    color: #fff;
-    border-color: #535353;
-  }
-  .company-msg {
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    font-size: 12px;
-    color: #fafafa;
-    text-align: center;
-    line-height: 1.5;
-    letter-spacing: 0px;
-    border: 1px dotted transparent;
-  }
-  .company-msg.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .company-msg:not(.editing):hover {
-    border-color: #535353;
-  }
-}
-.am-picker-popup-wrap {
-  left: calc(50vw - 305px);
-  right: calc(50vw - 45px);
-  bottom: 54px;
-  overflow: hidden;
-}
-.clear-both {
-  float: none!important;
-  clear: both;
-}
\ No newline at end of file
diff --git a/src/mob/components/login/mob-login-2/index.jsx b/src/mob/components/login/mob-login-2/index.jsx
deleted file mode 100644
index e9aa20c..0000000
--- a/src/mob/components/login/mob-login-2/index.jsx
+++ /dev/null
@@ -1,423 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { InputItem, Button } from 'antd-mobile'
-import { Icon } from 'antd'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import Utils from '@/utils/utils.js'
-import ContentUpdate from '@/mob/contupdate'
-import ContentDelete from '@/mob/contdelete'
-import './index.scss'
-
-class MobLogin2 extends Component {
-  static propTpyes = {
-    card: PropTypes.object,
-    editId: PropTypes.any,
-    triggerEdit: PropTypes.func,
-    updateConfig: PropTypes.func,
-    onDoubleClick: PropTypes.func
-  }
-
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    view: 'account',
-    param: {
-      type: 'login',
-      subtype: 'mob-login-2',
-      box: { uuid: Utils.getuuid(), eleType: 'box', style: {}},
-      title: {
-        uuid: Utils.getuuid(), eleType: 'text', content: '鐧诲綍',
-        style: {
-          fontSize: '18px', fontWeight: 'bold', color: '#000000', textAlign: 'center', marginTop: '10vh', marginBottom: '10vh'
-        }
-      },
-      user: { uuid: Utils.getuuid(), eleType: 'input', content: '閭/鎵嬫満', style: {}},
-      password: { uuid: Utils.getuuid(), eleType: 'input', content: '瀵嗙爜', style: {}},
-      login: {
-        uuid: Utils.getuuid(), eleType: 'button', content: '鐧诲綍',
-        style: {
-          fontSize: '16px', color: '#ffffff', textAlign: 'center', lineHeight: 2.4, backgroundColor: '#44a8f2'
-        }
-      },
-      phone: {
-        uuid: Utils.getuuid(), eleType: 'button', content: '鎵嬫満鐭俊鐧诲綍',
-        style: {
-          fontSize: '16px', color: '#44a8f2', textAlign: 'center', lineHeight: 2.4, border: '1px solid #44a8f2'
-        }
-      },
-      register: {
-        uuid: Utils.getuuid(), eleType: 'text', content: '娉ㄥ唽',
-        style: {
-          fontSize: '14px', color: '#44a8f2', textAlign: 'left'
-        }
-      },
-      lose: {
-        uuid: Utils.getuuid(), eleType: 'text', content: '蹇樿瀵嗙爜锛�',
-        style: {
-          fontSize: '14px', color: '#44a8f2', textAlign: 'right', textDecoration: 'underline'
-        }
-      },
-      auth: {
-        uuid: Utils.getuuid(), eleType: 'text', content: '鍏朵粬鐧诲綍鏂瑰紡',
-        style: {
-          fontSize: '14px', color: '#bcbcbc', textAlign: 'center', marginTop: '30px', marginBottom: '20px'
-        }
-      },
-      authlist: {
-        uuid: Utils.getuuid(),
-        subItems: [
-          {uuid: 'qq', type: 'qq', icon: 'qq', label: 'QQ'},
-          {uuid: 'wechat', type: 'wechat', icon: 'wechat', label: '寰俊'},
-        ],
-      },
-      copyright: {
-        uuid: Utils.getuuid(), eleType: 'textarea', content: 'Copyright漏2017  鎵�鏈夌浉鍏崇増鏉冨綊  鍖椾含鏄庣鏅崕淇℃伅鎶�鏈湁闄愬叕鍙�',
-        style: {
-          fontSize: '12px', textAlign: 'center', color: 'rgba(0, 0, 0, 0.65)'
-        }
-      },
-      links: {
-        uuid: Utils.getuuid(), eleType: 'link', substyle: false,
-        subItems: [
-          {eleType: 'link', content: '闅愮鏀跨瓥', url: '', uuid: Utils.getuuid()},
-          {eleType: 'link', content: '浣跨敤鏉℃', url: '', uuid: Utils.getuuid()},
-        ],
-        style: {
-          fontSize: '12px', textAlign: 'center', color: '#44a8f2', textDecoration: 'underline'
-        }
-      },
-      account: {
-        uuid: Utils.getuuid(), eleType: 'button', content: '璐﹀彿瀵嗙爜鐧诲綍',
-        style: {
-          fontSize: '16px', color: '#44a8f2', textAlign: 'center', lineHeight: 2.4, border: '1px solid #44a8f2'
-        }
-      },
-    }
-  }
-
-  UNSAFE_componentWillMount () {
-    const { card } = this.props
-    const { param } = this.state
-
-    if (!card.box) {
-      this.props.updateConfig({...param, ...card})
-    }
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  editTitle = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.title.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.title.uuid,
-      items: ['font', 'margin'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editPlaceholder = (e, type) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      componentId: card.uuid,
-      uuid: card[type].uuid,
-      items: [''],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editMsg = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.copyright.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.copyright.uuid,
-      items: ['font', 'margin'],
-    }
-    this.props.triggerEdit(element)
-  }
-  
-  editLinks = (e, item) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.links.style).toJS(),
-      componentId: card.uuid,
-      classId: card.links.uuid,
-      uuid: item.uuid,
-      items: ['font'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editLogin = (e, type) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card[type].style).toJS(),
-      componentId: card.uuid,
-      uuid: card[type].uuid,
-      items: ['font', 'background', 'border', 'margin']
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editLose = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.lose.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.lose.uuid,
-      items: ['font'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editRegister = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.register.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.register.uuid,
-      items: ['font'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editAuth = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.auth.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.auth.uuid,
-      items: ['font', 'margin'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  editBox = (e) => {
-    const { card } = this.props
-    e.stopPropagation()
-    let element = {
-      ...fromJS(card.box.style).toJS(),
-      componentId: card.uuid,
-      uuid: card.box.uuid,
-      items: ['font', 'padding', 'background'],
-    }
-    this.props.triggerEdit(element)
-  }
-
-  linkItemAdd = (e) => {
-    let card = fromJS(this.props.card).toJS()
-    e.stopPropagation()
-
-    card.links.subItems.push({
-      eleType: 'link',
-      content: 'link',
-      url: '',
-      uuid: Utils.getuuid()
-    })
-
-    this.props.updateConfig(card)
-  }
-
-  updateContent = (card) => {
-    this.props.updateConfig(card)
-  }
-
-  updateLinkItem = (val, item) => {
-    let card = fromJS(this.props.card).toJS()
-
-    if (!val) {
-      card.links.subItems = card.links.subItems.filter(cell => cell.uuid !== item.uuid)
-    } else {
-      card.links.subItems = card.links.subItems.map(cell => {
-        if (cell.uuid === item.uuid) {
-          return val
-        } else {
-          return cell
-        }
-      })
-    }
-
-    this.props.updateConfig(card)
-  }
-
-  render () {
-    const { card, editId } = this.props
-    const { view } = this.state
-
-    if (!card.box) return null
-
-    let titleStyle = card.title && card.title.style ? fromJS(card.title.style).toJS() : null
-    if (titleStyle && titleStyle.marginTop && /vh$/ig.test(titleStyle.marginTop)) {
-      let percent = parseInt(titleStyle.marginTop)
-      titleStyle.marginTop = `calc(${(percent / 100) * 615}px)`
-    }
-    if (titleStyle && titleStyle.marginBottom && /vh$/ig.test(titleStyle.marginBottom)) {
-      let percent = parseInt(titleStyle.marginBottom)
-      titleStyle.marginBottom = `calc(${(percent / 100) * 615}px)`
-    }
-
-    if (view === 'account') {
-      return (
-        <div className="mob-login-2" onClick={this.editBox} style={card.box.style}>
-          {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
-            <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
-            {card.title.content}
-          </div> : null}
-          
-          <div className={`mk-login-input ${editId === card.user.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'user')}>
-            <ContentUpdate element={card.user} deletable={false} updateContent={(ele) => this.updateContent({...card, user: ele})}/>
-            <InputItem disabled={true} placeholder={card.user.content}></InputItem>
-          </div>
-          <div className={`mk-login-input ${editId === card.password.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'password')}>
-            <ContentUpdate element={card.password} deletable={false} updateContent={(ele) => this.updateContent({...card, password: ele})}/>
-            <InputItem disabled={true} placeholder={card.password.content}></InputItem>
-          </div>
-          <Button 
-            className={'login ' + (editId === card.login.uuid ? 'editing' : '')} 
-            onDoubleClick={() => this.props.doubleClickCard(card.login)}
-            style={card.login.style}
-            onClick={(e) => this.editLogin(e, 'login')}
-          >
-            <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
-            {card.login.content}
-          </Button>
-          <Button 
-            className={'login ' + (editId === card.phone.uuid ? 'editing' : '')} 
-            onDoubleClick={() => this.setState({view: 'phone'})}
-            style={card.phone.style}
-            onClick={(e) => this.editLogin(e, 'phone')}
-          >
-            <ContentUpdate element={card.phone} updateContent={(ele) => this.updateContent({...card, phone: ele})}/>
-            {card.phone.content}
-          </Button>
-          <div className="row-box">
-            {card.register ? <div className={'col-item ' + (editId === card.register.uuid ? 'editing' : '')} style={card.register.style} onClick={this.editRegister}>
-              <ContentUpdate element={card.register} updateContent={(ele) => this.updateContent({...card, register: ele})}/>
-              {card.register.content}
-            </div> : null}
-            {card.lose ? <div className={'col-item right ' + (editId === card.lose.uuid ? 'editing' : '')} style={card.lose.style} onClick={this.editLose}>
-              <ContentUpdate element={card.lose} updateContent={(ele) => this.updateContent({...card, lose: ele})}/>
-              {card.lose.content}
-            </div> : null}
-            <div style={{clear: 'both'}}></div>
-          </div>
-          {card.auth ? <div className={'plat-name ' + (editId === card.auth.uuid ? 'editing' : '')} style={card.auth.style} onClick={this.editAuth}>
-            <ContentUpdate element={card.auth} updateContent={(ele) => this.updateContent({...card, auth: ele})}/>
-            {card.auth.content}
-          </div> : null}
-          {card.authlist ? <div className="other-auth">
-            {card.authlist.subItems.map(cell => (
-              <span className="deletable-item" key={cell.type}>
-                <ContentDelete element={cell} list={card.authlist} updateContent={(ele) => this.updateContent({...card, authlist: ele})}/>
-                <Icon type={cell.icon} />
-                <p>{cell.label}</p>
-              </span>
-            ))}
-          </div> : null}
-          {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
-            <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
-            {card.copyright.content}
-          </div> : null}
-          {card.links ? <div className="links" style={card.links.style}>
-            {card.links.subItems.map(item => (
-              <span className={(editId === item.uuid ? 'editing' : '')} key={item.uuid} onClick={(e) => this.editLinks(e, item)}>
-                <ContentUpdate element={item} updateContent={(val) => this.updateLinkItem(val, item)}/>
-                {item.content}
-              </span>
-            ))}
-            <Icon type="plus" onClick={this.linkItemAdd} />
-          </div> : null}
-        </div>
-      )
-    } else if (view === 'phone') {
-      return (
-        <div className="mob-login-2" onClick={this.editBox} style={card.box.style}>
-          {card.title ? <div className={'plat-name ' + (editId === card.title.uuid ? 'editing' : '')} style={titleStyle} onClick={this.editTitle}>
-            <ContentUpdate element={card.title} updateContent={(ele) => this.updateContent({...card, title: ele})}/>
-            {card.title.content}
-          </div> : null}
-          
-          <div className={`mk-login-input ${editId === card.user.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'user')}>
-            <ContentUpdate element={card.user} deletable={false} updateContent={(ele) => this.updateContent({...card, user: ele})}/>
-            <InputItem disabled={true} placeholder={card.user.content}></InputItem>
-          </div>
-          <div className={`mk-login-input ${editId === card.password.uuid ? 'editing' : ''}`} onClick={(e) => this.editPlaceholder(e, 'password')}>
-            <ContentUpdate element={card.password} deletable={false} updateContent={(ele) => this.updateContent({...card, password: ele})}/>
-            <InputItem disabled={true} placeholder={card.password.content}></InputItem>
-          </div>
-          <Button 
-            className={'login ' + (editId === card.login.uuid ? 'editing' : '')} 
-            onDoubleClick={() => this.props.doubleClickCard(card.login)}
-            style={card.login.style}
-            onClick={(e) => this.editLogin(e, 'login')}
-          >
-            <ContentUpdate element={card.login} deletable={false} updateContent={(ele) => this.updateContent({...card, login: ele})}/>
-            {card.login.content}
-          </Button>
-          <Button 
-            className={'login ' + (editId === card.account.uuid ? 'editing' : '')} 
-            onDoubleClick={() => this.setState({view: 'account'})}
-            style={card.account.style}
-            onClick={(e) => this.editLogin(e, 'account')}
-          >
-            <ContentUpdate element={card.account} updateContent={(ele) => this.updateContent({...card, account: ele})}/>
-            {card.account.content}
-          </Button>
-          <div className="row-box">
-            {card.register ? <div className={'col-item ' + (editId === card.register.uuid ? 'editing' : '')} style={card.register.style} onClick={this.editRegister}>
-              <ContentUpdate element={card.register} updateContent={(ele) => this.updateContent({...card, register: ele})}/>
-              {card.register.content}
-            </div> : null}
-            {card.lose ? <div className={'col-item right ' + (editId === card.lose.uuid ? 'editing' : '')} style={card.lose.style} onClick={this.editLose}>
-              <ContentUpdate element={card.lose} updateContent={(ele) => this.updateContent({...card, lose: ele})}/>
-              {card.lose.content}
-            </div> : null}
-            <div style={{clear: 'both'}}></div>
-          </div>
-          {card.auth ? <div className={'plat-name ' + (editId === card.auth.uuid ? 'editing' : '')} style={card.auth.style} onClick={this.editAuth}>
-            <ContentUpdate element={card.auth} updateContent={(ele) => this.updateContent({...card, auth: ele})}/>
-            {card.auth.content}
-          </div> : null}
-          {card.authlist ? <div className="other-auth">
-            {card.authlist.subItems.map(cell => (
-              <span className="deletable-item" key={cell.type}>
-                <ContentDelete element={cell} list={card.authlist} updateContent={(ele) => this.updateContent({...card, authlist: ele})}/>
-                <Icon type={cell.icon} />
-                <p>{cell.label}</p>
-              </span>
-            ))}
-          </div> : null}
-          {card.copyright ? <div className={'company-msg ' + (editId === card.copyright.uuid ? 'editing' : '')} style={card.copyright.style} onClick={this.editMsg}>
-            <ContentUpdate element={card.copyright} updateContent={(ele) => this.updateContent({...card, copyright: ele})}/>
-            {card.copyright.content}
-          </div> : null}
-          {card.links ? <div className="links" style={card.links.style}>
-            {card.links.subItems.map(item => (
-              <span className={(editId === item.uuid ? 'editing' : '')} key={item.uuid} onClick={(e) => this.editLinks(e, item)}>
-                <ContentUpdate element={item} updateContent={(val) => this.updateLinkItem(val, item)}/>
-                {item.content}
-              </span>
-            ))}
-            <Icon type="plus" onClick={this.linkItemAdd} />
-          </div> : null}
-        </div>
-      )
-    }
-  }
-}
-
-export default MobLogin2
\ No newline at end of file
diff --git a/src/mob/components/login/mob-login-2/index.scss b/src/mob/components/login/mob-login-2/index.scss
deleted file mode 100644
index 59cd1e1..0000000
--- a/src/mob/components/login/mob-login-2/index.scss
+++ /dev/null
@@ -1,201 +0,0 @@
-.mob-login-2 {
-  position: relative;
-  width: 100%;
-  min-height: 100%;
-  overflow-x: hidden;
-  background-repeat: no-repeat;
-  background-size: cover;
-  background-position: center center;
-
-  .plat-name {
-    position: relative;
-    max-width: 280px;
-    min-height: 10px;
-    margin: 0 auto;
-    text-align: center;
-    line-height: 1.5;
-    font-size: 18px;
-    color: #ffffff;
-    border: 1px dotted transparent;
-  }
-  .plat-name.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .plat-name:not(.editing):hover {
-    border-color: #535353;
-  }
-  .row-box {
-    position: relative;
-    width: 280px;
-    margin: 0 auto;
-    line-height: 1.5;
-
-    .col-item {
-      position: relative;
-      display: inline-block;
-      width: 50%;
-      border: 1px dotted transparent;
-    }
-    .col-item.right {
-      float: right;
-    }
-
-    .col-item.editing {
-      border: 1px solid #1890ff;
-      box-shadow: 0px 0px 2px #1890ff;
-    }
-    .col-item:not(.editing):hover {
-      border-color: #535353;
-    }
-  }
-  .other-auth {
-    text-align: center;
-    font-size: 26px;
-    color: rgb(68, 168, 242);
-
-    span {
-      position: relative;
-      display: inline-block;
-      vertical-align: top;
-      p {
-        font-size: 12px;
-        margin-bottom: 10px;
-      }
-    }
-    span:not(:last-child) {
-      margin-right: 15px;
-    }
-  }
-
-  .am-list-item {
-    position: relative;
-    z-index: 1;
-    width: 100%;
-    font-size: 14px;
-    height: 38px;
-    min-height: 38px;
-    line-height: 1.5;
-    margin-bottom: 10px;
-    border: 1px solid #dddddd;
-
-    .am-input-control input:disabled {
-      color: rgba(0, 0, 0, 0.65);
-    }
-
-    .am-input-label {
-      width: 30px;
-      color: inherit;
-      padding-top: 10px;
-    }
-    input {
-      font-size: 14px;
-      color: inherit;
-    }
-    input::-webkit-input-placeholder {
-      color: inherit;
-      opacity: 0.5;
-    }
-    input:-moz-placeholder {
-      color: inherit;
-      opacity: 0.5;
-    }
-    input::-moz-placeholder {
-      color: inherit;
-      opacity: 0.5;
-    }
-    input:-ms-input-placeholder {
-      color: inherit;
-      opacity: 0.5;
-    }
-  }
-  .am-list-item:not(:last-child) .am-list-line {
-    border: none;
-  }
-
-  .mk-login-input {
-    width: 280px;
-    position: relative;
-    margin: 0 auto;
-  }
-  
-  .am-button {
-    position: relative;
-    z-index: 1;
-    width: 280px;
-    margin: 0 auto 10px;
-    border: 1px dotted transparent;
-    overflow: visible;
-    letter-spacing: 0px;
-    background-repeat: no-repeat;
-    background-size: cover;
-    background-position: center center;
-    border-radius: 0;
-    
-    span {
-      font-style: inherit;
-      font-weight: inherit;
-    }
-  }
-  .am-button:hover {
-    color: unset;
-    border-color: #535353;
-  }
-  .company-msg {
-    width: 88%;
-    min-height: 10px;
-    margin-left: 6%;
-    font-size: 12px;
-    text-align: center;
-    line-height: 1.5;
-    letter-spacing: 0px;
-    border: 1px dotted transparent;
-  }
-  .company-msg.editing {
-    border: 1px solid #1890ff;
-    box-shadow: 0px 0px 2px #1890ff;
-  }
-  .company-msg:not(.editing):hover {
-    border-color: #535353;
-  }
-
-  .links {
-    min-height: 10px;
-    font-size: 12px;
-    text-align: center;
-    line-height: 1.5;
-
-    span {
-      display: inline-block;
-      position: relative;
-      text-decoration: inherit;
-      font-style: inherit;
-      min-width: 40px;
-      border: 1px dotted transparent;
-    }
-    span:not(:last-child) {
-      margin-right: 10px;
-    }
-    span:hover {
-      border-color: #535353;
-    }
-    span.editing {
-      border: 1px solid #1890ff;
-      box-shadow: 0px 0px 2px #1890ff;
-    }
-    >.anticon-plus {
-      cursor: pointer;
-      color: #26C281;
-    }
-  }
-}
-.am-picker-popup-wrap {
-  left: calc(50vw - 305px);
-  right: calc(50vw - 45px);
-  bottom: 54px;
-  overflow: hidden;
-}
-.clear-both {
-  float: none!important;
-  clear: both;
-}
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/index.jsx b/src/mob/components/menubar/normal-menubar/index.jsx
new file mode 100644
index 0000000..e02f32e
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/index.jsx
@@ -0,0 +1,265 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, Modal } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+const MenuComponent = asyncComponent(() => import('./menucomponent'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+
+const { confirm } = Modal
+
+class NoramlMenuBar extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: '',
+        parentId: '',
+        dataName: card.dataName || '',
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        wrap: { name: card.name, width: card.width || 24, title: '' },
+        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
+        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
+        subMenus: [{
+          uuid: Utils.getuuid(),
+          setting: { type: 'menu', width: 6, sign: 'icon', icon: 'user', name: '瀹㈡埛', url: '', color: '#ffffff', iconFont: 20, padding: 12, background: '#1890ff', imgWidth: '' },
+          style: {
+            paddingTop: '15px', paddingBottom: '15px'
+          }
+        }]
+      }
+
+      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.subMenus = config.subMenus.map(item => {
+          item.uuid = Utils.getuuid()
+          
+          return item
+        })
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  updateCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.subMenus = card.subMenus.map(item => {
+      if (item.uuid === cell.uuid) return cell
+      return item
+    })
+
+    this.setState({card})
+
+    this.props.updateConfig(card)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  deleteCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+    let _this = this
+
+    confirm({
+      content: '纭畾鍒犻櫎鍗$墖鍚楋紵',
+      onOk() {
+        card.subMenus = card.subMenus.filter(item => item.uuid !== cell.uuid)
+
+        _this.setState({card})
+        _this.props.updateConfig(card)
+      },
+      onCancel() {}
+    })
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  addMenu = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    let newcard = {
+      uuid: Utils.getuuid(),
+      setting: { type: 'menu', width: 6, sign: 'icon', icon: 'user', name: '瀹㈡埛', url: '', color: '#ffffff', iconFont: 20, padding: 12, background: '#1890ff', imgWidth: '' },
+      style: {
+        paddingTop: '15px', paddingBottom: '15px'
+      },
+      isnew: true
+    }
+
+    if (card.subMenus.length > 0) {
+      newcard = fromJS(card.subMenus.slice(-1)[0]).toJS()
+      newcard.uuid = Utils.getuuid()
+      newcard.isnew = true
+    }
+
+    card.subMenus.push(newcard)
+    
+    this.setState({card})
+    this.props.updateConfig(card)
+  }
+
+  move = (item, direction) => {
+    let card = fromJS(this.state.card).toJS()
+
+    let dragIndex = card.subMenus.findIndex(c => c.uuid === item.uuid)
+    let hoverIndex = null
+
+    if (direction === 'left') {
+      hoverIndex = dragIndex - 1
+    } else {
+      hoverIndex = dragIndex + 1
+    }
+
+    if (hoverIndex === -1 || hoverIndex === card.subMenus.length) return 
+
+    card.subMenus.splice(hoverIndex, 0, ...card.subMenus.splice(dragIndex, 1))
+
+    this.setState({card})
+    this.props.updateConfig(card)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card } = this.state
+
+    let offset = 0
+    if (card.wrap.cardFloat && card.wrap.cardFloat !== 'left') {
+      let _width = 0
+      card.subMenus.forEach(card => {
+        _width += card.setting.width
+      })
+      offset = _width < 24 ? 24 - _width : 0
+      if (card.wrap.cardFloat === 'center') {
+        offset = Math.floor(offset / 2)
+      }
+    }
+
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-menubar-edit-box" 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">
+            <Icon className="plus" title="娣诲姞鑿滃崟" onClick={this.addMenu} type="plus" />
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <CopyComponent type="normalmenu" card={card}/>
+            <PasteComponent config={card} options={['menucell']} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <UserComponent config={card}/>
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        {card.subMenus.map((menu, index) => (<MenuComponent key={menu.uuid} offset={!index ? offset : 0} cards={card} card={menu} move={this.move} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
+      </div>
+    )
+  }
+}
+
+export default NoramlMenuBar
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/index.scss b/src/mob/components/menubar/normal-menubar/index.scss
new file mode 100644
index 0000000..c4c97f1
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/index.scss
@@ -0,0 +1,62 @@
+.menu-menubar-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 20px;
+  
+  .card-control {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    .anticon-tool {
+      right: auto;
+      left: 1px;
+      padding: 1px;
+    }
+  }
+  .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);
+  }
+
+  .menu-item {
+    overflow: hidden;
+    position: relative;
+    min-height: 20px;
+    .menu-name {
+      text-align: center;
+      font-style: inherit;
+      font-weight: inherit;
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+    }
+    .menu-sign {
+      text-align: center;
+      .anticon {
+        border-radius: 50%;
+      }
+      img {
+        border-radius: 50%;
+      }
+    }
+  }
+}
+.menu-menubar-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-menubar-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/mob/components/menubar/normal-menubar/menucomponent/index.jsx b/src/mob/components/menubar/normal-menubar/menucomponent/index.jsx
new file mode 100644
index 0000000..b85cfd5
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/menucomponent/index.jsx
@@ -0,0 +1,218 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Modal, Popover, Icon, Col } from 'antd'
+
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import Utils from '@/utils/utils.js'
+import SettingForm from './settingform'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { confirm } = Modal
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+
+class MenuBoxComponent extends Component {
+  static propTpyes = {
+    offset: PropTypes.any,           // 鍋忕Щ閲�
+    cards: PropTypes.object,         // 鍗$墖琛岄厤缃俊鎭�
+    card: PropTypes.object,          // 鍗$墖閰嶇疆淇℃伅
+    move: PropTypes.func,            // 鍗$墖绉诲姩
+    deleteElement: PropTypes.func,   // 鍗$墖鍒犻櫎
+    updateElement: PropTypes.func    // 鑿滃崟閰嶇疆鏇存柊
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    formlist: null,
+    visible: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    this.setState({
+      card: fromJS(card).toJS()
+    })
+  }
+
+  componentDidMount () {
+    const { card } = this.props
+    MKEmitter.addListener('submitStyle', this.getStyle)
+
+    if (card.isnew) {
+      this.setState({
+        visible: true
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    const { cards } = this.props
+    
+    return !is(fromJS(cards.wrap), fromJS(nextProps.cards.wrap)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  getStyle = (comIds, style) => {
+    const { cards } = this.props
+    const { card } = this.state
+
+    if (comIds.length !== 2 || comIds[0] !== cards.uuid || comIds[1] !== card.uuid) return
+
+    let _card = fromJS(card).toJS()
+    _card.style = style
+
+    this.setState({
+      card: _card
+    })
+
+    this.props.updateElement(_card)
+  }
+
+  changeStyle = () => {
+    const { cards } = this.props
+    const { card } = this.state
+
+    let _style = card.style ? fromJS(card.style).toJS() : {}
+    let options = ['font', 'border', 'padding']
+
+    MKEmitter.emit('changeStyle', [cards.uuid, card.uuid], options, _style)
+  }
+
+  settingSubmit = () => {
+    const { card } = this.state
+
+    this.settingRef.handleConfirm().then(res => {
+      let _card = {...card, setting: res}
+
+      if (!card.isnew && card.setting.type === 'menu' && _card.setting.type !== 'menu') {
+        const _this = this
+        confirm({
+          content: '鑿滃崟灞炴�х敱鈥滆彍鍗曗�濆垏鎹㈣嚦鍏朵粬绫诲瀷鏃讹紝鑿滃崟灏嗚閲嶇疆锛屽嵆瑙i櫎涔嬪墠鑿滃崟鐨勭粦瀹氬叧绯伙紝纭畾淇敼鍚楋紵',
+          onOk() {
+            _card.uuid = Utils.getuuid()
+            _this.setState({ visible: false, card: _card })
+            _this.props.updateElement(_card)
+          },
+          onCancel() {}
+        })
+      } else {
+        delete _card.isnew
+        this.setState({ visible: false, card: _card })
+        this.props.updateElement(_card)
+      }
+    })
+  }
+
+  cancel = () => {
+    const { card } = this.state
+
+    if (card.isnew) {
+      let _card = fromJS(card).toJS()
+      delete _card.isnew
+
+      this.setState({ visible: false, card: _card })
+      this.props.updateElement(_card)
+    } else {
+      this.setState({ visible: false })
+    }
+  }
+
+  changeMenu = () => {
+    const { card } = this.state
+
+    if (card.setting.type === 'link') {
+      window.open(card.setting.linkurl)
+    } else {
+      MKEmitter.emit('changeEditMenu', {
+        MenuID: card.setting.type === 'linkmenu' ? card.setting.linkMenuId : card.uuid,
+        copyMenuId: card.setting.type === 'menu' ? card.setting.copyMenuId : '',
+        MenuNo: card.setting.MenuNo || '',
+        MenuName: card.setting.name,
+      })
+    }
+  }
+
+  render() {
+    const { cards, offset } = this.props
+    const { card, visible, dict } = this.state
+
+    let _style = {...card.style}
+
+    if (_style.shadow) {
+      _style.boxShadow = '0 0 4px ' + _style.shadow
+    }
+
+    _style = resetStyle(_style)
+
+    return (
+      <Col span={card.setting.width || 6} offset={offset || 0}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="edit" title="缂栬緫" type="edit" onClick={() => this.setState({visible: true})} />
+            <CopyComponent type="menucell" card={card}/>
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+              <div className="mk-popover-control">
+                <Icon className="plus" title="宸︾Щ" type="arrow-left" onClick={() => this.props.move(card, 'left')} />
+                <Icon className="close" title="鍙崇Щ" type="arrow-right" onClick={() => this.props.move(card, 'right')} />
+              </div>
+            } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}>
+              <Icon type="swap" id={card.uuid + 'swap'}/>
+            </Popover>
+            <Icon className="close" title="鍒犻櫎鑿滃崟" type="delete" onClick={() => this.props.deleteElement(card)} />
+          </div>
+        } trigger="hover">
+          <div className="menu-item" onDoubleClick={() => this.changeMenu()} style={_style}>
+            {card.setting.sign === 'icon' ? <div className="menu-sign">
+              <Icon style={{
+                fontSize: card.setting.iconFont || 20,
+                padding: card.setting.padding,
+                background: card.setting.background,
+                color: card.setting.color
+              }} type={card.setting.icon}/>
+            </div> : <div className="menu-sign">
+              <img style={{width: card.setting.imgWidth, height: card.setting.imgWidth}} src={card.setting.url} alt=""/>
+            </div>}
+            <div className="menu-name">{card.setting.name}</div>
+          </div>
+        </Popover>
+        <Modal
+          wrapClassName="popview-modal"
+          title={'鑿滃崟璁剧疆'}
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.settingSubmit}
+          onCancel={this.cancel}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            cards={cards}
+            setting={card.setting}
+            inputSubmit={this.settingSubmit}
+            wrappedComponentRef={(inst) => this.settingRef = inst}
+          />
+        </Modal>
+      </Col>
+    )
+  }
+}
+
+export default MenuBoxComponent
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/mob/components/menubar/normal-menubar/menucomponent/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/mob/components/menubar/normal-menubar/menucomponent/index.scss
diff --git a/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.jsx b/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.jsx
new file mode 100644
index 0000000..b193269
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.jsx
@@ -0,0 +1,302 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Radio, Tooltip, Icon, Input, InputNumber, Select } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const { TextArea } = Input
+const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
+const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
+const MkIcon = asyncComponent(() => import('@/components/mkIcon'))
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    cards: PropTypes.object,     // 鍗$墖闆�
+    setting: PropTypes.object,   // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    type: this.props.setting.type,
+    sign: this.props.setting.sign,
+    menulist: []
+  }
+
+  UNSAFE_componentWillMount() {
+    let menulist = sessionStorage.getItem('appMenus')
+
+    if (menulist) {
+      try {
+        menulist = JSON.parse(menulist)
+      } catch {
+        menulist = []
+      }
+    } else {
+      menulist = []
+    }
+    this.setState({menulist})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { setting } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { menulist, type, sign } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menubar-menu-card-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="鑿滃崟鍚嶇О">
+                {getFieldDecorator('name', {
+                  initialValue: setting.name || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '鑿滃崟鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鑿滃崟鍙傛暟">
+                {getFieldDecorator('MenuNo', {
+                  initialValue: setting.MenuNo || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '鑿滃崟鍙傛暟!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  鍗$墖瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: setting.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit}/>)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鑿滃崟灞炴��">
+                {getFieldDecorator('type', {
+                  initialValue: type,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '绫诲瀷!'
+                    }
+                  ]
+                })(
+                  <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({type: e.target.value})}>
+                    <Radio value="menu">鑿滃崟</Radio>
+                    <Radio value="linkmenu">鍏宠仈鑿滃崟</Radio>
+                    <Radio value="link">閾炬帴</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {type === 'menu' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="澶嶅埗鑿滃崟浠呭湪褰撳墠鑿滃崟涓嶅瓨鍦ㄦ椂鏈夋晥銆�">
+                  <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
+                  澶嶅埗鑿滃崟
+                </Tooltip>
+              }>
+                {getFieldDecorator('copyMenuId', {
+                  initialValue: setting.copyMenuId || ''
+                })(
+                  <Select allowClear>
+                    {menulist.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {type === 'linkmenu' ? <Col span={12}>
+              <Form.Item label="鍏宠仈鑿滃崟">
+                {getFieldDecorator('linkMenuId', {
+                  initialValue: setting.linkMenuId || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鍏宠仈鑿滃崟!'
+                    }
+                  ]
+                })(
+                  <Select
+                    showSearch
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {menulist.map(option =>
+                      <Select.Option key={option.MenuID} value={option.MenuID}>{option.MenuName}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {type === 'link' ? <Col span={24} className="textarea">
+              <Form.Item label="閾炬帴">
+                {getFieldDecorator('linkurl', {
+                  initialValue: setting.linkurl || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '閾炬帴!'
+                    }
+                  ]
+                })( <TextArea rows={2}/> )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label="鏍囧織">
+                {getFieldDecorator('sign', {
+                  initialValue: sign,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鏍囧織!'
+                    }
+                  ]
+                })(
+                  <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({sign: e.target.value})}>
+                    <Radio value="icon">鍥炬爣</Radio>
+                    <Radio value="image">鍥剧墖</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {sign === 'icon' ? <Col span={12}>
+              <Form.Item label="鍥炬爣">
+                {getFieldDecorator('icon', {
+                  initialValue: setting.icon || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鍥炬爣!'
+                    }
+                  ]
+                })(
+                  <MkIcon />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'icon' ? <Col span={12}>
+              <Form.Item label="瀛椾綋澶у皬">
+                {getFieldDecorator('iconFont', {
+                  initialValue: setting.iconFont || 20
+                })(
+                  <InputNumber min={12} max={200} precision={0} onPressEnter={this.handleSubmit}/>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'icon' ? <Col span={12}>
+              <Form.Item label="鍐呰竟璺�">
+                {getFieldDecorator('padding', {
+                  initialValue: setting.padding || 12
+                })(
+                  <InputNumber min={0} max={200} precision={0} onPressEnter={this.handleSubmit}/>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'icon' ? <Col span={12}>
+              <Form.Item label="瀛椾綋棰滆壊">
+                {getFieldDecorator('color', {
+                  initialValue: setting.color || '#ffffff'
+                })(
+                  <ColorSketch />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'icon' ? <Col span={12}>
+              <Form.Item label="鑳屾櫙鑹�">
+                {getFieldDecorator('background', {
+                  initialValue: setting.background || '#1890ff'
+                })(
+                  <ColorSketch />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'image' ? <Col span={12}>
+              <Form.Item label="鍥剧墖鍦板潃">
+                {getFieldDecorator('url', {
+                  initialValue: setting.url || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '鍥剧墖鍦板潃!'
+                    }
+                  ]
+                })(
+                  <SourceComponent type="" placement="right"/>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {sign === 'image' ? <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鍥剧墖瀹藉害涓庨珮搴︾浉褰擄紝浣跨敤鐨勫浘鐗囨瘮渚嬪簲涓�1:1銆�">
+                  <Icon type="question-circle" />
+                  鍥剧墖瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('imgWidth', {
+                  initialValue: setting.imgWidth || 36
+                })(
+                  <InputNumber min={10} max={500} precision={0} onPressEnter={this.handleSubmit}/>
+                )}
+              </Form.Item>
+            </Col> : null}
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.scss b/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.scss
new file mode 100644
index 0000000..91dfcf6
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/menucomponent/settingform/index.scss
@@ -0,0 +1,25 @@
+.model-menubar-menu-card-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .textarea {
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+    }
+  }
+  .ant-radio-wrapper {
+    margin-right: 3px;
+  }
+  .color-sketch-block {
+    margin-top: 7px;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/wrapsetting/index.jsx b/src/mob/components/menubar/normal-menubar/wrapsetting/index.jsx
new file mode 100644
index 0000000..81346a6
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/wrapsetting/index.jsx
@@ -0,0 +1,83 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title={config.type === 'table' ? '琛ㄦ牸璁剧疆' : '鍗$墖璁剧疆'}
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            config={config}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/wrapsetting/index.scss b/src/mob/components/menubar/normal-menubar/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.jsx b/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..e501fa1
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.jsx
@@ -0,0 +1,155 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    roleList: [],
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    this.setState({roleList})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { wrap } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { roleList } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menubar-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="鏍囬">
+                {getFieldDecorator('title', {
+                  initialValue: wrap.title || ''
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="瀵归綈鏂瑰紡">
+                {getFieldDecorator('float', {
+                  initialValue: wrap.float || 'left'
+                })(
+                  <Radio.Group style={{whiteSpace: 'nowrap'}}>
+                    <Radio key="left" value="left"> 宸﹀榻� </Radio>
+                    <Radio key="center" value="center"> 灞呬腑 </Radio>
+                    <Radio key="right" value="right"> 鍙冲榻� </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.blacklist || []
+                })(
+                  <Select
+                    showSearch
+                    mode="multiple"
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {roleList.map(option =>
+                      <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.scss b/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..92283b8
--- /dev/null
+++ b/src/mob/components/menubar/normal-menubar/wrapsetting/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menubar-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/index.jsx b/src/mob/components/navbar/normal-navbar/index.jsx
new file mode 100644
index 0000000..3565e4a
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/index.jsx
@@ -0,0 +1,187 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+
+import asyncIconComponent from '@/utils/asyncIconComponent'
+
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+const MenuComponent = asyncIconComponent(() => import('./menusetting'))
+const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
+
+class NormalNavbar extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, datatype: 'static', height: 50 },
+        style: {borderTopColor: '#bcbcbc', borderTopWidth: '1px', paddingTop: '5px', fontSize: '13px' },
+        menus: [],
+        columns: [],
+        scripts: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+      }
+
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+  
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['font', 'background', 'border', 'padding'], card.style)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  changeMenu = (menu) => {
+    if (menu.property === 'link') {
+      window.open(menu.link)
+    } else {
+      MKEmitter.emit('changeEditMenu', {
+        MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
+        copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
+        MenuNo: menu.MenuNo,
+        MenuName: menu.name,
+      })
+    }
+  }
+
+  render() {
+    const { card } = this.state
+
+    let _style = {...card.style}
+    if (_style.shadow) {
+      _style.boxShadow = '0 0 4px ' + _style.shadow
+    }
+    _style.height = card.wrap.height
+
+    return (
+      <div className="normal-navbar-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <MenuComponent config={card} updateConfig={this.updateComponent} />
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
+            {card.wrap.datatype === 'static' ? <Icon style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <div className="menu">
+          {card.menus.map(menu => {
+            return (
+              <div key={menu.MenuID} className="am-tab-bar-tab" onDoubleClick={() => this.changeMenu(menu)}>
+                {menu.icon ? <div className="am-tab-bar-tab-icon">
+                  <span className="am-badge am-tab-bar-tab-badge tab-badge">
+                    <Icon type={menu.icon} />
+                    {menu.tip ? <sup className="am-badge-text"></sup> : null}
+                  </span>
+                </div> : null}
+                <p className="am-tab-bar-tab-title">{menu.name}</p>
+              </div>
+            )
+          })}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default NormalNavbar
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/index.scss b/src/mob/components/navbar/normal-navbar/index.scss
new file mode 100644
index 0000000..cebf6d4
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/index.scss
@@ -0,0 +1,111 @@
+.normal-navbar-edit-box {
+  position: absolute;
+  bottom: 0px;
+  left: 0px;
+  width: 100%;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 30px;
+  z-index: 3;
+  
+  .menu {
+    height: 100%;
+    display: flex;
+    font-size: inherit;
+    color: inherit;
+    .am-tab-bar-tab {
+      position: relative;
+      text-align: center;
+      flex: 1;
+      cursor: pointer;
+      .anticon {
+        font-size: 150%;
+      }
+      .am-badge-text {
+        position: absolute;
+        top: -2px;
+        height: 8px;
+        width: 8px;
+        border-radius: 100%;
+        background: #ff5b05;
+        z-index: 1;
+      }
+      p {
+        margin-bottom: 0;
+      }
+    }
+  }
+
+  .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 {
+    overflow: hidden;
+    position: relative;
+    background-color: #ffffff;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    min-height: 20px;
+  }
+  
+  .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;
+    }
+  }
+  .card-add-button {
+    text-align: right;
+    clear: left;
+    .anticon-plus {
+      font-size: 20px;
+      color: #26C281;
+      padding: 5px;
+      margin-right: 10px;
+    }
+  }
+  .ant-pagination {
+    float: right;
+    margin: 10px;
+  }
+
+  .model-menu-action-list {
+    .page-card {
+      line-height: 55px;
+    }
+  }
+}
+.normal-navbar-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.normal-navbar-edit-box:hover {
+  box-shadow: 0px 0px 4px #1890ff;
+}
+.top-menu-popover {
+  padding-top: 0!important;
+}
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/index.jsx b/src/mob/components/navbar/normal-navbar/menusetting/index.jsx
new file mode 100644
index 0000000..633fff4
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/index.jsx
@@ -0,0 +1,63 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import MenuTable from './menutable'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+    let menus = this.mTable.state.data || []
+
+    this.props.updateConfig({...config, menus})
+    this.setState({visible: false})
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="menu" title="鑿滃崟" onClick={() => this.setState({ visible: true })}/>
+        <Modal
+          wrapClassName="popview-modal"
+          title="鑿滃崟缂栬緫"
+          visible={visible}
+          width={950}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <MenuTable
+            menus={config.menus}
+            cols={config.columns}
+            ref={(ref) => { this.mTable = ref }}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/index.scss b/src/mob/components/navbar/normal-navbar/menusetting/index.scss
new file mode 100644
index 0000000..3a906d8
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-menu {
+    color: purple;
+  }
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx b/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx
new file mode 100644
index 0000000..2fafa7b
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx
@@ -0,0 +1,222 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, Select } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const { TextArea } = Input
+const MkIcon = asyncComponent(() => import('@/components/mkIcon'))
+
+class SettingForm extends Component {
+  static propTpyes = {
+    menu: PropTypes.object,      // 鑿滃崟淇℃伅
+    cols: PropTypes.array,       // 瀛楁闆�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    property: this.props.menu.property || 'menu',
+    appMenus: [],
+  }
+
+  UNSAFE_componentWillMount () {
+    let appMenus = sessionStorage.getItem('appMenus')
+    if (appMenus) {
+      try {
+        appMenus = JSON.parse(appMenus)
+      } catch {
+        appMenus = []
+      }
+    } else {
+      appMenus = []
+    }
+
+    this.setState({appMenus})
+  }
+
+  componentDidMount() {
+    const { menu } = this.props
+
+    if (!menu.MenuID) {
+      let _form = document.getElementById('name')
+      _form && _form.select()
+    }
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  changeProperty = (e) => {
+    let val = e.target.value
+
+    this.setState({property: val})
+  }
+
+  render() {
+    const { menu, cols } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { property, appMenus } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="mob-menu-form">
+        <Row gutter={24}>
+          <Col span={12}>
+            <Form.Item label="鑿滃崟鍚嶇О">
+              {getFieldDecorator('name', {
+                initialValue: menu.name,
+                rules: [
+                  {
+                    required: true,
+                    message: '璇疯緭鍏ヨ彍鍗曞悕绉�!'
+                  }
+                ]
+              })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="鑿滃崟鍙傛暟">
+              {getFieldDecorator('MenuNo', {
+                initialValue: menu.MenuNo || '',
+                rules: [
+                  {
+                    required: true,
+                    message: '璇疯緭鍏ヨ彍鍗曞弬鏁�!'
+                  }
+                ]
+              })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="鍥炬爣">
+              {getFieldDecorator('icon', {
+                initialValue: menu.icon || ''
+              })(
+                <MkIcon allowClear />
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="缁戝畾鎻愮ず瀛楁鍚庯紝浼氬湪鑿滃崟鍙充笂瑙掓樉绀烘彁绀轰俊鎭�傛敞锛氬湪娣诲姞鍥炬爣鏃舵湁鏁堛��">
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
+                鎻愮ず
+              </Tooltip>
+            }>
+              {getFieldDecorator('tip', {
+                initialValue: menu.tip || ''
+              })(
+                <Select allowClear>
+                  {cols.map(item => <Select.Option key={item.uuid} value={item.field}>{item.label}</Select.Option>)}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="鑿滃崟灞炴��">
+              {getFieldDecorator('property', {
+                initialValue: menu.property || 'menu'
+              })(
+                <Radio.Group onChange={this.changeProperty} style={{whiteSpace: 'nowrap'}}>
+                  <Radio value="menu">鑿滃崟</Radio>
+                  <Radio value="linkmenu">鍏宠仈鑿滃崟</Radio>
+                  <Radio value="link">閾炬帴</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="闅愯棌">
+              {getFieldDecorator('hidden', {
+                initialValue: menu.hidden || 'false'
+              })(
+                <Radio.Group>
+                  <Radio value="false">鍚�</Radio>
+                  <Radio value="true">鏄�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {property === 'link' ? <Col span={24}>
+            <Form.Item label="閾炬帴鍦板潃" className="textarea">
+              {getFieldDecorator('link', {
+                initialValue: menu.link || '',
+                rules: [{
+                  required: true,
+                  message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
+                }]
+              })(<TextArea rows={2} />)}
+            </Form.Item>
+          </Col> : null}
+          {property === 'linkmenu' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鍏宠仈褰撳墠app涓凡鏈夌殑鑿滃崟銆�">
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
+                鍏宠仈鑿滃崟
+              </Tooltip>
+            }>
+              {getFieldDecorator('linkMenuId', {
+                initialValue: menu.linkMenuId || '',
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨鍏宠仈鑿滃崟!'
+                }]
+              })(
+                <Select>
+                  {appMenus.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {property === 'menu' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="澶嶅埗鑿滃崟浠呭湪褰撳墠鑿滃崟涓嶅瓨鍦ㄦ椂鏈夋晥銆�">
+                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
+                澶嶅埗鑿滃崟
+              </Tooltip>
+            }>
+              {getFieldDecorator('copyMenuId', {
+                initialValue: menu.copyMenuId || ''
+              })(
+                <Select>
+                  {appMenus.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.scss b/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.scss
new file mode 100644
index 0000000..b94aad3
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/menuform/index.scss
@@ -0,0 +1,10 @@
+.mob-menu-form {
+  .ant-form-item.textarea {
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx b/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx
new file mode 100644
index 0000000..b17ff7d
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx
@@ -0,0 +1,198 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Table, Button, Modal, Icon } from 'antd'
+
+import MenuForm from '../menuform'
+import Utils from '@/utils/utils.js'
+// import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { confirm } = Modal
+
+class MenuTable extends Component {
+  static propTpyes = {
+    menus: PropTypes.array,     // 鍗$墖琛屼俊鎭�
+    cols: PropTypes.array,      // 瀛楁闆�
+  }
+
+  state = {
+    data: [],
+    editMenu: null,
+    columns: [
+      { title: '鑿滃崟鍚嶇О', dataIndex: 'name', key: 'name' },
+      { title: '鑿滃崟鍙傛暟', dataIndex: 'MenuNo', key: 'MenuNo' },
+      { title: '鑿滃崟灞炴��', dataIndex: 'property', key: 'property',  render: text => {
+        const trans = {menu: '鑿滃崟', link: '閾炬帴', linkmenu: '鍏宠仈鑿滃崟'}
+
+        return trans[text]
+      }},
+      { title: '鍥炬爣', dataIndex: 'icon', key: 'icon',  render: (text, record) => {
+        return text ? <Icon type={text} /> : ''
+      }},
+      { title: '鏄惁闅愯棌', dataIndex: 'hidden', key: 'hidden',  render: (text, record) => {
+        const trans = {'true': '鏄�', 'false': '鍚�'}
+        return trans[text] || '鍚�'
+      }},
+      { title: '鎿嶄綔', key: 'operation', align: 'center', width: '190px', render: (text, record) =>
+        (<div>
+          <Button type="link" style={{padding: '0 5px', marginRight: '5px'}} onClick={() => this.editMenu(record)}>缂栬緫</Button>
+          <Button type="link" style={{color: '#ff4d4f', padding: '0 5px', marginRight: '5px'}} onClick={() => this.delMenu(record)}>鍒犻櫎</Button>
+          <Icon type="arrow-up" style={{color: '#26C281', cursor: 'pointer', padding: '0 5px', marginRight: '5px'}} onClick={() => this.moveUp(record)}/>
+          <Icon type="arrow-down" style={{color: '#ff4d4f', cursor: 'pointer', padding: '0 5px'}} onClick={() => this.moveDown(record)}/>
+        </div>)
+      }
+    ]
+  }
+
+  UNSAFE_componentWillMount () {
+    const { menus } = this.props
+
+    this.setState({data: fromJS(menus).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  moveUp = (record) => {
+    let data = fromJS(this.state.data).toJS()
+
+    let dragIndex = data.findIndex(c => c.MenuID === record.MenuID)
+    let hoverIndex = dragIndex - 1
+
+    if (hoverIndex === -1) return
+
+    data.splice(hoverIndex, 0, ...data.splice(dragIndex, 1))
+    this.setState({data})
+  }
+
+  moveDown = (record) => {
+    let data = fromJS(this.state.data).toJS()
+
+    let dragIndex = data.findIndex(c => c.MenuID === record.MenuID)
+    let hoverIndex = dragIndex + 1
+
+    if (hoverIndex === data.length) return
+
+    data.splice(hoverIndex, 0, ...data.splice(dragIndex, 1))
+    this.setState({data})
+  }
+
+  delMenu = (record) => {
+    const { data } = this.state
+    const _this = this
+
+    confirm({
+      title: '纭畾鍒犻櫎鍚楋紵',
+      content: '',
+      onOk() {
+        _this.setState({data: data.filter(item => item.MenuID !== record.MenuID)})
+      },
+      onCancel() {}
+    })
+  }
+
+  editMenu = (record) => {
+    this.setState({editMenu: record, visible: true})
+  }
+
+  plusMenu = () => {
+    let _menu = {
+      name: '鑿滃崟',
+      property: 'menu'
+    }
+
+    this.setState({editMenu: _menu, visible: true})
+  }
+
+  menuSubmit = () => {
+    const { editMenu, data } = this.state
+
+    this.menuRef.handleConfirm().then(res => {
+      let _menu = {...editMenu, ...res}
+      let _data = fromJS(data).toJS()
+
+      if (!_menu.MenuID) {
+        _menu.MenuID = Utils.getuuid()
+        _data.push(_menu)
+      } else {
+        _data = _data.map(item => {
+          if (item.MenuID === _menu.MenuID) {
+            return _menu
+          } else {
+            return item
+          }
+        })
+      }
+
+      if (editMenu.MenuID && editMenu.property === 'menu' && _menu.property !== 'menu') {
+        const _this = this
+        confirm({
+          content: '鑿滃崟灞炴�х敱鈥滆彍鍗曗�濆垏鎹㈣嚦鍏朵粬绫诲瀷鏃讹紝鑿滃崟灏嗚閲嶇疆锛屽嵆瑙i櫎涔嬪墠鑿滃崟鐨勭粦瀹氬叧绯伙紝纭畾淇敼鍚楋紵',
+          onOk() {
+            _data = _data.map(item => {
+              if (item.MenuID === _menu.MenuID) {
+                item.MenuID = Utils.getuuid()
+              }
+              return item
+            })
+            _this.setState({data: _data, editMenu: null, visible: false})
+          },
+          onCancel() {}
+        })
+      } else {
+        this.setState({data: _data, editMenu: null, visible: false})
+      }
+    })
+  }
+
+  menuUpdate = (res) => {
+    const { data } = this.state
+
+    this.setState({
+      data: data.map(item => {
+        if (item.MenuID === res.MenuID) {
+          return res
+        } else {
+          return item
+        }
+      })
+    })
+  }
+
+  render() {
+    const { cols } = this.props
+    const { columns, data, visible, editMenu } = this.state
+
+    return (
+      <div className="menu-control-wrap">
+        <Button className="menu-plus mk-green" onClick={this.plusMenu}>娣诲姞</Button>
+        <Table
+          rowKey="MenuID"
+          columns={columns}
+          dataSource={data}
+          pagination={false}
+        />
+        <Modal
+          title="缂栬緫"
+          visible={visible}
+          width={750}
+          maskClosable={false}
+          onOk={this.menuSubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <MenuForm
+            menu={editMenu}
+            cols={cols}
+            inputSubmit={this.menuSubmit}
+            wrappedComponentRef={(inst) => this.menuRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default MenuTable
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.scss b/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.scss
new file mode 100644
index 0000000..725a1d5
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/menusetting/menutable/index.scss
@@ -0,0 +1,23 @@
+.menu-control-wrap {
+  position: relative;
+
+  .menu-plus {
+    float: right;
+    position: relative;
+    z-index: 1;
+    margin-bottom: 5px;
+  }
+  .ant-empty {
+    margin: 5px 0;
+  }
+  thead tr {
+    background: #fbfbfb;
+  }
+  tbody > tr {
+    background: #ffffff;
+  }
+
+  .ant-table-body {
+    margin: 0!important;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx b/src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx
new file mode 100644
index 0000000..a6785d0
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx
@@ -0,0 +1,81 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="鑿滃崟鏍忚缃�"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/wrapsetting/index.scss b/src/mob/components/navbar/normal-navbar/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx b/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..debd0d8
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
@@ -0,0 +1,118 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, InputNumber, Tooltip, Icon, Radio } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {}
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { wrap } = this.props
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="瀵艰埅鏍忓悕绉�">
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀵艰埅鏍忓悕绉�!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鑿滃崟鍙傛暟">
+                {getFieldDecorator('MenuNo', {
+                  initialValue: wrap.MenuNo,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '鑿滃崟鍙傛暟!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨闈欐�佸�硷紝鏃犻渶閰嶇疆鏁版嵁婧愩��">
+                  <Icon type="question-circle" />
+                  鏁版嵁鏉ユ簮
+                </Tooltip>
+              }>
+                {getFieldDecorator('datatype', {
+                  initialValue: wrap.datatype || 'static'
+                })(
+                  <Radio.Group>
+                    <Radio value="dynamic">鍔ㄦ��</Radio>
+                    <Radio value="static">闈欐��</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="楂樺害">
+                {getFieldDecorator('height', {
+                  initialValue: wrap.height || 50,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '楂樺害!'
+                    }
+                  ]
+                })(<InputNumber min={30} max={200} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.scss b/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..159130b
--- /dev/null
+++ b/src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/topbar/normal-navbar/index.jsx b/src/mob/components/topbar/normal-navbar/index.jsx
new file mode 100644
index 0000000..db75aed
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/index.jsx
@@ -0,0 +1,195 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+
+import asyncIconComponent from '@/utils/asyncIconComponent'
+
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import './index.scss'
+
+const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
+
+class NormalNavbar extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        width: 24,
+        subtype: card.subtype,
+        wrap: { type: 'navbar', height: 50, title: 'NavBar', back: 'true', search: 'false', logout: 'false' },
+        style: {borderBottomColor: '#bcbcbc', borderBottomWidth: '1px', paddingLeft: '10px', paddingRight: '10px', lineHeight: '2.8', fontSize: '18px' },
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.style = config.style
+      }
+
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('submitSearch', this.getSearch)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+    MKEmitter.removeListener('submitSearch', this.getSearch)
+  }
+  
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    this.props.updateConfig(component)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['font', 'background', 'border', 'padding', 'shadow'], card.style)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  changeMenu = (menu) => {
+    if (menu.property === 'link') {
+      window.open(menu.link)
+    } else {
+      MKEmitter.emit('changeEditMenu', {
+        MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
+        copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
+        MenuNo: menu.MenuNo,
+        MenuName: menu.name,
+      })
+    }
+  }
+
+  getSearch = (config) => {
+    const { card } = this.state
+
+    if (card.uuid !== config.uuid) return
+
+    this.setState({
+      card: config
+    })
+    
+    this.props.updateConfig(config)
+  }
+
+  setSearch = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    if (!card.search) {
+      card.search = {
+        floor: 1,
+        setting: { type: 'title', field: '', title: '', focus: 'true', btn: 'hidden' },
+        groups: [],
+        fields: []
+      }
+    }
+    this.props.updateConfig(card)
+    MKEmitter.emit('changeSearch', card)
+  }
+
+  render() {
+    const { card } = this.state
+
+    let _style = {...card.style}
+    if (_style.shadow) {
+      _style.boxShadow = '0 0 4px ' + _style.shadow
+    }
+
+    return (
+      <div className="normal-topbar-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <div className="am-navbar">
+          <div className="am-navbar-left">
+            {card.wrap.back !== 'false' ? <Icon type="left" /> : null}
+          </div>
+          {card.wrap.type !== 'search' ?
+            <div className="am-navbar-title">{card.wrap.title || ''}</div> :
+            <div className="am-navbar-search" onDoubleClick={this.setSearch}><div className="search-bar"><Icon type="search" /></div></div>
+          }
+          <div className="am-navbar-right">
+            {card.wrap.search === 'true' ? <Icon type="search" onDoubleClick={this.setSearch}/> : null}
+            {card.wrap.logout === 'true' ? <Icon type="ellipsis" /> : null}
+          </div>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default NormalNavbar
\ No newline at end of file
diff --git a/src/mob/components/topbar/normal-navbar/index.scss b/src/mob/components/topbar/normal-navbar/index.scss
new file mode 100644
index 0000000..c7cd342
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/index.scss
@@ -0,0 +1,82 @@
+.normal-topbar-edit-box {
+  position: absolute;
+  top: 0px;
+  left: 0px;
+  width: 100%;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  height: 50px;
+  z-index: 3;
+  
+  .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);
+    color: rgba(0, 0, 0, 0.65);
+  }
+  .am-navbar {
+    height: 100%;
+    display: flex;
+    font-style: inherit;
+    font-weight: inherit;
+    .am-navbar-left {
+      width: 30px;
+      text-align: left;
+      color: #1890ff;
+      font-size: 20px;
+      line-height: 50px;
+    }
+    .am-navbar-title {
+      text-align: center;
+      font-style: inherit;
+      font-weight: inherit;
+      flex: 1;
+    }
+    .am-navbar-search {
+      flex: 1;
+      padding: 0 5px;
+      .search-bar {
+        height: 30px;
+        line-height: 30px;
+        padding: 0 10px;
+        color:rgba(0, 0, 0, 0.65);
+        border: 1px solid #E9EDF0;
+        background: #E9EDF0;
+        border-radius: 4px;
+        position: relative;
+        top: 50%;
+        transform: translateY(-50%);
+        cursor: pointer;
+        font-size: 18px;
+      }
+    }
+    .am-navbar-right {
+      text-align: right;
+      color: #1890ff;
+      min-width: 30px;
+      font-size: 20px;
+      line-height: 50px;
+      .anticon-search {
+        margin-right: 5px;
+        padding: 5px;
+        cursor: pointer;
+      }
+    }
+  }
+}
+.normal-topbar-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.normal-topbar-edit-box:hover {
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx b/src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx
new file mode 100644
index 0000000..77c0894
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx
@@ -0,0 +1,81 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="瀵艰埅鏍忚缃�"
+          visible={visible}
+          width={750}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/mob/components/topbar/normal-navbar/wrapsetting/index.scss b/src/mob/components/topbar/normal-navbar/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx b/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..7656c0e
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx
@@ -0,0 +1,130 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    type: this.props.wrap.type || 'navbar'
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { wrap } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { type } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label="绫诲瀷">
+                {getFieldDecorator('type', {
+                  initialValue: wrap.type || 'navbar'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({type: e.target.value})}>
+                    <Radio value="navbar">瀵艰埅鏍�</Radio>
+                    <Radio value="search">鎼滅储鏍�</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="浣跨敤鎼滅储鏍忔椂锛屾爣棰樼敤浜庢悳绱㈡潯浠堕殣钘忔椂鏄剧ず銆�">
+                  <Icon type="question-circle" />
+                  鏍囬
+                </Tooltip>
+              }>
+                {getFieldDecorator('title', {
+                  initialValue: wrap.title || ''
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="杩斿洖">
+                {getFieldDecorator('back', {
+                  initialValue: wrap.back || 'true'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {type === 'navbar' ? <Col span={12}>
+              <Form.Item label="鎼滅储">
+                {getFieldDecorator('search', {
+                  initialValue: wrap.search || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐐瑰嚮閫�鍑烘椂锛岃繑鍥炵涓�涓〉闈€��">
+                  <Icon type="question-circle" />
+                  閫�鍑�
+                </Tooltip>
+              }>
+                {getFieldDecorator('logout', {
+                  initialValue: wrap.logout || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鏄剧ず</Radio>
+                    <Radio value="false">闅愯棌</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.scss b/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..159130b
--- /dev/null
+++ b/src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/header/index.jsx b/src/mob/header/index.jsx
index 38c5863..5bf90ea 100644
--- a/src/mob/header/index.jsx
+++ b/src/mob/header/index.jsx
@@ -1,4 +1,5 @@
 import React, {Component} from 'react'
+import { Radio } from 'antd'
 
 import avatar from '@/assets/img/avatar.jpg'
 import MainLogo from '@/assets/img/main-logo.png'
@@ -7,13 +8,26 @@
 class MobHeader extends Component {
   state = {
     avatar: sessionStorage.getItem('CloudAvatar') || avatar,
-    userName: sessionStorage.getItem('CloudUserName')
+    userName: sessionStorage.getItem('CloudUserName'),
+    typename: sessionStorage.getItem('typename')
+  }
+
+  changeView = (e) => {
+    let val = e.target.value
+    this.props.changeView(val)
   }
 
   render () {
+    const { typename } = this.state
     return (
       <header className="mob-header-container">
         <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        {typename === 'pad' ? <div className="change-view">
+          <Radio.Group defaultValue="vertical" onChange={this.changeView}>
+            <Radio value="vertical">绔栧睆</Radio>
+            <Radio value="horizontal">妯睆</Radio>
+          </Radio.Group>
+        </div> : null}
         <div className="header-user">
           <img src={this.state.avatar} alt=""/>
           <span>
diff --git a/src/mob/header/index.scss b/src/mob/header/index.scss
index 40ac737..b4009e2 100644
--- a/src/mob/header/index.scss
+++ b/src/mob/header/index.scss
@@ -45,4 +45,12 @@
       }
     }
   }
+  .change-view {
+    position: absolute;
+    left: calc(50% - 70px);
+    top: 12px;
+    .ant-radio-wrapper {
+      color: #ffffff;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/mob/home/index.jsx b/src/mob/home/index.jsx
deleted file mode 100644
index dde5d1f..0000000
--- a/src/mob/home/index.jsx
+++ /dev/null
@@ -1,126 +0,0 @@
-import React, {Component} from 'react'
-// import PropTypes from 'prop-types'
-import { is, fromJS } from 'immutable'
-import { Flex, WhiteSpace, Tabs } from 'antd-mobile'
-
-import zhCN from '@/locales/zh-CN/mob.js'
-import enUS from '@/locales/en-US/mob.js'
-import './index.scss'
-
-const PlaceHolder = ({ className = '', children = ''}) => (
-  <div className={`${className} placeholder`}>{children ? children : 'Block'}</div>
-)
-
-const tabs2 = [
-  { title: '绠�浠�', sub: '1' },
-  { title: '宸ヤ綔鍙�', sub: '2' },
-  { title: '涓汉涓績', sub: '3' },
-]
-
-class MobHome extends Component {
-  // static propTpyes = {
-  //   collapse: PropTypes.bool,
-  // }
-  state = {
-    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-  }
-
-  shouldComponentUpdate (nextProps, nextState) {
-    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
-  }
-
-  render () {
-
-    return (
-      <div className="mob-home">
-        <Tabs tabs={tabs2}
-          initialPage={1}
-          tabBarPosition="bottom"
-          renderTab={tab => <span>{tab.title}</span>}
-        >
-          <div className="home-tab">
-            <div className="flex-container">
-              <div className="sub-title">Basic</div>
-              <Flex>
-                <Flex.Item><PlaceHolder ><span> test</span></PlaceHolder></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-              </Flex>
-              <WhiteSpace size="lg" />
-              <Flex>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-              </Flex>
-              <WhiteSpace size="lg" />
-              <Flex>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-                <Flex.Item><PlaceHolder /></Flex.Item>
-              </Flex>
-              <WhiteSpace size="lg" />
-
-              <div className="sub-title">Wrap</div>
-              <Flex wrap="wrap">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-              </Flex>
-              <WhiteSpace size="lg" />
-
-              <div className="sub-title">Align</div>
-              <Flex justify="center">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-              </Flex>
-              <WhiteSpace />
-              <Flex justify="end">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-              </Flex>
-              <WhiteSpace />
-              <Flex justify="between">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline" />
-              </Flex>
-
-              <WhiteSpace />
-              <Flex align="start">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline small" />
-                <PlaceHolder className="inline" />
-              </Flex>
-              <WhiteSpace />
-              <Flex align="end">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline small" />
-                <PlaceHolder className="inline" />
-              </Flex>
-              <WhiteSpace />
-              <Flex align="baseline">
-                <PlaceHolder className="inline" />
-                <PlaceHolder className="inline small" />
-                <PlaceHolder className="inline" />
-              </Flex>
-            </div>
-          </div>
-          <div className="home-tab">
-            Content of second tab
-          </div>
-          <div className="home-tab">
-            Content of third tab
-          </div>
-        </Tabs>
-      </div>
-    )
-  }
-}
-
-export default MobHome
\ No newline at end of file
diff --git a/src/mob/home/index.scss b/src/mob/home/index.scss
deleted file mode 100644
index 9b2141a..0000000
--- a/src/mob/home/index.scss
+++ /dev/null
@@ -1,38 +0,0 @@
-.mob-home {
-  width: 100%;
-  height: 100%;
-  overflow: hidden;
-  > .am-tabs {
-    > .am-tabs-tab-bar-wrap {
-      .am-tabs-default-bar-underline {
-        display: none;
-      }
-      .am-tabs-default-bar-tab {
-        cursor: pointer;
-      }
-    }
-    > .am-tabs-content-wrap {
-      > .am-tabs-pane-wrap {
-        .home-tab {
-          display: flex;
-          align-items: center;
-          justify-content: center;
-        }
-      }
-      > .am-tabs-pane-wrap::-webkit-scrollbar {
-        width: 4px;
-      }
-      > .am-tabs-pane-wrap::-webkit-scrollbar-thumb {
-        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-        background: rgba(0, 0, 0, 0.13);
-        border-radius: 5px;
-      }
-      > .am-tabs-pane-wrap::-webkit-scrollbar-track {
-        box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
-        border: 1px solid rgba(0, 0, 0, 0.07);
-        background: rgba(0, 0, 0, 0);
-        border-radius: 3px;
-      }
-    }
-  }
-}
\ No newline at end of file
diff --git a/src/mob/mobshell/card.jsx b/src/mob/mobshell/card.jsx
index 30225a7..9cd7402 100644
--- a/src/mob/mobshell/card.jsx
+++ b/src/mob/mobshell/card.jsx
@@ -5,8 +5,10 @@
 import './index.scss'
 
 const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
-const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
+// const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
+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 PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
@@ -17,6 +19,12 @@
 const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
+const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
+const NormalLogin = asyncComponent(() => import('@/pc/components/login/normal-login'))
+const NormalNavbar = asyncComponent(() => import('@/mob/components/navbar/normal-navbar'))
+const NormalTopbar = asyncComponent(() => import('@/mob/components/topbar/normal-navbar'))
+const NormalMenuBar = asyncComponent(() => import('@/mob/components/menubar/normal-menubar'))
+const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -51,13 +59,34 @@
     style = { opacity: 0.3}
   }
 
+  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'
+      })
+    }
+    
+    style.minHeight = height
+  }
+
   const getCardComponent = () => {
     if (card.type === 'bar' || card.type === 'line') {
       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 === 'search') {
+    //   return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'dashboard') {
+      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'scatter') {
+      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'form') {
       return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'tabs') {
@@ -78,12 +107,29 @@
       return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'editor') {
+      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'login') {
+      return (<NormalLogin card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'navbar') {
+      return (<NormalNavbar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'topbar') {
+      return (<NormalTopbar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'menubar') {
+      return (<NormalMenuBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
-  return (
-    <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}>
-      {getCardComponent()}
-    </div>
-  )
+
+  if (card.type === 'navbar' || card.type === 'topbar') {
+    return getCardComponent()
+  } else {
+    return (
+      <div className={'ant-col mk-component-card ' + col} ref={node => drag(drop(node))} style={style}>
+        {getCardComponent()}
+      </div>
+    )
+  }
 }
 export default Card
diff --git a/src/mob/mobshell/index.jsx b/src/mob/mobshell/index.jsx
index ee23621..5cdb407 100644
--- a/src/mob/mobshell/index.jsx
+++ b/src/mob/mobshell/index.jsx
@@ -19,6 +19,10 @@
     handleList({...menu, components: _cards})
     setCards(_cards)
   }
+
+  if (menu.components.length > cards.length) {
+    setCards(menu.components)
+  }
   
   const findCard = id => {
     const card = cards.filter(c => `${c.uuid}` === id)[0]
@@ -49,13 +53,16 @@
     let uuids = MenuUtils.getDelButtonIds(card)
 
     confirm({
-      title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
+      title: `纭畾鍒犻櫎${card.name ? `銆�${card.name}銆媊 : '缁勪欢'}鍚楋紵`,
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
-        MKEmitter.emit('delButtons', uuids)
         const _cards = cards.filter(item => item.uuid !== card.uuid)
         handleList({...menu, components: _cards})
         setCards(_cards)
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -78,6 +85,24 @@
           })
           return
         }
+      } else if (item.component === 'navbar') {
+        if (cards.filter(card => card.type === 'navbar').length > 0) {
+          notification.warning({
+            top: 92,
+            message: '鑿滃崟鏍忎笉鍙噸澶嶆坊鍔狅紒',
+            duration: 5
+          })
+          return
+        }
+      } else if (item.component === 'topbar') {
+        if (cards.filter(card => card.type === 'topbar').length > 0) {
+          notification.warning({
+            top: 92,
+            message: '瀵艰埅鏍忎笉鍙噸澶嶆坊鍔狅紒',
+            duration: 5
+          })
+          return
+        }
       }
 
       let name = ''
@@ -92,8 +117,12 @@
         editor: '瀵屾枃鏈�',
         code: '鑷畾涔�',
         carousel: '杞挱',
+        dashboard: '浠〃鐩�',
         form: '琛ㄥ崟',
-        card: '鍗$墖'
+        card: '鍗$墖',
+        navbar: '瀵艰埅鏍�',
+        menubar: '鑿滃崟鏍�',
+        login: '鐧诲綍'
       }
       let i = 1
       
@@ -127,7 +156,25 @@
       }
 
       const { index: overIndex } = findCard(`${targetId}`)
-      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
+      let _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
+      let Topbar = null
+      let Navbar = null
+      _cards = _cards.filter(item => {
+        if (item.type === 'topbar') {
+          Topbar = item
+        } else if (item.type === 'navbar') {
+          Navbar = item
+        }
+
+        return item.type !== 'topbar' && item.type !== 'navbar'
+      })
+
+      if (Topbar) {
+        _cards.unshift(Topbar)
+      }
+      if (Navbar) {
+        _cards.push(Navbar)
+      }
 
       handleList({...menu, components: _cards})
       setCards(_cards)
@@ -135,8 +182,8 @@
   })
 
   return (
-    <div ref={drop} className="mob-shell-inner" id="menu-shell-inner" style={menu.style}>
-      <div className="ant-row">
+    <div ref={drop} className="mob-shell-inner" id="menu-shell-inner">
+      <div className="ant-row" style={menu.style}>
         {cards.map(card => (
           <Card
             id={card.uuid}
@@ -148,10 +195,10 @@
             updateConfig={updateConfig}
           />
         ))}
+        {cards.length === 0 ?
+          <Empty description="璇锋坊鍔犵粍浠�" /> : null
+        }
       </div>
-      {cards.length === 0 ?
-        <Empty description="璇锋坊鍔犵粍浠�" /> : null
-      }
     </div>
   )
 }
diff --git a/src/mob/mobshell/index.scss b/src/mob/mobshell/index.scss
index 55dd022..cd21f50 100644
--- a/src/mob/mobshell/index.scss
+++ b/src/mob/mobshell/index.scss
@@ -1,8 +1,34 @@
 .mob-shell-inner {
+  // scaleview
+  width: 120%;
+  height: 120%;
+  overflow-y: auto;
+  overflow-x: hidden;
+  background: #ffffff;
+  box-shadow: 0px 0px 2px #000000;
+  transform: scale(0.8333333333333334, 0.8333333333333334);
+  transform-origin: left top;
   .mk-component-card {
     position: relative;
   }
-  >.ant-empty {
-    padding-top: 150px;
+  >.ant-row {
+    min-height: 100%;
+    >.ant-empty {
+      padding-top: 150px;
+    }
   }
+}
+.mob-shell-inner::-webkit-scrollbar {
+  width: 2px;
+}
+.mob-shell-inner::-webkit-scrollbar-thumb {
+  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+  background: rgba(0, 0, 0, 0.23);
+  border-radius: 5px;
+}
+.mob-shell-inner::-webkit-scrollbar-track {
+  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+  border: 1px solid rgba(0, 0, 0, 0.07);
+  background: rgba(0, 0, 0, 0);
+  border-radius: 3px;
 }
\ No newline at end of file
diff --git a/src/mob/modalconfig/controller.jsx b/src/mob/modalconfig/controller.jsx
new file mode 100644
index 0000000..efd36d6
--- /dev/null
+++ b/src/mob/modalconfig/controller.jsx
@@ -0,0 +1,64 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+
+import MKEmitter from '@/utils/events.js'
+import ModalConfig from '@/mob/modalconfig'
+
+class ModalController extends Component {
+  state = {
+    btn: null,
+    config: null,
+    visible: false
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('changeModal', this.initConfig)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('changeModal', this.initConfig)
+  }
+
+  initConfig = (config, btn) => {
+    this.setState({
+      visible: true,
+      config: fromJS(config).toJS(),
+      btn: fromJS(btn).toJS()
+    })
+  }
+
+  handleBack = () => {
+    this.setState({
+      visible: false,
+      config: null,
+      btn: null
+    })
+  }
+  
+  handleSave = (modal) => {
+    const { config, btn } = this.state
+    MKEmitter.emit('submitModal', config, btn, modal)
+  }
+
+  render () {
+    const { config, btn, visible } = this.state
+
+    if (!visible) return null
+
+    return (
+      <ModalConfig btn={btn} componentConfig={config} handleBack={this.handleBack} handleSave={this.handleSave}/>
+    )
+  }
+}
+
+export default ModalController
\ No newline at end of file
diff --git a/src/mob/modalconfig/index.jsx b/src/mob/modalconfig/index.jsx
new file mode 100644
index 0000000..fc634fd
--- /dev/null
+++ b/src/mob/modalconfig/index.jsx
@@ -0,0 +1,466 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { DndProvider } from 'react-dnd'
+import HTML5Backend from 'react-dnd-html5-backend'
+import moment from 'moment'
+import { Button, Modal, Collapse, notification, Switch, Icon } from 'antd'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getModalForm } from '@/templates/zshare/formconfig'
+
+import SourceElement from '@/templates/modalconfig/dragelement/source'
+import SettingForm from '@/templates/modalconfig/settingform'
+import asyncComponent from '@/utils/asyncComponent'
+import { SearchItems } from './source'
+import './index.scss'
+
+const { Panel } = Collapse
+const { confirm } = Modal
+const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+const PasteComponent = asyncComponent(() => import('./pastecomponent'))
+const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
+const DragElement = asyncComponent(() => import('@/mob/components/formdragelement'))
+const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
+
+class ComModalConfig extends Component {
+  static propTpyes = {
+    btn: PropTypes.object,
+    handleSave: PropTypes.func,
+    handleBack: PropTypes.func
+  }
+
+  state = {
+    dict: CommonDict,      // 瀛楀吀
+    config: null,          // 椤甸潰閰嶇疆锛屽寘鎷ā鏉跨被鍨嬨�佹ā鎬佹璁剧疆銆佹坊鍔犺〃鍚嶃�佽〃鍗曞垪琛�
+    visible: false,        // 琛ㄥ崟缂栬緫妯℃�佹锛屾樉绀烘帶鍒�
+    formlist: null,        // 琛ㄥ崟缂栬緫妯℃�佹锛屽彲缂栬緫瀛楁
+    card: null,            // 缂栬緫鍏冪礌
+    settingVisible: false, // 鍏ㄥ眬閰嶇疆妯℃�佹
+    originConfig: null,    // 鍘熷鑿滃崟
+    sqlVerifing: false,    // sql楠岃瘉
+    showField: false,      // 鏄剧ず琛ㄥ崟瀛楁鍊�
+    standardform: null
+  }
+
+  /**
+   * @description 鏁版嵁棰勫鐞�
+   */
+  UNSAFE_componentWillMount () {
+    const { btn } = this.props
+
+    let _config = btn.modal
+    _config.version = '1.0'
+
+    this.setState({
+      config: _config,
+      originConfig: fromJS(_config).toJS()
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  /**
+   * @description 琛ㄥ崟鍙樺寲
+   * 1銆佽〃鍗曟嫋鎷芥坊鍔犳椂锛屾鏌ユ槸鍚﹀瓨鍦ㄧず渚嬭〃鍗曪紝濡傚瓨鍦ㄥ垯鍘婚櫎绀轰緥
+   * 2銆佽〃鍗曠Щ鍔ㄥ悗锛屼繚瀛樼Щ鍔ㄥ悗鐨勯『搴�
+   * 3銆佹柊澧炶〃鍗曟椂锛岀洿鎺ユ墦寮�缂栬緫妗�
+   */
+  handleList = (list, newcard) => {
+    let _config = fromJS(this.state.config).toJS()
+
+    if (list.length > _config.fields.length) {
+      _config.fields = list.filter(item => !item.origin)
+
+      this.setState({
+        config: _config
+      }, () => {
+        this.handleForm(newcard)
+      })
+    } else {
+      _config.fields = list
+      this.setState({config: _config})
+    }
+  }
+
+  /**
+   * @description 琛ㄥ崟缂栬緫
+   * 1銆佹樉绀虹紪杈戝脊绐�-visible
+   * 2銆佷繚瀛樼紪杈戦」-card
+   * 3銆佽缃紪杈戝弬鏁伴」-formlist
+   */
+  handleForm = (_card) => {
+    const { componentConfig } = this.props
+    const { config } = this.state
+    let card = fromJS(_card).toJS()
+    let _inputfields = []
+    let _tabfields = []
+    let _linkableFields = []
+    let _linksupFields = [{
+      value: '',
+      text: '绌�'
+    }]
+    let standardform = null
+
+    _inputfields = config.fields.filter(item => item.type === 'text' || item.type === 'number' || item.type === 'textarea' || item.type === 'color')
+    _tabfields = config.fields.filter(item => card.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
+    _tabfields.unshift({field: '', text: '鍘熻〃鍗�'})
+
+    let uniq = new Map()
+    uniq.set(card.field, true)
+    let index = null
+    config.fields.forEach((item, i) => {
+      if (card.uuid === item.uuid) {
+        index = i
+      }
+      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
+      if (item.field && !uniq.has(item.field)) {
+        uniq.set(item.field, true)
+
+        _linkableFields.push({
+          value: item.field,
+          text: item.label + ' (琛ㄥ崟)'
+        })
+        _linksupFields.push({
+          value: item.field,
+          text: item.label
+        })
+      }
+    })
+    if (index !== null) {
+      if (index === 0) {
+        standardform = config.fields[index + 1] || null
+      } else {
+        standardform = config.fields[index - 1] || null
+      }
+    }
+
+    componentConfig.columns.forEach(col => {
+      if (col.field && !uniq.has(col.field)) {
+        uniq.set(col.field, true)
+
+        _linkableFields.push({
+          value: col.field,
+          text: col.label + ' (鏄剧ず鍒�)'
+        })
+      }
+    })
+
+    if (card.linkSubField && card.linkSubField.length > 0) {
+      let fields = _inputfields.map(item => item.field)
+      card.linkSubField = card.linkSubField.filter(item => fields.includes(item))
+    }
+
+    if (!card.span && standardform && standardform.span) {
+      card.span = standardform.span
+      card.labelwidth = standardform.labelwidth
+    }
+
+    this.setState({
+      standardform,
+      visible: true,
+      card: card,
+      formlist: getModalForm(card, _inputfields, _tabfields, _linkableFields, _linksupFields, !!this.props.editTab)
+    })
+  }
+
+  /**
+   * @description 缂栬緫鍚庢彁浜�
+   * 1銆佽幏鍙栫紪杈戝悗鐨勮〃鍗曚俊鎭�
+   * 2銆佸幓闄ゅ彲鑳藉瓨鍦ㄧ殑绀轰緥琛ㄥ崟
+   * 3銆侀�氳繃loading鍒锋柊
+   */
+  handleSubmit = () => {
+    this.formRef.handleConfirm().then(res => {
+      let _config = fromJS(this.state.config).toJS()
+      let fieldrepet = false // 瀛楁閲嶅
+      let labelrepet = false // 鎻愮ず鏂囧瓧閲嶅
+
+      _config.fields = _config.fields.map(item => {
+        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
+          fieldrepet = true
+        } else if (res.label && item.uuid !== res.uuid && item.label === res.label) {
+          labelrepet = true
+        }
+
+        if (item.uuid === res.uuid) {
+          return res
+        } else {
+          return item
+        }
+      })
+
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁宸插瓨鍦紒',
+          duration: 10
+        })
+        return
+      } else if (labelrepet) {
+        notification.warning({
+          top: 92,
+          message: '鍚嶇О宸插瓨鍦紒',
+          duration: 10
+        })
+        return
+      }
+
+      _config.fields = _config.fields.filter(item => !item.origin)
+
+      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+        this.setState({
+          sqlVerifing: true
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          exec_type: 'y',
+          LText: res.dataSource
+        }
+
+        param.LText = param.LText.replace(/@\$|\$@/ig, '')
+        
+        param.LText = Utils.formatOptions(param.LText)
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+        param.secretkey = Utils.encrypt('', param.timestamp)
+
+        if (window.GLOB.mainSystemApi && res.database === 'sso') {
+          param.rduri = window.GLOB.mainSystemApi
+        }
+        
+        Api.getLocalConfig(param).then(result => {
+          if (result.status) {
+            this.setState({
+              sqlVerifing: false,
+              config: _config,
+              card: null,
+              visible: false
+            })
+          } else {
+            this.setState({sqlVerifing: false})
+            
+            Modal.error({
+              title: result.message
+            })
+          }
+        })
+      } else {
+        this.setState({
+          config: _config,
+          card: null,
+          visible: false
+        })
+      }
+    })
+  }
+
+  /**
+   * @description 琛ㄥ崟鍒犻櫎骞跺埛鏂�
+   */
+  closeForm = (card) => {
+    let _this = this
+
+    confirm({
+      content: `纭畾鍒犻櫎${card.label ? `<<${card.label}>>` : ''}鍚楋紵`,
+      onOk() {
+        let _config = fromJS(_this.state.config).toJS()
+        _config.fields = _config.fields.filter(item => !(item.uuid === card.uuid))
+
+        _this.setState({
+          config: _config,
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  submitConfig = () => {
+    const { config } = this.state
+
+    this.setState({originConfig: fromJS(config).toJS()})
+    this.props.handleSave(config)
+    notification.success({
+      top: 92,
+      message: '淇濆瓨鎴愬姛銆�',
+      duration: 2
+    })
+  }
+
+  cancelConfig = () => {
+    const { config, originConfig } = this.state
+
+    if (!is(fromJS(config), fromJS(originConfig))) {
+      let _this = this
+      confirm({
+        content: '閰嶇疆淇℃伅鏈繚瀛橈紝纭畾杩斿洖鍚楋紵',
+        onOk() {
+          _this.props.handleBack()
+        },
+        onCancel() {}
+      })
+    } else {
+      this.props.handleBack()
+    }
+  }
+
+  /**
+   * @description 鍏ㄥ眬璁剧疆妯℃�佹
+   */
+  changeSetting = () => {
+    this.setState({
+      settingVisible: true
+    })
+  }
+
+  /**
+   * @description 淇濆瓨鍏ㄥ眬璁剧疆
+   */
+  settingSave = () => {
+    const {config} = this.state
+    this.settingRef.handleConfirm().then(res => {
+      this.setState({
+        config: {...config, setting: res},
+        settingVisible: false
+      })
+    })
+  }
+
+  editModalCancel = () => {
+    const { config, card } = this.state
+
+    if (card.focus) {
+      let _fields = config.fields.filter(item => item.uuid !== card.uuid)
+      let _config = {...config, fields: _fields}
+
+      this.setState({
+        card: null,
+        config: _config,
+        visible: false
+      })
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  /**
+   * @description 鏇存柊
+   */
+  updateConfig = (config) => {
+    this.setState({
+      config
+    })
+  }
+
+  insert = (config) => {
+    this.setState({
+      config
+    }, () => {
+      this.handleForm(config.fields[config.fields.length - 1])
+    })
+  }
+
+  render () {
+    const { config, dict } = this.state
+
+    return (
+      <div className="mob-form-board">
+        <DndProvider backend={HTML5Backend}>
+          <div className="tools">
+            <Collapse accordion defaultActiveKey="1" bordered={false}>
+              <Panel header={dict['header.menu.form']} key="1">
+                <div className="search-element">
+                  {SearchItems.map((item, index) => {
+                    return (<SourceElement key={index} content={item}/>)
+                  })}
+                </div>
+                <FieldsComponent
+                  config={config}
+                  type="form"
+                  updatefield={this.updateConfig}
+                />
+              </Panel>
+            </Collapse>
+          </div>
+          <div className="modal-control">
+            <Button icon="setting" onClick={this.changeSetting}>璁剧疆</Button>
+            <Button type="primary" onClick={this.submitConfig}>淇濆瓨</Button>
+            <Button onClick={this.cancelConfig}>杩斿洖</Button>
+            <PasteComponent config={config} updateConfig={this.insert} />
+            <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
+          </div>
+          <div className="setting">
+            <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
+              <div className="mob-shell-inner">
+                <div className="am-navbar">
+                  <Icon type="close" />
+                  <div className="am-navbar-title">{config.setting.title}</div>
+                </div>
+                <DragElement
+                  list={config.fields}
+                  setting={config.setting}
+                  showField={this.state.showField}
+                  placeholder={this.state.dict['header.form.modal.placeholder']}
+                  handleList={this.handleList}
+                  handleForm={this.handleForm}
+                  closeForm={this.closeForm}
+                />
+                <Button className="modal-submit" type="primary">纭畾</Button>
+              </div>
+            </div>
+          </div>
+        </DndProvider>
+        <Modal
+          title={this.state.dict['model.edit']}
+          visible={this.state.visible}
+          width={850}
+          onCancel={this.editModalCancel}
+          onOk={this.handleSubmit}
+          confirmLoading={this.state.sqlVerifing}
+          destroyOnClose
+        >
+          <ModalForm
+            dict={this.state.dict}
+            card={this.state.card}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            standardform={this.state.standardform}
+            wrappedComponentRef={(inst) => this.formRef = inst}
+          />
+        </Modal>
+        <Modal
+          title={this.state.dict['model.edit']}
+          visible={this.state.settingVisible}
+          width={850}
+          maskClosable={false}
+          onOk={this.settingSave}
+          onCancel={() => { this.setState({ settingVisible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            config={config}
+            dict={this.state.dict}
+            isSubTab={!!this.props.editTab}
+            inputSubmit={this.settingSave}
+            wrappedComponentRef={(inst) => this.settingRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ComModalConfig
\ No newline at end of file
diff --git a/src/mob/modalconfig/index.scss b/src/mob/modalconfig/index.scss
new file mode 100644
index 0000000..02bdd82
--- /dev/null
+++ b/src/mob/modalconfig/index.scss
@@ -0,0 +1,321 @@
+.mob-form-board {
+  position: fixed;
+  z-index: 1070;
+  top: 48px;
+  left: 0px;
+  right: 0px;
+  bottom: 0px;
+  background: rgba(0, 0, 0, 1);
+  .tools {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    width: 235px;
+    background: #ffffff;
+    border-right: 1px solid #d9d9d9;
+    height: 100%;
+    overflow-y: auto;
+    padding-bottom: 30px;
+    .ant-collapse-borderless {
+      background-color: #ffffff;
+    }
+    .ant-collapse-item {
+      border: 0;
+    }
+    .ant-input-search {
+      margin-top: 10px;
+    }
+    .ant-collapse-item.ant-collapse-item-active {
+      border-bottom: 1px solid #d9d9d9;
+    }
+    .ant-collapse .ant-collapse-header {
+      padding: 11px 16px 10px 40px;
+      border-bottom: 1px solid #d9d9d9;
+      background: #1890ff;
+      color: #ffffff;
+    }
+    .ant-collapse-content-box {
+      .ant-form-item {
+        margin-bottom: 10px;
+        .ant-form-item-label {
+          text-align: left;
+          height: 25px;
+          line-height: 25px;
+        }
+      }
+      .ant-btn {
+        margin-bottom: 10px;
+      }
+    }
+    .search-element {
+      padding-top: 10px;
+      li {
+        padding: 0px 16px 10px;
+        div {
+          cursor: move;
+        }
+      }
+    }
+    .tables {
+      .ant-select-selection-selected-value {
+        opacity: 0.4!important;
+      }
+    }
+    .ant-list {
+      margin-top: 20px;
+      .ant-list-item {
+        display: -webkit-box;
+        padding-right: 20px;
+        position: relative;
+        padding-left: 5px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        -webkit-line-clamp: 2;
+        -webkit-box-orient: vertical;
+        width: 100%;
+        .anticon {
+          position: absolute;
+          top: 0px;
+          right: 0px;
+          padding: 3px 3px 10px 10px;
+          cursor: pointer;
+        }
+        .bottom-mask {
+          position: absolute;
+          width: 100%;
+          height: 8px;
+          bottom: 0;
+          left: 0;
+          background: #ffffff;
+          border-radius: 8px;
+        }
+      }
+    }
+  }
+  .tools::-webkit-scrollbar {
+    width: 4px;
+  }
+  .tools::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+    background: rgba(0, 0, 0, 0.08);
+  }
+  .tools::-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);
+  }
+  .modal-control {
+    position: absolute;
+    right: 0;
+    top: 0;
+    width: 120px;
+    height: 100vh;
+    padding: 20px 10px;
+    background: #ffffff;
+    z-index: 10;
+    transition: right 0.3s;
+
+    div:not(.draw), button:not(.ant-switch) {
+      display: block!important;
+      margin-bottom: 15px;
+      width: 100%;
+    }
+    .ant-switch.big {
+      min-width: 60px;
+      height: 24px;
+      line-height: 24px;
+      margin-bottom: 15px;
+      .ant-switch-inner {
+        font-size: 14px;
+      }
+    }
+    .ant-switch.big:after {
+      width: 22px;
+      height: 22px;
+    }
+  }
+  .setting {
+    position: relative;
+    width: 100vw;
+    height: 100%;
+    background: #959595;
+    
+    .mob-shell {
+      margin: 0 auto;
+      background: #000000;
+      background-size: 100% 100%;
+      padding: 25px 13px 40px;
+      border-radius: 30px;
+
+      .am-navbar {
+        height: 45px;
+        line-height: 45px;
+        position: relative;
+        border-bottom: 1px solid #f0f0f0;
+        margin-bottom: 10px;
+        .anticon-close {
+          position: absolute;
+          line-height: 45px;
+          font-size: 18px;
+          right: 10px;
+        }
+        .am-navbar-title {
+          font-size: 16px;
+          text-align: center;
+        }
+      }
+      .modal-submit {
+        width: 100%;
+        border-radius: 0;
+        opacity: 0.5;
+        cursor: default;
+        font-size: 18px;
+        height: 40px;
+      }
+
+      .modal-fields-row {
+        min-height: calc(100% - 95px);
+        padding: 0 10px 35px;
+      }
+
+      .modal-form {
+        padding: 0px 24px;
+        min-height: 87px;
+        .group-title {
+          position: relative;
+          min-height: 22px;
+          margin-bottom: 10px;
+          padding-top: 10px;
+          border-bottom: 1px solid #e8e8e8;
+
+          span {
+            padding: 0 5px 5px;
+          }
+        }
+        > .ant-row {
+          min-height: 120px;
+        }
+        .ant-row .ant-col-6 {
+          padding: 0 12px!important;
+        }
+        .ant-row.ant-form-item .ant-col {
+          padding: 0;
+        }
+        .textarea2, .textarea4 {
+          padding-left: 7px;
+        }
+        .page-card {
+          position: relative;
+          background: #ffffff;
+          border-radius: 2px;
+          margin-bottom: 15px;
+          .ant-form-item {
+            cursor: move;
+            display: flex;
+            margin-bottom: 0px;
+            .ant-form-item-label {
+              overflow: visible;
+              position: relative;
+              height: 40px;
+              label {
+                width: 100%;
+                cursor: move;
+                overflow: hidden;
+                display: inline-block;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+              }
+            }
+            .ant-form-item-control-wrapper {
+              position: relative;
+              .ant-select {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .ant-calendar-picker {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .ant-input-number {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .normal-braft-editor {
+                border: 1px solid #d9d9d9;
+                border-radius: 4px;
+              }
+            }
+            .ant-form-item-control-wrapper::after {
+              content: '';
+              position: absolute;
+              top: 0;
+              left: 0;
+              right: 0;
+              bottom: 0;
+              opacity: 0;
+              z-index: 1;
+            }
+            .ant-col-cuslabel {
+              width: 10.5%;
+            }
+            .ant-col-cuswrap {
+              width: 89.5%;
+            }
+          }
+        }
+        .ant-calendar-picker {
+          min-width: 100px!important;
+        }
+      }
+    }
+  }
+  .setting {
+    overflow-y: auto;
+  }
+  .setting::-webkit-scrollbar {
+    width: 7px;
+  }
+  .setting::-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);
+  }
+  .setting::-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);
+  }
+}
+
+
+.modal-fields {
+  .ant-modal {
+    top: 50px;
+    padding-bottom: 5px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      .ant-empty {
+        margin: 15vh 8px;
+      }
+    }
+    .ant-modal-body::-webkit-scrollbar {
+      width: 7px;
+    }
+    .ant-modal-body::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.13);
+    }
+    .ant-modal-body::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+      border-radius: 3px;
+      border: 1px solid rgba(0, 0, 0, 0.07);
+      background: rgba(0, 0, 0, 0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/mob/modalconfig/pastecomponent/index.jsx b/src/mob/modalconfig/pastecomponent/index.jsx
new file mode 100644
index 0000000..03b2200
--- /dev/null
+++ b/src/mob/modalconfig/pastecomponent/index.jsx
@@ -0,0 +1,76 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Button, Modal, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
+
+class PasteController extends Component {
+  static propTpyes = {
+    config: PropTypes.object,        // 缁勪欢閰嶇疆
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false
+  }
+
+  pasteSubmit = () => {
+    const { config } = this.props
+    this.pasteFormRef.handleConfirm().then(res => {
+      if (res.copyType !== 'form') {
+        notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
+        return
+      }
+
+      let keys = config.fields.map(item => item.field ? item.field.toLowerCase() : '$emp_ty$')
+
+      if (['multiselect', 'color', 'brafteditor'].includes(res.type)) {
+        res.type = 'text'
+      }
+
+      if (res.field && keys.includes(res.field.toLowerCase())) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁宸插瓨鍦紒',
+          duration: 5
+        })
+        return
+      }
+
+      this.props.updateConfig({...config, fields: [...config.fields, res]})
+      this.setState({visible: false})
+
+      notification.success({
+        top: 92,
+        message: '绮樿创鎴愬姛锛�',
+        duration: 2
+      })
+    })
+  }
+
+  render() {
+    const { visible } = this.state
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Button icon="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} >绮樿创</Button>
+        <Modal
+          title="绮樿创"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.pasteSubmit}
+          onCancel={() => {this.setState({visible: false})}}
+          destroyOnClose
+        >
+          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default PasteController
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/mob/modalconfig/pastecomponent/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/mob/modalconfig/pastecomponent/index.scss
diff --git a/src/mob/modalconfig/source.jsx b/src/mob/modalconfig/source.jsx
new file mode 100644
index 0000000..3fed414
--- /dev/null
+++ b/src/mob/modalconfig/source.jsx
@@ -0,0 +1,104 @@
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+
+const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+export const SearchItems = [
+  {
+    type: 'form',
+    label: CommonDict['model.form.text'],
+    subType: 'text',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.number'],
+    subType: 'number',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.select'],
+    subType: 'select',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.link'],
+    subType: 'link',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '寮�鍏�',
+    subType: 'switch',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '澶氶�夋',
+    subType: 'checkbox',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '鍗曢�夋',
+    subType: 'radio',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '閫夐」鍗�',
+    subType: 'checkcard',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['header.form.fileupload'],
+    subType: 'fileupload',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.dateday'],
+    subType: 'date',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.datemonth'],
+    subType: 'datemonth',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.datetime'],
+    subType: 'datetime',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['model.form.textarea'],
+    subType: 'textarea',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: CommonDict['header.form.funcvar'],
+    subType: 'funcvar',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '鎻愮ず',
+    subType: 'hint',
+    url: ''
+  },
+  {
+    type: 'form',
+    label: '鍒嗗壊绾�',
+    subType: 'split',
+    url: ''
+  }
+]
+
diff --git a/src/mob/modulesource/index.jsx b/src/mob/modulesource/index.jsx
index f4705bf..f84cdd7 100644
--- a/src/mob/modulesource/index.jsx
+++ b/src/mob/modulesource/index.jsx
@@ -53,6 +53,7 @@
             c_id: item.uuid,
             images: '',
             c_name: item.title,
+            typename: sessionStorage.getItem('appType') || '',
             long_param: '',
             del_type: 'Y'
           }).then(result => {
diff --git a/src/mob/modulesource/option.jsx b/src/mob/modulesource/option.jsx
index 6260773..417a095 100644
--- a/src/mob/modulesource/option.jsx
+++ b/src/mob/modulesource/option.jsx
@@ -9,22 +9,31 @@
 import TableCard from '@/assets/mobimg/table-card.png'
 import NormalTable from '@/assets/mobimg/normal-table.png'
 import Pie from '@/assets/mobimg/pie.png'
+import Editor from '@/assets/mobimg/editor.png'
 import SandBox from '@/assets/mobimg/sandbox.png'
 import Pie1 from '@/assets/mobimg/ring.png'
 import Pie2 from '@/assets/mobimg/nightingale.png'
-import Mainsearch from '@/assets/mobimg/mainsearch.png'
+// import Mainsearch from '@/assets/mobimg/mainsearch.png'
 import Navbar from '@/assets/mobimg/navbar-mob.png'
 import Carousel from '@/assets/mobimg/carousel.png'
 import Carousel1 from '@/assets/mobimg/carousel1.png'
 import form from '@/assets/mobimg/form.png'
+import Login from '@/assets/mobimg/login.png'
+// import dashboard from '@/assets/mobimg/dashboard.png'
+import NavTop from '@/assets/mobimg/navtop-mob.png'
+import scatter from '@/assets/mobimg/scatter.png'
+import MenuBar from '@/assets/mobimg/menubar.png'
 
 // 缁勪欢閰嶇疆淇℃伅
 export const menuOptions = [
-  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'mobnavbar', title: '瀵艰埅鏍�', width: 1200 },
+  { type: 'menu', url: NavTop, component: 'topbar', subtype: 'topbar', title: '瀵艰埅鏍�' },
+  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'tabbar', title: '鑿滃崟鏍�' },
+  { type: 'menu', url: MenuBar, component: 'menubar', subtype: 'menubar', title: '鑿滃崟' },
   { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '鏍囩椤�', width: 24 },
-  { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24 },
+  // { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24 },
   { 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: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟', width: 24 },
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24 },
   { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24 },
@@ -36,7 +45,11 @@
   { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '鏉″舰鍥�', width: 24 },
   { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '楗煎浘', width: 24 },
   { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '鐜浘', width: 24 },
-  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
   { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 24 },
+  // { type: 'menu', url: dashboard, component: 'dashboard', subtype: 'dashboard', title: '浠〃鐩�', width: 12 },
+  { type: 'menu', url: scatter, component: 'scatter', subtype: 'scatter', title: '鏁g偣鍥�', width: 24 },
+  { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
+  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24 },
+  { type: 'menu', url: Login, component: 'login', subtype: 'normallogin', title: '鐧诲綍', width: 24 },
 ]
diff --git a/src/mob/searchconfig/controller.jsx b/src/mob/searchconfig/controller.jsx
new file mode 100644
index 0000000..cd440c3
--- /dev/null
+++ b/src/mob/searchconfig/controller.jsx
@@ -0,0 +1,62 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+
+import MKEmitter from '@/utils/events.js'
+import SearchConfig from '@/mob/searchconfig'
+
+class SearchController extends Component {
+  state = {
+    config: null,
+    visible: false
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('changeSearch', this.initConfig)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('changeSearch', this.initConfig)
+  }
+
+  initConfig = (config) => {
+    this.setState({
+      visible: true,
+      config: fromJS(config).toJS()
+    })
+  }
+
+  handleBack = () => {
+    this.setState({
+      visible: false,
+      config: null
+    })
+  }
+  
+  handleSave = (search) => {
+    const { config } = this.state
+
+    MKEmitter.emit('submitSearch', {...config, search})
+  }
+
+  render () {
+    const { config, visible } = this.state
+
+    if (!visible) return null
+
+    return (
+      <SearchConfig config={config.search} handleBack={this.handleBack} handleSave={this.handleSave}/>
+    )
+  }
+}
+
+export default SearchController
\ No newline at end of file
diff --git a/src/mob/searchconfig/groupdragelement/card.jsx b/src/mob/searchconfig/groupdragelement/card.jsx
new file mode 100644
index 0000000..b0e56e2
--- /dev/null
+++ b/src/mob/searchconfig/groupdragelement/card.jsx
@@ -0,0 +1,61 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Popover } from 'antd'
+
+import './index.scss'
+
+const Card = ({ id, card, moveCard, findCard, editCard, closeCard, changeGroup }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'search', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'search',
+    canDrop: () => true,
+    drop: (item) => {
+      const { id: draggedId } = item
+
+      if (draggedId && draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    }
+  })
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+
+  const close = () => {
+    closeCard(id)
+  }
+
+  const change = () => {
+    changeGroup(id)
+  }
+
+  return (
+    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+      <div className="mk-popover-control">
+        <Icon className="edit" type="edit" onClick={edit} />
+        <Icon className="close" type="close" onClick={close} />
+      </div>
+    } trigger="hover">
+      <div className="page-card" onDoubleClick={change} style={{ opacity: opacity}}>
+        <div ref={node => drag(drop(node))}>
+          {card.wrap.icon ? <div className="icon">
+            <Icon type={card.wrap.icon} />
+          </div> : null}
+          <div className="name">
+            {card.wrap.name}
+          </div>
+        </div>
+      </div>
+    </Popover>
+  )
+}
+export default Card
diff --git a/src/mob/searchconfig/groupdragelement/index.jsx b/src/mob/searchconfig/groupdragelement/index.jsx
new file mode 100644
index 0000000..da4ac2e
--- /dev/null
+++ b/src/mob/searchconfig/groupdragelement/index.jsx
@@ -0,0 +1,64 @@
+import React, { useState } from 'react'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, handleList, handleForm, closeForm, handleGroup }) => {
+  const [cards, setCards] = useState(list)
+  const moveCard = (id, atIndex) => {
+    const { card, index } = findCard(id)
+
+    if (!card) return
+
+    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
+
+    handleList(_cards)
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
+  }
+
+  const findCard = id => {
+    const card = cards.filter(c => `${c.uuid}` === id)[0]
+    return {
+      card,
+      index: cards.indexOf(card),
+    }
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+
+    handleForm(card)
+  }
+
+  const closeCard = id => {
+    const { card } = findCard(id)
+    closeForm(card)
+  }
+
+  const changeGroup = id => {
+    const { card } = findCard(id)
+    handleGroup(card)
+  }
+
+  return (
+    <div className="ant-row modal-search-groups-row">
+      {cards.map(card => {
+        return <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          moveCard={moveCard}
+          editCard={editCard}
+          closeCard={closeCard}
+          changeGroup={changeGroup}
+          findCard={findCard}
+        />
+      })}
+    </div>
+  )
+}
+export default Container
diff --git a/src/mob/searchconfig/groupdragelement/index.scss b/src/mob/searchconfig/groupdragelement/index.scss
new file mode 100644
index 0000000..068d8d6
--- /dev/null
+++ b/src/mob/searchconfig/groupdragelement/index.scss
@@ -0,0 +1,27 @@
+
+.modal-search-groups-row {
+  min-height: 20px!important;
+  padding-right: 30px;
+  margin-bottom: 15px;
+  .page-card {
+    float: left;
+    width: 13.333%;
+    text-align: center;
+    padding: 5px;
+    .icon {
+      background: #f0f0f0;
+      color: #000000;
+      border-radius: 30px;
+      width: 35px;
+      height: 35px;
+      line-height: 35px;
+      font-size: 18px;
+      margin: 0 auto 5px;
+    }
+    .name {
+      font-size: 13px;
+      white-space: nowrap;
+      color: rgba(0, 0, 0, 0.85);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/mob/searchconfig/groupform/index.jsx b/src/mob/searchconfig/groupform/index.jsx
new file mode 100644
index 0000000..44598bc
--- /dev/null
+++ b/src/mob/searchconfig/groupform/index.jsx
@@ -0,0 +1,90 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input } from 'antd'
+import { formRule } from '@/utils/option.js'
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const MkIcon = asyncComponent(() => import('@/components/mkIcon'))
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    config: PropTypes.object,   // 琛ㄥ崟閰嶇疆淇℃伅
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {}
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { getFieldDecorator } = this.props.form
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="ant-advanced-search-form modal-setting-form">
+        <Row gutter={24}>
+          <Col span={22}>
+            <Form.Item label="鍚嶇О">
+              {getFieldDecorator('name', {
+                initialValue: config.wrap.name,
+                rules: [
+                  {
+                    required: true,
+                    message: '璇峰~鍐欏悕绉�!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+          <Col span={22}>
+            <Form.Item label="鍥炬爣">
+              {getFieldDecorator('icon', {
+                initialValue: config.wrap.icon
+              })(
+                <MkIcon allowClear/>
+              )}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/searchconfig/groupform/index.scss b/src/mob/searchconfig/groupform/index.scss
new file mode 100644
index 0000000..9a74987
--- /dev/null
+++ b/src/mob/searchconfig/groupform/index.scss
@@ -0,0 +1,18 @@
+.ant-advanced-search-form.modal-setting-form {
+  .textarea {
+    .ant-form-item-label {
+      width: 16.3%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 83.33333333%;
+    }
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/searchconfig/index.jsx b/src/mob/searchconfig/index.jsx
new file mode 100644
index 0000000..1d388a5
--- /dev/null
+++ b/src/mob/searchconfig/index.jsx
@@ -0,0 +1,574 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { DndProvider } from 'react-dnd'
+import HTML5Backend from 'react-dnd-html5-backend'
+import moment from 'moment'
+import { Button, Modal, Collapse, notification, Switch, Icon } from 'antd'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { getSearchForm } from '@/templates/zshare/formconfig'
+import SourceElement from '@/templates/modalconfig/dragelement/source'
+import SettingForm from './settingform'
+import asyncComponent from '@/utils/asyncComponent'
+import { SearchItems } from './source'
+import './index.scss'
+
+const { Panel } = Collapse
+const { confirm } = Modal
+const SearchForm = asyncComponent(() => import('@/templates/sharecomponent/searchcomponent/searchform'))
+const PasteComponent = asyncComponent(() => import('./pastecomponent'))
+const DragElement = asyncComponent(() => import('./searchdragelement'))
+const GDragElement = asyncComponent(() => import('./groupdragelement'))
+const GroupForm = asyncComponent(() => import('./groupform'))
+
+class ComModalConfig extends Component {
+  static propTpyes = {
+    btn: PropTypes.object,
+    handleSave: PropTypes.func,
+    handleBack: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,      // 瀛楀吀
+    config: null,          // 椤甸潰閰嶇疆锛屽寘鎷ā鏉跨被鍨嬨�佹ā鎬佹璁剧疆銆佹坊鍔犺〃鍚嶃�佽〃鍗曞垪琛�
+    visible: false,        // 琛ㄥ崟缂栬緫妯℃�佹锛屾樉绀烘帶鍒�
+    formlist: null,        // 琛ㄥ崟缂栬緫妯℃�佹锛屽彲缂栬緫瀛楁
+    card: null,            // 缂栬緫鍏冪礌
+    settingVisible: false, // 鍏ㄥ眬閰嶇疆妯℃�佹
+    originConfig: null,    // 鍘熷鑿滃崟
+    sqlVerifing: false,    // sql楠岃瘉
+    showField: false,      // 鏄剧ず琛ㄥ崟瀛楁鍊�
+    group: null,
+    editGroup: null
+  }
+
+  /**
+   * @description 鏁版嵁棰勫鐞�
+   */
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({
+      group: fromJS(config).toJS(),
+      config: fromJS(config).toJS(),
+      originConfig: fromJS(config).toJS()
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  /**
+   * @description 琛ㄥ崟鍙樺寲
+   */
+  handleList = (list, newcard) => {
+    let _group = {...this.state.group, fields: list}
+
+    this.setState({
+      group: _group
+    }, () => {
+      if (newcard) {
+        this.handleForm(newcard)
+      }
+    })
+    this.resetConfig(_group)
+  }
+
+  /**
+   * @description 鍒嗙粍鍙樺寲
+   */
+  handleGroupList = (list) => {
+    let _group = {...this.state.group, groups: list}
+
+    this.setState({
+      group: _group
+    })
+    this.resetConfig(_group)
+  }
+
+  /**
+   * @description 琛ㄥ崟鍙樺寲
+   */
+  handleList = (list, newcard) => {
+    let _group = {...this.state.group, fields: list}
+
+    this.setState({
+      group: _group
+    }, () => {
+      if (newcard) {
+        this.handleForm(newcard)
+      }
+    })
+    this.resetConfig(_group)
+  }
+
+  resetConfig = (group) => {
+    let _config = fromJS(this.state.config).toJS()
+    if (group.floor === 1) {
+      _config = group
+    } else {
+      _config.groups = _config.groups.map(item => {
+        if (item.uuid === group.uuid) return group
+        return item
+      })
+    }
+
+    this.setState({
+      config: _config
+    })
+  }
+
+  /**
+   * @description 琛ㄥ崟缂栬緫
+   */
+  handleForm = (_card) => {
+    let card = fromJS(_card).toJS()
+
+    this.setState({
+      visible: true,
+      card: card,
+      formlist: getSearchForm(card, [])
+    })
+  }
+
+  /**
+   * @description 缂栬緫鍚庢彁浜�
+   * 1銆佽幏鍙栫紪杈戝悗鐨勮〃鍗曚俊鎭�
+   * 2銆佸幓闄ゅ彲鑳藉瓨鍦ㄧ殑绀轰緥琛ㄥ崟
+   * 3銆侀�氳繃loading鍒锋柊
+   */
+  handleSubmit = () => {
+    const { config } = this.state
+    this.formRef.handleConfirm().then(res => {
+      let _group = fromJS(this.state.group).toJS()
+      
+      _group.fields = _group.fields.map(item => {
+        if (item.uuid === res.uuid) {
+          return res
+        } else {
+          return item
+        }
+      })
+
+      let fieldrepet = false // 瀛楁閲嶅
+      let lowerField = res.field.toLowerCase()
+
+      if (config.setting.field) {
+        let m = config.setting.field.toLowerCase().split(',')
+        if (m.includes(lowerField)) {
+          fieldrepet = true
+        }
+      }
+      config.fields.forEach(item => {
+        if (item.uuid === res.uuid) return
+        if (res.type === 'date' && item.type === 'date') return
+        if (item.field.toLowerCase() === lowerField) {
+          fieldrepet = true
+        }
+      })
+
+      config.groups.forEach(group => {
+        if (group.setting.field) {
+          let m = group.setting.field.toLowerCase().split(',')
+          if (m.includes(lowerField)) {
+            fieldrepet = true
+          }
+        }
+        group.fields.forEach(item => {
+          if (item.uuid === res.uuid) return
+          if (res.type === 'date' && item.type === 'date') return
+          if (item.field.toLowerCase() === lowerField) {
+            fieldrepet = true
+          }
+        })
+      })
+
+      if (fieldrepet) {
+        notification.warning({
+          top: 92,
+          message: '瀛楁宸插瓨鍦紒',
+          duration: 10
+        })
+        return
+      }
+
+      if (['checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+        this.setState({
+          sqlVerifing: true
+        })
+
+        let param = {
+          func: 's_debug_sql',
+          exec_type: 'y',
+          LText: res.dataSource
+        }
+
+        param.LText = param.LText.replace(/@\$|\$@/ig, '')
+        
+        param.LText = Utils.formatOptions(param.LText)
+        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+        param.secretkey = Utils.encrypt('', param.timestamp)
+
+        if (window.GLOB.mainSystemApi && res.database === 'sso') {
+          param.rduri = window.GLOB.mainSystemApi
+        }
+        
+        Api.getLocalConfig(param).then(result => {
+          if (result.status) {
+            this.setState({
+              sqlVerifing: false,
+              group: _group,
+              card: null,
+              visible: false
+            })
+            this.resetConfig(_group)
+          } else {
+            this.setState({sqlVerifing: false})
+            
+            Modal.error({
+              title: result.message
+            })
+          }
+        })
+      } else {
+        this.setState({
+          group: _group,
+          card: null,
+          visible: false
+        })
+        this.resetConfig(_group)
+      }
+    })
+  }
+
+  /**
+   * @description 琛ㄥ崟鍒犻櫎骞跺埛鏂�
+   */
+  closeForm = (card) => {
+    let _this = this
+
+    confirm({
+      content: `纭畾鍒犻櫎${card.label ? `<<${card.label}>>` : ''}鍚楋紵`,
+      onOk() {
+        let _group = fromJS(_this.state.group).toJS()
+        _group.fields = _group.fields.filter(item => item.uuid !== card.uuid)
+
+        _this.setState({
+          group: _group,
+        })
+        _this.resetConfig(_group)
+      },
+      onCancel() {}
+    })
+  }
+
+  submitConfig = () => {
+    const { config } = this.state
+
+    this.setState({originConfig: fromJS(config).toJS()})
+    this.props.handleSave(config)
+    notification.success({
+      top: 92,
+      message: '淇濆瓨鎴愬姛銆�',
+      duration: 1
+    })
+  }
+
+  cancelConfig = () => {
+    const { config, originConfig } = this.state
+
+    if (!is(fromJS(config), fromJS(originConfig))) {
+      let _this = this
+      confirm({
+        content: '閰嶇疆淇℃伅鏈繚瀛橈紝纭畾杩斿洖鍚楋紵',
+        onOk() {
+          _this.props.handleBack()
+        },
+        onCancel() {}
+      })
+    } else {
+      this.props.handleBack()
+    }
+  }
+
+  /**
+   * @description 鍒嗙粍璁剧疆妯℃�佹
+   */
+  changeSetting = () => {
+    this.setState({
+      settingVisible: true
+    })
+  }
+
+  /**
+   * @description 淇濆瓨鍒嗙粍璁剧疆
+   */
+  settingSave = () => {
+    const { config } = this.state
+    this.settingRef.handleConfirm().then(res => {
+      let _group = {...this.state.group, setting: res}
+      let lowers = _group.setting.field ? _group.setting.field.toLowerCase() : ''
+
+      if (lowers) {
+        let fieldrepet = false // 瀛楁閲嶅
+        lowers = lowers.split(',')
+        let length = lowers.length
+
+        if (_group.floor !== 1 && config.setting.field) {
+          let m = config.setting.field.toLowerCase().split(',')
+          if (Array.from(new Set([...m, ...lowers])).length < m.length + length) {
+            fieldrepet = true
+          }
+        }
+
+        config.fields.forEach(item => {
+          if (lowers.includes(item.field.toLowerCase())) {
+            fieldrepet = true
+          }
+        })
+
+        config.groups.forEach(group => {
+          if (_group.uuid === group.uuid) return
+          if (group.setting.field) {
+            let m = group.setting.field.toLowerCase().split(',')
+            if (Array.from(new Set([...m, ...lowers])).length < m.length + length) {
+              fieldrepet = true
+            }
+          }
+          group.fields.forEach(item => {
+            if (lowers.includes(item.field.toLowerCase())) {
+              fieldrepet = true
+            }
+          })
+        })
+
+        if (fieldrepet) {
+          notification.warning({
+            top: 92,
+            message: '瀛楁宸插瓨鍦紒',
+            duration: 10
+          })
+          return
+        }
+      }
+
+      this.setState({
+        group: _group,
+        settingVisible: false
+      })
+      this.resetConfig(_group)
+    })
+  }
+
+  editModalCancel = () => {
+    const { group, card } = this.state
+
+    if (card.focus) {
+      let _fields = group.fields.filter(item => item.uuid !== card.uuid)
+      let _group = {...group, fields: _fields}
+
+      this.setState({
+        card: null,
+        group: _group,
+        visible: false
+      })
+      this.resetConfig(_group)
+    } else {
+      this.setState({
+        card: null,
+        visible: false
+      })
+    }
+  }
+
+  plusGroup = () => {
+    let config = fromJS(this.state.config).toJS()
+    let _g = {
+      uuid: Utils.getuuid(),
+      wrap: { name: 'name', icon: '' },
+      setting: { type: 'title', field: '', title: '', focus: 'true', btn: 'hidden' },
+      fields: []
+    }
+
+    config.groups.push(_g)
+
+    this.setState({config, group: config, editGroup: _g, gVisible: true})
+  }
+
+  handleGroupForm = (_g) => {
+    this.setState({editGroup: _g, gVisible: true})
+  }
+
+   /**
+   * @description 淇濆瓨鍒嗙粍璁剧疆
+   */
+  groupSave = () => {
+    this.gRef.handleConfirm().then(res => {
+      let _g = {...this.state.editGroup, wrap: res}
+
+      let _group = fromJS(this.state.group).toJS()
+      _group.groups = _group.groups.map(item => {
+        if (item.uuid === _g.uuid) return _g
+        return item
+      })
+
+      this.setState({
+        editGroup: null,
+        group: _group,
+        gVisible: false
+      })
+      this.resetConfig(_group)
+    })
+  }
+
+  handleGroup = (g) => {
+    this.setState({
+      group: g
+    })
+  }
+
+  closeGroup = (g) => {
+    const _this = this
+    let _group = fromJS(this.state.group).toJS()
+    _group.groups = _group.groups.filter(item => item.uuid !== g.uuid)
+
+    confirm({
+      content: `纭畾鍒犻櫎鍒嗙粍銆�${g.wrap.name}銆嬪悧锛焋,
+      onOk() {
+        _this.setState({ group: _group })
+        _this.resetConfig(_group)
+      },
+      onCancel() {}
+    })
+  }
+
+  returnUp = () => {
+    const { config } = this.state
+
+    this.setState({
+      group: config
+    })
+  }
+
+  render () {
+    const { dict, group, editGroup } = this.state
+    return (
+      <div className="mob-search-board">
+        <DndProvider backend={HTML5Backend}>
+          <div className="tools">
+            <Collapse accordion defaultActiveKey="1" bordered={false}>
+              <Panel header={dict['header.menu.form']} key="1">
+                <div className="search-element">
+                  {SearchItems.map((item, index) => {
+                    return (<SourceElement key={index} content={item}/>)
+                  })}
+                </div>
+              </Panel>
+            </Collapse>
+          </div>
+          <div className="modal-control">
+            <Button type="primary" onClick={this.submitConfig}>淇濆瓨</Button>
+            <Button onClick={this.cancelConfig}>鍏抽棴</Button>
+            {!group.floor ? <Button onClick={this.returnUp}>杩斿洖涓婄骇</Button> : null}
+            <PasteComponent insert={this.insert} />
+            <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
+          </div>
+          <div className="setting">
+            <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
+              <div className="mob-shell-inner">
+                <Icon className="setting-group" onClick={this.changeSetting} type="setting" />
+                {group.setting.type === 'title' ? <div className="am-navbar">
+                  <Icon type="left" />
+                  <div className="am-navbar-title">{group.setting.title}</div>
+                </div> : <div className="am-navbar">
+                  <Icon type="left" />
+                  <div className="search-bar"><Icon type="search" /></div>
+                </div>}
+                {group.floor === 1 ? <Icon className="plus-group" type="plus" onClick={this.plusGroup} /> : null}
+                <div style={{minHeight: 'calc(100% - 100px)'}}>
+                  {group.floor === 1 && group.groups.length > 0 ? <GDragElement
+                    list={group.groups}
+                    handleList={this.handleGroupList}
+                    handleForm={this.handleGroupForm}
+                    handleGroup={this.handleGroup}
+                    closeForm={this.closeGroup}
+                  /> : null}
+                  <DragElement
+                    list={group.fields}
+                    showField={this.state.showField}
+                    handleList={this.handleList}
+                    handleForm={this.handleForm}
+                    closeForm={this.closeForm}
+                  />
+                </div>
+                {group.setting.btn !== 'hidden' ? <div className="search-btn">
+                  <Button className="reset">閲嶇疆</Button>
+                  <Button className="submit" type="primary">纭畾</Button>
+                </div> : null}
+              </div>
+            </div>
+          </div>
+        </DndProvider>
+        <Modal
+          title={this.state.dict['model.edit']}
+          visible={this.state.visible}
+          width={850}
+          onCancel={this.editModalCancel}
+          onOk={this.handleSubmit}
+          confirmLoading={this.state.sqlVerifing}
+          destroyOnClose
+        >
+          <SearchForm
+            dict={this.state.dict}
+            card={this.state.card}
+            formlist={this.state.formlist}
+            inputSubmit={this.handleSubmit}
+            wrappedComponentRef={(inst) => this.formRef = inst}
+          />
+        </Modal>
+        <Modal
+          title={this.state.dict['model.edit']}
+          visible={this.state.settingVisible}
+          width={850}
+          maskClosable={false}
+          onOk={this.settingSave}
+          onCancel={() => { this.setState({ settingVisible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            config={group}
+            inputSubmit={this.settingSave}
+            wrappedComponentRef={(inst) => this.settingRef = inst}
+          />
+        </Modal>
+        <Modal
+          title={this.state.dict['model.edit']}
+          visible={this.state.gVisible}
+          width={600}
+          maskClosable={false}
+          onOk={this.groupSave}
+          onCancel={() => { this.setState({ gVisible: false }) }}
+          destroyOnClose
+        >
+          <GroupForm
+            config={editGroup}
+            inputSubmit={this.groupSave}
+            wrappedComponentRef={(inst) => this.gRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default ComModalConfig
\ No newline at end of file
diff --git a/src/mob/searchconfig/index.scss b/src/mob/searchconfig/index.scss
new file mode 100644
index 0000000..fac4043
--- /dev/null
+++ b/src/mob/searchconfig/index.scss
@@ -0,0 +1,365 @@
+.mob-search-board {
+  position: fixed;
+  z-index: 1070;
+  top: 48px;
+  left: 0px;
+  right: 0px;
+  bottom: 0px;
+  background: rgba(0, 0, 0, 1);
+  .tools {
+    position: absolute;
+    top: 0;
+    left: 0;
+    z-index: 1;
+    width: 235px;
+    background: #ffffff;
+    border-right: 1px solid #d9d9d9;
+    height: 100%;
+    overflow-y: auto;
+    padding-bottom: 30px;
+    .ant-collapse-borderless {
+      background-color: #ffffff;
+    }
+    .ant-collapse-item {
+      border: 0;
+    }
+    .ant-input-search {
+      margin-top: 10px;
+    }
+    .ant-collapse-item.ant-collapse-item-active {
+      border-bottom: 1px solid #d9d9d9;
+    }
+    .ant-collapse .ant-collapse-header {
+      padding: 11px 16px 10px 40px;
+      border-bottom: 1px solid #d9d9d9;
+      background: #1890ff;
+      color: #ffffff;
+    }
+    .ant-collapse-content-box {
+      .ant-form-item {
+        margin-bottom: 10px;
+        .ant-form-item-label {
+          text-align: left;
+          height: 25px;
+          line-height: 25px;
+        }
+      }
+      .ant-btn {
+        margin-bottom: 10px;
+      }
+    }
+    .search-element {
+      padding-top: 10px;
+      li {
+        padding: 0px 16px 10px;
+        div {
+          cursor: move;
+        }
+      }
+    }
+    .tables {
+      .ant-select-selection-selected-value {
+        opacity: 0.4!important;
+      }
+    }
+    .ant-list {
+      margin-top: 20px;
+      .ant-list-item {
+        display: -webkit-box;
+        padding-right: 20px;
+        position: relative;
+        padding-left: 5px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        -webkit-line-clamp: 2;
+        -webkit-box-orient: vertical;
+        width: 100%;
+        .anticon {
+          position: absolute;
+          top: 0px;
+          right: 0px;
+          padding: 3px 3px 10px 10px;
+          cursor: pointer;
+        }
+        .bottom-mask {
+          position: absolute;
+          width: 100%;
+          height: 8px;
+          bottom: 0;
+          left: 0;
+          background: #ffffff;
+          border-radius: 8px;
+        }
+      }
+    }
+  }
+  .tools::-webkit-scrollbar {
+    width: 4px;
+  }
+  .tools::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
+    background: rgba(0, 0, 0, 0.08);
+  }
+  .tools::-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);
+  }
+  .modal-control {
+    position: absolute;
+    right: 0;
+    top: 0;
+    width: 120px;
+    height: 100vh;
+    padding: 20px 10px;
+    background: #ffffff;
+    z-index: 10;
+    transition: right 0.3s;
+
+    div:not(.draw), button:not(.ant-switch) {
+      display: block!important;
+      margin-bottom: 15px;
+      width: 100%;
+    }
+    .ant-switch.big {
+      min-width: 60px;
+      height: 24px;
+      line-height: 24px;
+      margin-bottom: 15px;
+      .ant-switch-inner {
+        font-size: 14px;
+      }
+    }
+    .ant-switch.big:after {
+      width: 22px;
+      height: 22px;
+    }
+  }
+  .setting {
+    position: relative;
+    width: 100vw;
+    height: 100%;
+    background: #959595;
+    
+    .mob-shell {
+      margin: 0 auto;
+      background: #000000;
+      background-size: 100% 100%;
+      padding: 25px 13px 40px;
+      border-radius: 30px;
+
+      .am-navbar {
+        height: 45px;
+        line-height: 45px;
+        position: relative;
+        border-bottom: 1px solid #f0f0f0;
+        margin-bottom: 10px;
+        .anticon-close, .anticon-left {
+          position: absolute;
+          line-height: 45px;
+          font-size: 18px;
+          left: 10px;
+        }
+        .am-navbar-title {
+          font-size: 16px;
+          text-align: center;
+          color: #000000;
+        }
+        .search-bar {
+          height: 35px;
+          line-height: 35px;
+          padding: 0 10px;
+          color:rgba(0, 0, 0, 0.65);
+          border: 1px solid #E9EDF0;
+          background: #E9EDF0;
+          border-radius: 4px;
+          position: relative;
+          top: 50%;
+          transform: translateY(-50%);
+          margin: 0 30px 0 35px;
+        }
+      }
+      .search-btn {
+        .reset {
+          width: 30%;
+          border-radius: 0;
+          opacity: 0.5;
+          cursor: default;
+          font-size: 18px;
+          height: 45px;
+        }
+        .submit {
+          width: 70%;
+          border-radius: 0;
+          opacity: 0.5;
+          cursor: default;
+          font-size: 18px;
+          height: 45px;
+        }
+      }
+
+      .setting-group {
+        position: absolute;
+        right: 0px;
+        top: 0px;
+        font-size: 18px;
+        padding: 5px;
+        cursor: pointer;
+        z-index: 1;
+      }
+      .plus-group {
+        color: #26C281;
+        position: absolute;
+        right: 0px;
+        top: 45px;
+        font-size: 18px;
+        padding: 5px;
+        cursor: pointer;
+        z-index: 2;
+      }
+
+      .modal-search-fields-row {
+        min-height: 300px;
+        padding: 0 10px 35px;
+      }
+
+      .modal-form {
+        padding: 0px 24px;
+        min-height: 87px;
+        .group-title {
+          position: relative;
+          min-height: 22px;
+          margin-bottom: 10px;
+          padding-top: 10px;
+          border-bottom: 1px solid #e8e8e8;
+
+          span {
+            padding: 0 5px 5px;
+          }
+        }
+        > .ant-row {
+          min-height: 120px;
+        }
+        .ant-row .ant-col-6 {
+          padding: 0 12px!important;
+        }
+        .ant-row.ant-form-item .ant-col {
+          padding: 0;
+        }
+        .textarea2, .textarea4 {
+          padding-left: 7px;
+        }
+        .page-card {
+          position: relative;
+          background: #ffffff;
+          border-radius: 2px;
+          margin-bottom: 15px;
+          .ant-form-item {
+            cursor: move;
+            display: flex;
+            margin-bottom: 0px;
+            .ant-form-item-label {
+              overflow: visible;
+              position: relative;
+              height: 40px;
+              label {
+                width: 100%;
+                cursor: move;
+                overflow: hidden;
+                display: inline-block;
+                text-overflow: ellipsis;
+                white-space: nowrap;
+              }
+            }
+            .ant-form-item-control-wrapper {
+              position: relative;
+              .ant-select {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .ant-calendar-picker {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .ant-input-number {
+                width: 100%;
+                margin-top: 4px;
+              }
+              .normal-braft-editor {
+                border: 1px solid #d9d9d9;
+                border-radius: 4px;
+              }
+            }
+            .ant-form-item-control-wrapper::after {
+              content: '';
+              position: absolute;
+              top: 0;
+              left: 0;
+              right: 0;
+              bottom: 0;
+              opacity: 0;
+              z-index: 1;
+            }
+            .ant-col-cuslabel {
+              width: 10.5%;
+            }
+            .ant-col-cuswrap {
+              width: 89.5%;
+            }
+          }
+        }
+        .ant-calendar-picker {
+          min-width: 100px!important;
+        }
+      }
+    }
+  }
+  .setting {
+    overflow-y: auto;
+  }
+  .setting::-webkit-scrollbar {
+    width: 7px;
+  }
+  .setting::-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);
+  }
+  .setting::-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);
+  }
+}
+
+
+.modal-fields {
+  .ant-modal {
+    top: 50px;
+    padding-bottom: 5px;
+    .ant-modal-body {
+      max-height: calc(100vh - 190px);
+      overflow-y: auto;
+      .ant-empty {
+        margin: 15vh 8px;
+      }
+    }
+    .ant-modal-body::-webkit-scrollbar {
+      width: 7px;
+    }
+    .ant-modal-body::-webkit-scrollbar-thumb {
+      border-radius: 5px;
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
+      background: rgba(0, 0, 0, 0.13);
+    }
+    .ant-modal-body::-webkit-scrollbar-track {
+      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
+      border-radius: 3px;
+      border: 1px solid rgba(0, 0, 0, 0.07);
+      background: rgba(0, 0, 0, 0);
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/mob/searchconfig/pastecomponent/index.jsx b/src/mob/searchconfig/pastecomponent/index.jsx
new file mode 100644
index 0000000..ed81117
--- /dev/null
+++ b/src/mob/searchconfig/pastecomponent/index.jsx
@@ -0,0 +1,57 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Button, Modal, notification } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const PasteForm = asyncComponent(() => import('@/templates/zshare/pasteform'))
+
+class PasteController extends Component {
+  static propTpyes = {
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    visible: false
+  }
+
+  pasteSubmit = () => {
+    this.pasteFormRef.handleConfirm().then(res => {
+      if (res.copyType !== 'search') {
+        notification.warning({ top: 92, message: '閰嶇疆淇℃伅鏍煎紡閿欒锛�', duration: 5 })
+        return
+      }
+
+      if (['multiselect', 'color', 'brafteditor'].includes(res.type)) {
+        res.type = 'text'
+      }
+
+      this.props.updateConfig(res)
+      this.setState({visible: false})
+    })
+  }
+
+  render() {
+    const { visible } = this.state
+
+    return (
+      <div style={{display: 'inline-block'}}>
+        <Button icon="snippets" style={{color: 'purple'}} onClick={() => {this.setState({visible: true})}} >绮樿创</Button>
+        <Modal
+          title="绮樿创"
+          visible={visible}
+          width={600}
+          maskClosable={false}
+          onOk={this.pasteSubmit}
+          onCancel={() => {this.setState({visible: false})}}
+          destroyOnClose
+        >
+          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default PasteController
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/mob/searchconfig/pastecomponent/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/mob/searchconfig/pastecomponent/index.scss
diff --git a/src/mob/searchconfig/searchdragelement/card.jsx b/src/mob/searchconfig/searchdragelement/card.jsx
new file mode 100644
index 0000000..5a4b632
--- /dev/null
+++ b/src/mob/searchconfig/searchdragelement/card.jsx
@@ -0,0 +1,132 @@
+import React from 'react'
+import { useDrag, useDrop } from 'react-dnd'
+import { Icon, Popover, Form } from 'antd'
+import { Range } from 'antd-mobile'
+import moment from 'moment'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard'))
+
+const Card = ({ id, card, moveCard, findCard, editCard, closeCard, copyCard, showField }) => {
+  const originalIndex = findCard(id).index
+  const [{ isDragging }, drag] = useDrag({
+    item: { type: 'search', id, originalIndex },
+    collect: monitor => ({
+      isDragging: monitor.isDragging(),
+    }),
+  })
+  const [, drop] = useDrop({
+    accept: 'search',
+    canDrop: () => true,
+    drop: (item) => {
+      const { id: draggedId, originalIndex } = item
+
+      if (originalIndex === undefined) {
+        item.dropTargetId = id
+      } else if (draggedId && draggedId !== id) {
+        const { index: overIndex } = findCard(id)
+        moveCard(draggedId, overIndex)
+      }
+    }
+  })
+  const opacity = isDragging ? 0 : 1
+
+  const edit = () => {
+    editCard(id)
+  }
+
+  const close = () => {
+    closeCard(id)
+  }
+
+  const copy = () => {
+    copyCard(id)
+  }
+
+  let formItem = null
+  if (card.type === 'date') {
+    formItem = (<div className="am-list-item">
+      <div className="am-list-line">
+        {card.labelShow !== 'false' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">{card.initval ? moment().subtract(card.initval, 'days').format('YYYY-MM-DD') : '璇烽�夋嫨'}</div>
+        <div className="am-list-extra"><Icon type="right" /></div>
+      </div>
+    </div>)
+  } else if (card.type === 'datemonth') {
+    formItem = (<div className="am-list-item">
+      <div className="am-list-line">
+        {card.labelShow !== 'false' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">{card.initval ? moment().subtract(card.initval, 'month').format('YYYY-MM') : '璇烽�夋嫨'}</div>
+        <div className="am-list-extra"><Icon type="right" /></div>
+      </div>
+    </div>)
+  } else if (card.type === 'range') {
+    let value = [(card.minValue || 0), (card.maxValue || 20)]
+    if (card.initval) {
+      value = card.initval.split(',')
+      value = [+value[0], +value[1]]
+    }
+    formItem = (<div className="am-list-item slider">
+      <div className="am-list-line">
+        {card.labelShow !== 'false' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">
+          <Range
+            min={card.minValue || 0}
+            max={card.maxValue || 20}
+            value={value}
+          />
+        </div>
+      </div>
+    </div>)
+  } else if (card.type === 'daterange') {
+    let value = '璇烽�夋嫨'
+    if (card.initval) {
+      try {
+        let _initval = JSON.parse(card.initval)
+        value = [moment().subtract(_initval[0], 'days').format('YYYY-MM-DD'), moment().subtract(_initval[1], 'days').format('YYYY-MM-DD')].join(' ~ ')
+      } catch {
+        value = '璇烽�夋嫨'
+      }
+    }
+    formItem = (<div className="am-list-item">
+      <div className="am-list-line">
+        {card.labelShow !== 'false' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">{value}</div>
+        <div className="am-list-extra"><Icon type="right" /></div>
+      </div>
+    </div>)
+  } else if (card.type === 'checkcard') {
+    formItem = (<div className="am-list-item check-card">
+      <div className="am-list-line">
+        {card.labelShow !== 'false' ? <div className="am-input-label">{card.label}</div> : null}
+        <div className="am-input-control">
+          <CheckCard config={card} />
+        </div>
+      </div>
+    </div>)
+  }
+
+  return (
+    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+      <div className="mk-popover-control">
+        <Icon className="edit" type="edit" onClick={edit} />
+        <Icon className="copy" type="copy" onClick={copy} />
+        <Icon className="close" type="close" onClick={close} />
+      </div>
+    } trigger="hover">
+      <div className="page-card" style={{ opacity: opacity}}>
+        <div ref={node => drag(drop(node))}>
+          {card.type === 'split' ? formItem : <Form.Item
+            className={'ant-form-item' + (card.required === 'true' ? ' required' : '') + (card.splitline === 'false' ? ' no-boder' : '')}
+          >
+            {formItem}
+            {showField ? <div className="field-name">{card.field}{card.hidden === 'true' ? '(闅愯棌)' : ''}</div> : ''}
+          </Form.Item>}
+        </div>
+      </div>
+    </Popover>
+  )
+}
+export default Card
diff --git a/src/mob/searchconfig/searchdragelement/index.jsx b/src/mob/searchconfig/searchdragelement/index.jsx
new file mode 100644
index 0000000..10a535e
--- /dev/null
+++ b/src/mob/searchconfig/searchdragelement/index.jsx
@@ -0,0 +1,123 @@
+import React, { useState } from 'react'
+import { useDrop } from 'react-dnd'
+import { is, fromJS } from 'immutable'
+import update from 'immutability-helper'
+import Utils from '@/utils/utils.js'
+import Card from './card'
+import './index.scss'
+
+const Container = ({list, handleList, handleForm, closeForm, showField }) => {
+  const [cards, setCards] = useState(list)
+  const moveCard = (id, atIndex) => {
+    const { card, index } = findCard(id)
+
+    if (!card) return
+
+    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
+
+    handleList(_cards)
+  }
+
+  if (!is(fromJS(cards), fromJS(list))) {
+    setCards(list)
+  }
+
+  const findCard = id => {
+    const card = cards.filter(c => `${c.uuid}` === id)[0]
+    return {
+      card,
+      index: cards.indexOf(card),
+    }
+  }
+
+  const editCard = id => {
+    const { card } = findCard(id)
+    delete card.focus
+    handleForm(card)
+  }
+
+  const closeCard = id => {
+    const { card } = findCard(id)
+    closeForm(card)
+  }
+
+  const copyCard = id => {
+    const { card, index: overIndex } = findCard(id)
+
+    let _card = fromJS(card).toJS()
+    _card.uuid = Utils.getuuid()
+    _card.focus = true
+
+    // 澶嶅埗鍒板壀鍒囨澘
+    let oInput = document.createElement('input')
+    let val = JSON.parse(JSON.stringify(_card))
+    val.copyType = 'search'
+
+    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
+    document.body.appendChild(oInput)
+    oInput.select()
+    document.execCommand('Copy')
+    oInput.className = 'oInput'
+    oInput.style.display = 'none'
+    document.body.removeChild(oInput)
+
+    const _cards = update(cards, { $splice: [[overIndex + 1, 0, _card]] })
+
+    setCards(_cards)
+
+    handleList(_cards, _card)
+  }
+
+  const [, drop] = useDrop({
+    accept: 'search',
+    drop(item) {
+      if (item.hasOwnProperty('originalIndex')) {
+        return
+      }
+
+      let newcard = {}
+      newcard.uuid = Utils.getuuid()
+      newcard.label = 'label'
+      newcard.type = item.subType
+      newcard.resourceType = '0'
+      newcard.options = []
+      newcard.required = 'true'
+      newcard.focus = true
+
+      let targetId = ''
+
+      if (item.dropTargetId) {
+        targetId = item.dropTargetId
+        delete item.dropTargetId
+      } else if (cards.length > 0) {
+        targetId = cards[cards.length - 1].uuid
+      }
+
+      const { index: overIndex } = findCard(`${targetId}`) // cards涓虹┖鏃� overIndex 涓� -1
+      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
+
+      setCards(_cards)
+
+      handleList(_cards, newcard)
+    }
+  })
+
+  return (
+    <div ref={drop} className="ant-row modal-search-fields-row">
+      {cards.map(card => {
+        return <Card
+          id={card.uuid}
+          key={card.uuid}
+          card={card}
+          showField={showField}
+          moveCard={moveCard}
+          editCard={editCard}
+          closeCard={closeCard}
+          copyCard={copyCard}
+          findCard={findCard}
+        />
+      })}
+    </div>
+  )
+}
+export default Container
diff --git a/src/mob/searchconfig/searchdragelement/index.scss b/src/mob/searchconfig/searchdragelement/index.scss
new file mode 100644
index 0000000..357ef51
--- /dev/null
+++ b/src/mob/searchconfig/searchdragelement/index.scss
@@ -0,0 +1,149 @@
+
+.modal-search-fields-row {
+  padding-bottom: 35px;
+  .mob-col.ant-col {
+    display: inline-block;
+    float: none;
+    vertical-align: top;
+    padding-left: 1.2%;
+    padding-right: 1.2%;
+  }
+  .am-list-item {
+    font-size: 16px;
+    padding-left: 10px;
+    position: relative;
+    display: flex;
+    height: 44px;
+    min-height: 44px;
+    background-color: #fff;
+    vertical-align: middle;
+    overflow: hidden;
+    transition: background-color 200ms;
+    align-items: center;
+
+    .am-list-line {
+      align-items: center;
+      position: relative;
+      display: flex;
+      flex: 1 1;
+      align-self: stretch;
+      padding-right: 15px;
+      overflow: hidden;
+      .am-input-label {
+        width: 28%;
+        color: #000;
+        font-size: 16px;
+        margin-left: 0;
+        margin-right: 5px;
+        text-align: left;
+        white-space: nowrap;
+        overflow: hidden;
+        padding: 2px 0;
+        text-overflow: ellipsis;
+      }
+      .am-list-switch {
+        flex: 1;
+        text-align: right;
+      }
+      .am-input-control {
+        font-size: 16px;
+        flex: 1 1;
+        text-align: right;
+      }
+      .am-input-control.left {
+        text-align: left;
+      }
+      .am-list-extra {
+        display: block;
+        width: 15px;
+        height: 15px;
+        margin-left: 8px;
+        i {
+          vertical-align: top;
+        }
+      }
+    }
+  }
+  .am-list-item.check-card {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+      .check-card-edit-box {
+        margin-top: 0!important;
+      }
+    }
+  }
+  .am-list-item.hint {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+      .am-input-label {
+        line-height: 2;
+      }
+      .am-input-control {
+        font-size: 14px;
+        line-height: 1.5;
+        text-align: left;
+        padding-bottom: 5px;
+      }
+    }
+  }
+  .am-list-item.slider {
+    height: auto;
+    .am-list-line {
+      align-items: start;
+      display: block;
+      .am-input-control {
+        height: 25px;
+        padding-top: 10px;
+        padding-left: 12px;
+      }
+    }
+  }
+  
+  .check-card-edit-box .card-cell span {
+    line-height: 1.5;
+  }
+  .ant-form-item {
+    cursor: move;
+    margin-bottom: 0px;
+    .ant-form-item-control-wrapper::after {
+      content: '';
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      opacity: 0;
+      z-index: 1;
+    }
+    .field-name {
+      margin-left: 10px;
+      line-height: 1.5;
+    }
+    .ant-form-item-children {
+      vertical-align: top;
+    }
+  }
+  .ant-form-item.required {
+    .am-input-label::before {
+      display: inline-block;
+      margin-right: 4px;
+      color: #f5222d;
+      font-size: 14px;
+      font-family: SimSun, sans-serif;
+      line-height: 1;
+      content: '*';
+    }
+  }
+  .ant-form-item.no-boder {
+    .am-list-line {
+      border-bottom: none;
+    }
+  }
+  .page-card {
+    margin-bottom: 10px;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/searchconfig/settingform/index.jsx b/src/mob/searchconfig/settingform/index.jsx
new file mode 100644
index 0000000..c5a5443
--- /dev/null
+++ b/src/mob/searchconfig/settingform/index.jsx
@@ -0,0 +1,222 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Radio, Select, Tooltip, Icon } from 'antd'
+import { formRule } from '@/utils/option.js'
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,     // 瀛楀吀椤�
+    config: PropTypes.object,   // 琛ㄥ崟閰嶇疆淇℃伅
+    inputSubmit: PropTypes.any  // 鍥炶溅鎻愪氦浜嬩欢
+  }
+
+  state = {
+    roleList: [],
+    type: this.props.config.setting.type || 'title'
+  }
+
+  UNSAFE_componentWillMount() {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    this.setState({roleList})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { type, roleList } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="mob-search-setting-form">
+        <Row gutter={24}>
+          <Col span={12}>
+            <Form.Item label="椤堕儴鏍峰紡">
+              {getFieldDecorator('type', {
+                initialValue: type
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({type: e.target.value})}>
+                  <Radio value="title">鏍囬鏍�</Radio>
+                  <Radio value="search">鎼滅储鏍�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="浣跨敤鎼滅储鏍忔椂锛屾爣棰樼敤浜庢悳绱㈡潯浠堕殣钘忔椂鏄剧ず銆�">
+                <Icon type="question-circle" />
+                鏍囬
+              </Tooltip>
+            }>
+              {getFieldDecorator('title', {
+                initialValue: config.setting.title,
+                rules: [
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="鎼滅储瀛楁">
+              {getFieldDecorator('field', {
+                initialValue: config.setting.field,
+                rules: [
+                  {
+                    required: true,
+                    message: '璇峰~鍐欏瓧娈�!'
+                  },
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  },
+                  {
+                    pattern: formRule.field.multipattern,
+                    message: formRule.field.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col> : null}
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="鍒濆鍊�">
+              {getFieldDecorator('initval', {
+                initialValue: config.setting.initval,
+                rules: [
+                  {
+                    max: formRule.input.max,
+                    message: formRule.input.message
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col> : null}
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="鍖归厤鏂瑰紡">
+              {getFieldDecorator('match', {
+                initialValue: config.setting.match || 'like'
+              })(
+                <Radio.Group>
+                  <Radio value="like">like</Radio>
+                  <Radio value="not like">not like</Radio>
+                  <Radio value="=">=</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="蹇呭~">
+              {getFieldDecorator('required', {
+                initialValue: config.setting.required || 'false'
+              })(
+                <Radio.Group>
+                  <Radio value="true">鏄�</Radio>
+                  <Radio value="false">鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="闅愯棌">
+              {getFieldDecorator('Hide', {
+                initialValue: config.setting.Hide || 'false'
+              })(
+                <Radio.Group>
+                  <Radio value="true">鏄�</Radio>
+                  <Radio value="false">鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="鑷姩鑱氱劍">
+              {getFieldDecorator('focus', {
+                initialValue: config.setting.focus || 'true'
+              })(
+                <Radio.Group>
+                  <Radio value="true">鏄�</Radio>
+                  <Radio value="false">鍚�</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col> : null}
+          <Col span={12}>
+            <Form.Item label="鎼滅储鎸夐挳">
+              {getFieldDecorator('btn', {
+                initialValue: config.setting.btn || 'hidden'
+              })(
+                <Radio.Group>
+                  <Radio value="hidden">闅愯棌</Radio>
+                  <Radio value="show">鏄剧ず</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {type === 'search' ? <Col span={12}>
+            <Form.Item label="榛戝悕鍗�">
+              {getFieldDecorator('blacklist', {
+                initialValue: config.setting.blacklist || []
+              })(
+                <Select
+                  showSearch
+                  mode="multiple"
+                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                >
+                  {roleList.map(option =>
+                    <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/mob/searchconfig/settingform/index.scss b/src/mob/searchconfig/settingform/index.scss
new file mode 100644
index 0000000..f0d30ef
--- /dev/null
+++ b/src/mob/searchconfig/settingform/index.scss
@@ -0,0 +1,23 @@
+.mob-search-setting-form {
+  .textarea {
+    .ant-form-item-label {
+      width: 16.3%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 83.33333333%;
+    }
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
+  .ant-col.ant-col-12 {
+    display: inline-block;
+    float: none;
+    vertical-align: top;
+  }
+}
\ No newline at end of file
diff --git a/src/mob/searchconfig/source.jsx b/src/mob/searchconfig/source.jsx
new file mode 100644
index 0000000..9d4684f
--- /dev/null
+++ b/src/mob/searchconfig/source.jsx
@@ -0,0 +1,33 @@
+export const SearchItems = [
+  {
+    type: 'search',
+    label: '鏁板�硷紙鍖洪棿锛�',
+    subType: 'range',
+    url: ''
+  },
+  {
+    type: 'search',
+    label: '閫夐」鍗�',
+    subType: 'checkcard',
+    url: ''
+  },
+  {
+    type: 'search',
+    label: '鏃ユ湡锛堝ぉ锛�',
+    subType: 'date',
+    url: ''
+  },
+  {
+    type: 'search',
+    label: '鏃ユ湡锛堟湀锛�',
+    subType: 'datemonth',
+    url: ''
+  },
+  {
+    type: 'search',
+    label: '鏃ユ湡锛堝尯闂达級',
+    subType: 'daterange',
+    url: ''
+  },
+]
+
diff --git a/src/pc/bgcontroller/index.jsx b/src/pc/bgcontroller/index.jsx
index 67d98f5..b77b775 100644
--- a/src/pc/bgcontroller/index.jsx
+++ b/src/pc/bgcontroller/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Form, Icon } from 'antd'
+import { Form, Icon, Select } from 'antd'
 
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
@@ -11,6 +11,7 @@
 const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
 const StyleInput = asyncComponent(() => import('@/menu/stylecontroller/styleInput'))
 const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
+const { Option } = Select
 
 class MobController extends Component {
   static propTpyes = {
@@ -22,6 +23,10 @@
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     backgroundColor: '',
     backgroundImage: '',
+    backgroundSize: '',
+    backgroundRepeat: '',
+    backgroundPositon: '',
+    opacity: '',
   }
 
   UNSAFE_componentWillMount () {
@@ -36,7 +41,10 @@
 
     this.setState({
       backgroundColor: config.style.backgroundColor,
-      backgroundImage: bgImg
+      backgroundImage: bgImg,
+      backgroundSize: config.style.backgroundSize || '100%',
+      backgroundRepeat: config.style.backgroundRepeat || 'repeat',
+      backgroundPositon: config.style.backgroundPositon || 'center'
     })
   }
 
@@ -84,9 +92,42 @@
     this.props.updateConfig(config)
   }
 
+  backgroundSizeChange = (val) => {
+    this.setState({
+      backgroundSize: val
+    })
+
+    let config = fromJS(this.props.config).toJS()
+    config.style.backgroundSize = val
+
+    this.props.updateConfig(config)
+  }
+
+  backgroundRepeatChange = (val) => {
+    this.setState({
+      backgroundRepeat: val
+    })
+
+    let config = fromJS(this.props.config).toJS()
+    config.style.backgroundRepeat = val
+
+    this.props.updateConfig(config)
+  }
+
+  backgroundPositonChange = (val) => {
+    this.setState({
+      backgroundPositon: val
+    })
+
+    let config = fromJS(this.props.config).toJS()
+    config.style.backgroundPositon = val
+
+    this.props.updateConfig(config)
+  }
+
   render () {
     const { config } = this.props
-    const { backgroundColor, backgroundImage } = this.state
+    const { backgroundColor, backgroundImage, backgroundSize, backgroundRepeat, backgroundPositon } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -113,6 +154,30 @@
           <Form.Item colon={false} label="鑳屾櫙鍥�">
             <SourceComponent value={backgroundImage} type="" placement="right" onChange={this.imgChange}/>
           </Form.Item>
+          <Form.Item colon={false} label="姣斾緥">
+            <Select defaultValue={backgroundSize} onChange={this.backgroundSizeChange}>
+              <Option value="100%">100%</Option>
+              <Option value="100% 100%">100% 100%</Option>
+              <Option value="auto 100%">auto 100%</Option>
+              <Option value="contain">contain</Option>
+              <Option value="cover">cover</Option>
+            </Select>
+          </Form.Item>
+          <Form.Item colon={false} label="閲嶅">
+            <Select defaultValue={backgroundRepeat} onChange={this.backgroundRepeatChange}>
+              <Option value="repeat">repeat</Option>
+              <Option value="no-repeat">no-repeat</Option>
+              <Option value="repeat-x">repeat-x</Option>
+              <Option value="repeat-y">repeat-y</Option>
+            </Select>
+          </Form.Item>
+          <Form.Item colon={false} label="浣嶇疆">
+            <Select defaultValue={backgroundPositon} onChange={this.backgroundPositonChange}>
+              <Option value="center">center</Option>
+              <Option value="top">top</Option>
+              <Option value="bottom">bottom</Option>
+            </Select>
+          </Form.Item>
           <p 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
new file mode 100644
index 0000000..028d757
--- /dev/null
+++ b/src/pc/components/login/normal-login/index.jsx
@@ -0,0 +1,170 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover } from 'antd'
+
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import asyncComponent from '@/utils/asyncComponent'
+
+import MKEmitter from '@/utils/events.js'
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import { resetStyle } from '@/utils/utils-custom.js'
+import './index.scss'
+
+const LoginForm = asyncComponent(() => import('./loginform'))
+const WrapComponent = asyncIconComponent(() => import('../wrapsetting'))
+
+class PropCardEditComponent extends Component {
+  static propTpyes = {
+    card: PropTypes.object,
+    deletecomponent: PropTypes.func,
+    updateConfig: PropTypes.func,
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    card: null,
+    back: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { card } = this.props
+
+    if (card.isNew) {
+      let ismob = sessionStorage.getItem('appType') === 'mob'
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        dataName: card.dataName || '',
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        wrap: { name: card.name, width: card.width || 24, loginWays: ['uname_pwd'] },
+        style: { background: '#ffffff', width: '330px', borderRadius: '4px', marginLeft: '55vw'},
+        loginWays: [
+          {type: 'uname_pwd', label: '璐﹀彿瀵嗙爜', remember: 'true', labelStyle: {}, submitStyle: {}, submitLabel: '鐧诲綍'},
+          {type: 'sms_vcode', label: '鐭俊楠岃瘉鐮�', labelStyle: {}, submitStyle: {}, submitLabel: '鐧诲綍'}
+        ]
+      }
+
+      if (ismob) {
+        delete _card.style.width
+        delete _card.style.borderRadius
+        delete _card.style.marginLeft
+        
+        _card.style.paddingTop = '20px'
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['width', 'background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card, dict } = this.state
+    let style = resetStyle(card.style)
+    if (card.wrap.maxWidth) {
+      style.maxWidth = card.wrap.maxWidth
+      let left = style.marginLeft && style.marginLeft !== '0px' ? style.marginLeft : 'auto'
+      let right = style.marginRight && style.marginRight !== '0px' ? style.marginRight : 'auto'
+      style.margin = (style.marginTop || 0) + ' ' + right + ' ' + (style.marginBottom || 0) + ' ' + left
+      delete style.marginLeft
+      delete style.marginRight
+      delete style.marginTop
+      delete style.marginBottom
+    }
+
+    return (
+      <div className="login-edit-box" style={style} onClick={this.clickComponent} id={card.uuid}>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
+          </div>
+        } trigger="hover">
+          <Icon type="tool" />
+        </Popover>
+        <LoginForm loginWays={card.loginWays} wrap={card.wrap} menuId={card.uuid} dict={dict} />
+      </div>
+    )
+  }
+}
+
+export default PropCardEditComponent
\ No newline at end of file
diff --git a/src/pc/components/login/normal-login/index.scss b/src/pc/components/login/normal-login/index.scss
new file mode 100644
index 0000000..f87a9a8
--- /dev/null
+++ b/src/pc/components/login/normal-login/index.scss
@@ -0,0 +1,138 @@
+.login-edit-box {
+  display: inline-block;
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+  
+  .card-control {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    .anticon-tool {
+      right: auto;
+      left: 1px;
+      padding: 1px;
+    }
+  }
+  .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);
+  }
+  .login-edit-form {
+    border-radius: inherit;
+    .ant-form-item {
+      font-size: 16px;
+      margin: 0 15px 15px;
+      .ant-input {
+        height: 35px;
+        background: transparent;
+      }
+    }
+    button:not(.vercode) {
+      width: 100%;
+      height: 40px;
+      line-height: 1;
+      font-size: 18px;
+      margin-bottom: 25px;
+    }
+    .ant-form-item:last-child {
+      margin-bottom: 0;
+    }
+  }
+  .login-way-wrap {
+    height: 50px;
+    line-height: 50px;
+    margin-bottom: 10px;
+    display: flex;
+    border-radius: inherit;
+    .login-way {
+      flex: 1;
+      width: 50%;
+      font-size: 17px;
+      text-align: center;
+      white-space: nowrap;
+      text-overflow: ellipsis;
+      overflow: hidden;
+      padding: 0 16px;
+      transition: all 0.3s;
+      border: 1px solid transparent;
+      border-top: 0!important;
+    }
+    .login-way.active, .login-way:hover {
+      color: #1890ff;
+    }
+    .login-way:not(.active) {
+      cursor: pointer;
+      background: #fafafa;
+      border: 1px solid #e8e8e8;
+    }
+    .login-way:first-child {
+      border-left: 0;
+      border-top-left-radius: inherit;
+    }
+    .login-way:last-child {
+      border-right: 0;
+      border-top-right-radius: inherit;
+    }
+  }
+  .login-way-wrap.simple {
+    .login-way {
+      font-size: 18px;
+      text-align: left;
+      padding: 0 15px;
+      line-height: 60px;
+    }
+  }
+}
+.login-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.login-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
+
+.mk-mob-view .login-edit-box {
+  display: block;
+  .login-way-wrap.simple {
+    display: none;
+  }
+  .login-way-wrap {
+    padding: 0 15px;
+    border-radius: 0;
+    .login-way {
+      border: 0;
+      background: transparent!important;
+      transition: all 0.3s;
+      border-bottom: 2px solid transparent;
+    }
+    .login-way.active, .login-way:hover {
+      color: #1890ff;
+    }
+    .login-way.active {
+      border-bottom: 2px solid #1890ff;
+    }
+  }
+  .ant-input {
+    border: 0;
+    border-radius: 0;
+    border-bottom: 1px solid #d9d9d9;
+    box-shadow: none!important;
+  }
+  .ant-input-group-addon {
+    border: 0;
+    border-radius: 0;
+  }
+}
diff --git a/src/pc/components/login/normal-login/loginform.jsx b/src/pc/components/login/normal-login/loginform.jsx
new file mode 100644
index 0000000..20b96a4
--- /dev/null
+++ b/src/pc/components/login/normal-login/loginform.jsx
@@ -0,0 +1,139 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Form, Icon, Input, Button, Checkbox } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class LoginTabForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    menuId: PropTypes.string,
+    loginWays: PropTypes.array,
+    wrap: PropTypes.array,
+  }
+
+  state = {
+    activeWay: null,
+    loginWays: [],
+  }
+
+  UNSAFE_componentWillMount () {
+    const { loginWays, wrap } = this.props
+
+    let _loginWays = []
+    loginWays.forEach(item => {
+      if (!wrap.loginWays || wrap.loginWays.includes(item.type)) {
+        _loginWays.push(item)
+      }
+    })
+
+    this.setState({
+      loginWays: _loginWays,
+      activeWay: _loginWays[0],
+    })
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { loginWays, wrap } = this.props
+
+    if (!is(fromJS(wrap), fromJS(nextProps.wrap))) {
+      let _loginWays = []
+      loginWays.forEach(item => {
+        if (!nextProps.wrap.loginWays || nextProps.wrap.loginWays.includes(item.type)) {
+          _loginWays.push(item)
+        }
+      })
+
+      this.setState({
+        loginWays: _loginWays,
+        activeWay: _loginWays[0],
+      })
+    }
+  }
+
+  onChangeTab = (activeWay) => {
+    this.setState({activeWay})
+  }
+
+  changeMenu = () => {
+    const { wrap, menuId } = this.props
+
+    MKEmitter.emit('changeEditMenu', {
+      MenuID: wrap.link === 'linkmenu' ? wrap.linkmenu : menuId,
+      copyMenuId: '',
+      MenuNo: '',
+      MenuName: ''
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { activeWay, loginWays } = this.state
+
+    return (
+      <Form className="login-edit-form">
+        <div className={'login-way-wrap ' + (loginWays.length === 1 ? 'simple' : '')}>
+          {loginWays.map(item => (
+            <div className={'login-way' + (activeWay.type === item.type ? ' active' : '')} onClick={() => this.onChangeTab(item)} key={item.type}>{item.label}</div>
+          ))}
+        </div>
+        {activeWay.type === 'uname_pwd' ? <div className="form-item-wrap">
+          <Form.Item>
+            <Input
+              prefix={<Icon type="user" style={{ color: 'rgba(0,0,0,.25)' }} />}
+              placeholder="鐢ㄦ埛鍚�"
+              autoComplete="off"
+            />
+          </Form.Item>
+          <Form.Item>
+            <Input.Password placeholder="瀵嗙爜" prefix={<Icon type="lock" style={{ color: 'rgba(0,0,0,.25)' }} />} />
+          </Form.Item>
+          <Form.Item className="minline">
+            <Checkbox>璁颁綇瀵嗙爜</Checkbox>
+          </Form.Item>
+          <Form.Item className="btn-login">
+            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="login-form-button">
+              鐧诲綍
+            </Button>
+          </Form.Item>
+        </div> : null}
+        {activeWay.type === 'sms_vcode' ? <div className="form-item-wrap">
+          <Form.Item>
+            <Input
+              placeholder="鎵嬫満鍙�"
+              autoComplete="off"
+            />
+          </Form.Item>
+          <Form.Item style={{marginBottom: '35px'}}>
+            <Input
+              addonAfter={
+                <Button type="link" className="vercode" size="small">
+                  鑾峰彇楠岃瘉鐮�
+                </Button>
+              }
+              placeholder="楠岃瘉鐮�"
+              autoComplete="off"
+            />
+          </Form.Item>
+          <Form.Item className="btn-login">
+            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="login-form-button">
+              鐧诲綍
+            </Button>
+          </Form.Item>
+        </div> : null}
+      </Form>
+    )
+  }
+}
+
+export default LoginTabForm
\ No newline at end of file
diff --git a/src/pc/components/login/wrapsetting/index.jsx b/src/pc/components/login/wrapsetting/index.jsx
new file mode 100644
index 0000000..9c0ac72
--- /dev/null
+++ b/src/pc/components/login/wrapsetting/index.jsx
@@ -0,0 +1,81 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Modal } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import './index.scss'
+
+class DataSource extends Component {
+  static propTpyes = {
+    config: PropTypes.any,
+    updateConfig: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    wrap: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+
+    this.setState({wrap: fromJS(config.wrap).toJS()})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  editDataSource = () => {
+    this.setState({
+      visible: true
+    })
+  }
+
+  verifySubmit = () => {
+    const { config } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+
+      this.setState({
+        wrap: res,
+        visible: false
+      })
+      this.props.updateConfig({...config, wrap: res})
+    })
+  }
+
+  render () {
+    const { visible, dict, wrap } = this.state
+
+    return (
+      <div className="model-menu-setting-wrap">
+        <Icon type="edit" title="缂栬緫" onClick={() => this.editDataSource()} />
+        <Modal
+          wrapClassName="popview-modal"
+          title="鐧诲綍璁剧疆"
+          visible={visible}
+          width={800}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            wrap={wrap}
+            inputSubmit={this.verifySubmit}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default DataSource
\ No newline at end of file
diff --git a/src/pc/components/login/wrapsetting/index.scss b/src/pc/components/login/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/pc/components/login/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/pc/components/login/wrapsetting/settingform/index.jsx b/src/pc/components/login/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..97042c8
--- /dev/null
+++ b/src/pc/components/login/wrapsetting/settingform/index.jsx
@@ -0,0 +1,270 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Tooltip, Icon, InputNumber, Select, Checkbox, notification, Radio } from 'antd'
+
+import StyleInput from '@/menu/stylecontroller/styleInput'
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
+    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+  }
+
+  state = {
+    roleList: [],
+    msgTemps: [],
+    appMenus: [],
+    link: this.props.wrap.link || 'menu'
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    let msgTemps = sessionStorage.getItem('msgTemplate')
+
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    if (msgTemps) {
+      try {
+        msgTemps = JSON.parse(msgTemps)
+      } catch {
+        msgTemps = []
+      }
+    } else {
+      msgTemps = []
+    }
+
+    let appMenus = sessionStorage.getItem('appMenus')
+    if (appMenus) {
+      try {
+        appMenus = JSON.parse(appMenus)
+      } catch {
+        appMenus = []
+      }
+    } else {
+      appMenus = []
+    }
+
+    this.setState({roleList, msgTemps, appMenus})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          if (values.loginWays.includes('sms_vcode') && !values.tempId) {
+            notification.warning({
+              top: 92,
+              message: '浣跨敤鐭俊楠岃瘉鐮佺櫥褰曟椂锛岄渶瑕侀�夋嫨鐭俊妯℃澘锛�',
+              duration: 5
+            })
+            return
+          }
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  handleSubmit = (e) => {
+    e.preventDefault()
+
+    if (this.props.inputSubmit) {
+      this.props.inputSubmit()
+    }
+  }
+
+  render() {
+    const { wrap } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { roleList, msgTemps, appMenus, link } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <div className="model-menu-setting-form">
+        <Form {...formItemLayout}>
+          <Row gutter={24}>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {getFieldDecorator('name', {
+                  initialValue: wrap.name,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '缁勪欢鍚嶇О!'
+                    }
+                  ]
+                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="鐧诲綍鏂瑰紡">
+                {getFieldDecorator('loginWays', {
+                  initialValue: wrap.loginWays || [],
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鐧诲綍鏂瑰紡!'
+                    }
+                  ]
+                })(
+                  <Checkbox.Group
+                    options={[
+                      { label: '璐﹀彿瀵嗙爜', value: 'uname_pwd' },
+                      { label: '鐭俊楠岃瘉鐮�', value: 'sms_vcode' },
+                    ]}
+                  />
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐧诲綍妗嗙殑鏈�澶у搴﹀�笺��">
+                  <Icon type="question-circle" />
+                  鏈�澶у搴�
+                </Tooltip>
+              }>
+                {getFieldDecorator('maxWidth', {
+                  initialValue: wrap.maxWidth || ''
+                })(<InputNumber min={100} max={2000} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="缁勪欢鍗犵敤鐨勬渶灏忛珮搴︼紝鐢ㄤ簬椤甸潰甯冨眬銆�">
+                  <Icon type="question-circle" />
+                  楂樺害
+                </Tooltip>
+              }>
+                {getFieldDecorator('height', {
+                  initialValue: wrap.height
+                })(<StyleInput options={['px', 'vh', 'vw', '%']}/>)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="閾炬帴">
+                {getFieldDecorator('link', {
+                  initialValue: wrap.link || 'menu'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({link: e.target.value})}>
+                    <Radio key="menu" value="menu"> 鑿滃崟 </Radio>
+                    <Radio key="linkmenu" value="linkmenu"> 鍏宠仈鑿滃崟 </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {link === 'linkmenu' ? <Col span={12}>
+              <Form.Item label="鍏宠仈鑿滃崟">
+                {getFieldDecorator('linkmenu', {
+                  initialValue: wrap.linkmenu || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鑿滃崟!'
+                    }
+                  ]
+                })(
+                  <Select
+                    showSearch
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {appMenus.map(option =>
+                      <Select.Option key={option.MenuID} value={option.MenuID}>{option.MenuName}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {/* $楠岃瘉鐮�$  $mob$  $send_type$ */}
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="鐭俊妯℃澘鍙湪绠$悊绯荤粺 HS-濂囦簯鐭俊妯℃澘 澶勬坊鍔犮��">
+                  <Icon type="question-circle" />
+                  鐭俊妯℃澘
+                </Tooltip>
+              }>
+                {getFieldDecorator('tempId', {
+                  initialValue: wrap.tempId || ''
+                })(
+                  <Select
+                    showSearch
+                    allowClear
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {msgTemps.map(option =>
+                      <Select.Option key={option.ID} value={option.ID}>{option.SignName + ' - ' + option.TemplateCode}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.blacklist || []
+                })(
+                  <Select
+                    showSearch
+                    mode="multiple"
+                    filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+                  >
+                    {roleList.map(option =>
+                      <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
+                    )}
+                  </Select>
+                )}
+              </Form.Item>
+            </Col>
+          </Row>
+        </Form>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/pc/components/login/wrapsetting/settingform/index.scss b/src/pc/components/login/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..159130b
--- /dev/null
+++ b/src/pc/components/login/wrapsetting/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/pc/components/navbar/normal-navbar/index.jsx b/src/pc/components/navbar/normal-navbar/index.jsx
index efa2b56..b70d77b 100644
--- a/src/pc/components/navbar/normal-navbar/index.jsx
+++ b/src/pc/components/navbar/normal-navbar/index.jsx
@@ -138,8 +138,11 @@
   }
 
   changeMenu = (menu) => {
+    if (menu.property === 'link') {
+      window.open(menu.link)
+      return
+    }
     MKEmitter.emit('changeEditMenu', {
-      fixed: menu.property === 'menu',
       MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
       copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
       MenuNo: menu.MenuNo,
@@ -149,10 +152,15 @@
 
   changeLogoMenu = () => {
     const { card } = this.state
-
-    if (!card.wrap.logolink) return
-
-    MKEmitter.emit('changeEditMenu', {MenuID: card.wrap.logolink})
+  
+    if (card.wrap.property === 'linkmenu') {
+      MKEmitter.emit('changeEditMenu', {
+        MenuID: card.wrap.linkmenu,
+        copyMenuId: '',
+        MenuNo: '',
+        MenuName: ''
+      })
+    }
   }
 
   render() {
diff --git a/src/pc/components/navbar/normal-navbar/linksetting/linkform/index.jsx b/src/pc/components/navbar/normal-navbar/linksetting/linkform/index.jsx
index 7fc5a87..1a29300 100644
--- a/src/pc/components/navbar/normal-navbar/linksetting/linkform/index.jsx
+++ b/src/pc/components/navbar/normal-navbar/linksetting/linkform/index.jsx
@@ -112,17 +112,6 @@
               )}
             </Form.Item>
           </Col>
-          {property === 'link' ? <Col span={22}>
-            <Form.Item label="閾炬帴鍦板潃">
-              {getFieldDecorator('link', {
-                initialValue: menu.link || '',
-                rules: [{
-                  required: true,
-                  message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
-                }]
-              })(<TextArea rows={2} />)}
-            </Form.Item>
-          </Col> : null}
           <Col span={22}>
             <Form.Item label="鎵撳紑鏂瑰紡">
               {getFieldDecorator('open', {
@@ -135,6 +124,17 @@
               )}
             </Form.Item>
           </Col>
+          {property === 'link' ? <Col span={22}>
+            <Form.Item label="閾炬帴鍦板潃">
+              {getFieldDecorator('link', {
+                initialValue: menu.link || '',
+                rules: [{
+                  required: true,
+                  message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
+                }]
+              })(<TextArea rows={2} />)}
+            </Form.Item>
+          </Col> : null}
           {property === 'linkmenu' ? <Col span={22}>
             <Form.Item label={
               <Tooltip placement="topLeft" title="鍏宠仈褰撳墠app涓凡鏈夌殑鑿滃崟銆�">
diff --git a/src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx b/src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx
index fad6b76..2206100 100644
--- a/src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx
+++ b/src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx
@@ -120,8 +120,8 @@
               })(
                 <Radio.Group onChange={this.changeProperty}>
                   <Radio value="menu">鑿滃崟</Radio>
-                  <Radio value="link">閾炬帴</Radio>
                   <Radio value="linkmenu">鍏宠仈鑿滃崟</Radio>
+                  <Radio value="link">閾炬帴</Radio>
                   {menu.level === 1 || menu.level === 2 ? <Radio value="classify">鍒嗙被</Radio> : null}
                 </Radio.Group>
               )}
@@ -139,17 +139,6 @@
               )}
             </Form.Item>
           </Col>
-          {property === 'link' ? <Col span={22}>
-            <Form.Item label="閾炬帴鍦板潃">
-              {getFieldDecorator('link', {
-                initialValue: menu.link || '',
-                rules: [{
-                  required: true,
-                  message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
-                }]
-              })(<TextArea rows={2} />)}
-            </Form.Item>
-          </Col> : null}
           {property !== 'classify' ? <Col span={22}>
             <Form.Item label="鎵撳紑鏂瑰紡">
               {getFieldDecorator('open', {
@@ -160,6 +149,17 @@
                   <Radio value="self">褰撳墠绐楀彛</Radio>
                 </Radio.Group>
               )}
+            </Form.Item>
+          </Col> : null}
+          {property === 'link' ? <Col span={22}>
+            <Form.Item label="閾炬帴鍦板潃">
+              {getFieldDecorator('link', {
+                initialValue: menu.link || '',
+                rules: [{
+                  required: true,
+                  message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
+                }]
+              })(<TextArea rows={2} />)}
             </Form.Item>
           </Col> : null}
           {property === 'linkmenu' ? <Col span={22}>
@@ -192,7 +192,7 @@
               {getFieldDecorator('copyMenuId', {
                 initialValue: menu.copyMenuId || ''
               })(
-                <Select>
+                <Select allowClear>
                   {appMenus.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
                 </Select>
               )}
diff --git a/src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx b/src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx
index 92d751b..8174d84 100644
--- a/src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx
+++ b/src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx
@@ -5,7 +5,7 @@
 
 import MenuForm from '../menuform'
 import Utils from '@/utils/utils.js'
-import MKEmitter from '@/utils/events.js'
+// import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 const { confirm } = Modal
@@ -97,7 +97,6 @@
         let _data = _this.state.data.filter(item => item.MenuID !== record.MenuID)
         _this.setState({data: _data})
         _this.props.menuUpdate({...menu, sublist: _data})
-        MKEmitter.emit('delButtons', [record.MenuID])
       },
       onCancel() {}
     })
@@ -124,7 +123,7 @@
 
     this.menuRef.handleConfirm().then(res => {
       let _menu = {...editMenu, ...res}
-      let _data = this.state.data
+      let _data = fromJS(this.state.data).toJS()
       if (!_menu.MenuID) {
         _menu.MenuID = Utils.getuuid()
         _data.push(_menu)
@@ -137,8 +136,26 @@
           }
         })
       }
-      this.setState({data: _data, editMenu: null, visible: false})
-      this.props.menuUpdate({...menu, sublist: _data})
+      if (editMenu.MenuID && editMenu.property === 'menu' && _menu.property !== 'menu') {
+        const _this = this
+        confirm({
+          content: '鑿滃崟灞炴�х敱鈥滆彍鍗曗�濆垏鎹㈣嚦鍏朵粬绫诲瀷鏃讹紝鑿滃崟灏嗚閲嶇疆锛屽嵆瑙i櫎涔嬪墠鑿滃崟鐨勭粦瀹氬叧绯伙紝纭畾淇敼鍚楋紵',
+          onOk() {
+            _data = _data.map(item => {
+              if (item.MenuID === _menu.MenuID) {
+                item.MenuID = Utils.getuuid()
+              }
+              return item
+            })
+            _this.setState({data: _data, editMenu: null, visible: false})
+            _this.props.menuUpdate({...menu, sublist: _data})
+          },
+          onCancel() {}
+        })
+      } else {
+        this.setState({data: _data, editMenu: null, visible: false})
+        this.props.menuUpdate({...menu, sublist: _data})
+      }
     })
   }
 
@@ -263,12 +280,6 @@
         let _data = _this.state.data.filter(item => item.MenuID !== record.MenuID)
         _this.setState({data: _data})
         _this.props.menuUpdate({...menu, sublist: _data})
-
-        let uuids = [record.MenuID]
-        record.sublist && record.sublist.forEach(item => {
-          uuids.push(item.MenuID)
-        })
-        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -295,7 +306,7 @@
 
     this.menuRef.handleConfirm().then(res => {
       let _menu = {...editMenu, ...res}
-      let _data = this.state.data
+      let _data = fromJS(this.state.data).toJS()
       if (!_menu.MenuID) {
         _menu.MenuID = Utils.getuuid()
         _data.push(_menu)
@@ -308,8 +319,26 @@
           }
         })
       }
-      this.setState({data: _data, editMenu: null, visible: false})
-      this.props.menuUpdate({...menu, sublist: _data})
+      if (editMenu.MenuID && editMenu.property === 'menu' && _menu.property !== 'menu') {
+        const _this = this
+        confirm({
+          content: '鑿滃崟灞炴�х敱鈥滆彍鍗曗�濆垏鎹㈣嚦鍏朵粬绫诲瀷鏃讹紝鑿滃崟灏嗚閲嶇疆锛屽嵆瑙i櫎涔嬪墠鑿滃崟鐨勭粦瀹氬叧绯伙紝纭畾淇敼鍚楋紵',
+          onOk() {
+            _data = _data.map(item => {
+              if (item.MenuID === _menu.MenuID) {
+                item.MenuID = Utils.getuuid()
+              }
+              return item
+            })
+            _this.setState({data: _data, editMenu: null, visible: false})
+            _this.props.menuUpdate({...menu, sublist: _data})
+          },
+          onCancel() {}
+        })
+      } else {
+        this.setState({data: _data, editMenu: null, visible: false})
+        this.props.menuUpdate({...menu, sublist: _data})
+      }
     })
   }
 
@@ -444,16 +473,6 @@
       content: '',
       onOk() {
         _this.setState({data: data.filter(item => item.MenuID !== record.MenuID)})
-
-        let uuids = [record.MenuID]
-        record.sublist && record.sublist.forEach(item => {
-          uuids.push(item.MenuID)
-
-          item.sublist && item.sublist.forEach(cell => {
-            uuids.push(cell.MenuID)
-          })
-        })
-        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -479,22 +498,38 @@
 
     this.menuRef.handleConfirm().then(res => {
       let _menu = {...editMenu, ...res}
+      let _data = fromJS(data).toJS()
       if (!_menu.MenuID) {
         _menu.MenuID = Utils.getuuid()
-        this.setState({data: [...data, _menu], editMenu: null, visible: false})
+        _data.push(_menu)
       } else {
-        this.setState({
-          editMenu: null,
-          visible: false,
-          data: data.map(item => {
-            if (item.MenuID === _menu.MenuID) {
-              return _menu
-            } else {
-              return item
-            }
-          })
+        _data = _data.map(item => {
+          if (item.MenuID === _menu.MenuID) {
+            return _menu
+          } else {
+            return item
+          }
         })
       }
+
+      if (editMenu.MenuID && editMenu.property === 'menu' && _menu.property !== 'menu') {
+        const _this = this
+        confirm({
+          content: '鑿滃崟灞炴�х敱鈥滆彍鍗曗�濆垏鎹㈣嚦鍏朵粬绫诲瀷鏃讹紝鑿滃崟灏嗚閲嶇疆锛屽嵆瑙i櫎涔嬪墠鑿滃崟鐨勭粦瀹氬叧绯伙紝纭畾淇敼鍚楋紵',
+          onOk() {
+            _data = _data.map(item => {
+              if (item.MenuID === _menu.MenuID) {
+                item.MenuID = Utils.getuuid()
+              }
+              return item
+            })
+            _this.setState({data: _data, editMenu: null, visible: false})
+          },
+          onCancel() {}
+        })
+      } else {
+        this.setState({data: _data, editMenu: null, visible: false})
+      }
     })
   }
 
diff --git a/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx b/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
index b5d097d..3d066a8 100644
--- a/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
+++ b/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
@@ -6,6 +6,7 @@
 import './index.scss'
 
 const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
+const { TextArea } = Input
 
 class SettingForm extends Component {
   static propTpyes = {
@@ -16,7 +17,8 @@
   }
 
   state = {
-    appMenus: []
+    appMenus: [],
+    property: ''
   }
 
   UNSAFE_componentWillMount () {
@@ -31,7 +33,7 @@
       appMenus = []
     }
 
-    this.setState({appMenus})
+    this.setState({appMenus, property: this.props.wrap.property || ''})
   }
 
   handleConfirm = () => {
@@ -58,7 +60,7 @@
   render() {
     const { wrap } = this.props
     const { getFieldDecorator } = this.props.form
-    const { appMenus } = this.state
+    const { appMenus, property } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -141,22 +143,51 @@
               </Form.Item>
             </Col>
             <Col span={12}>
+              <Form.Item label="logo灞炴��">
+                {getFieldDecorator('property', {
+                  initialValue: wrap.property || ''
+                })(
+                  <Radio.Group onChange={(e) => this.setState({property: e.target.value})} style={{whiteSpace: 'nowrap'}}>
+                    <Radio value="">绌�</Radio>
+                    <Radio value="linkmenu">鍏宠仈鑿滃崟</Radio>
+                    <Radio value="link">閾炬帴</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {property === 'linkmenu' ? <Col span={12}>
               <Form.Item label="logo閾炬帴">
-                {getFieldDecorator('logolink', {
-                  initialValue: wrap.logolink || ''
+                {getFieldDecorator('linkmenu', {
+                  initialValue: wrap.linkmenu || '',
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鍏宠仈鑿滃崟!'
+                    }
+                  ]
                 })(
                   <Select
                     showSearch
                     filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                   >
-                    <Select.Option key="empty" intid={''} value={''}>鏃�</Select.Option>
                     {appMenus.map(option =>
                       <Select.Option key={option.MenuID} value={option.MenuID}>{option.MenuName}</Select.Option>
                     )}
                   </Select>
                 )}
               </Form.Item>
-            </Col>
+            </Col> : null}
+            {property === 'link' ? <Col span={24}>
+              <Form.Item label="logo閾炬帴" className="textarea">
+                {getFieldDecorator('link', {
+                  initialValue: wrap.link || '',
+                  rules: [{
+                    required: true,
+                    message: '璇疯緭鍏ラ摼鎺ュ湴鍧�!'
+                  }]
+                })(<TextArea rows={2} />)}
+              </Form.Item>
+            </Col> : null}
             <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="瀛樺湪鐧诲綍涓斿彇鍒扮櫥褰曚俊鎭椂锛屾樉绀虹敤鎴峰ご鍍忋�佺敤鎴峰悕鍙婇��鍑恒��">
@@ -174,6 +205,23 @@
                 )}
               </Form.Item>
             </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="榛樿闅愯棌鑿滃崟鏍忥紝榧犳爣鍦ㄩ潬杩戦《閮ㄦ椂鏄剧ず銆�">
+                  <Icon type="question-circle" />
+                  鎮诞鏄剧ず
+                </Tooltip>
+              }>
+                {getFieldDecorator('hover', {
+                  initialValue: wrap.hover || 'false'
+                })(
+                  <Radio.Group>
+                    <Radio value="true">鍚敤</Radio>
+                    <Radio value="false">涓嶅惎鐢�</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
           </Row>
         </Form>
       </div>
diff --git a/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss b/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
index 159130b..25eecb7 100644
--- a/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
+++ b/src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
@@ -8,4 +8,12 @@
   .ant-input-number {
     width: 100%;
   }
+  .ant-form-item.textarea {
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/pc/createview/index.jsx b/src/pc/createview/index.jsx
new file mode 100644
index 0000000..9dd88d5
--- /dev/null
+++ b/src/pc/createview/index.jsx
@@ -0,0 +1,201 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Button, Modal, notification } from 'antd'
+import moment from 'moment'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import Utils from '@/utils/utils.js'
+import MenuUtils from '@/utils/utils-custom.js'
+import SettingForm from './settingform'
+import Api from '@/api'
+import './index.scss'
+
+class CreateView extends Component {
+  static propTpyes = {
+    resetmenu: PropTypes.func
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    loading: false
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  verifySubmit = () => {
+    this.verifyRef.handleConfirm().then(res => {
+      this.setState({
+        loading: true
+      })
+
+      let parMenuId = sessionStorage.getItem('kei_no') + sessionStorage.getItem('typename') + sessionStorage.getItem('lang')
+      let menuId = Utils.getuuid()
+      let config = {
+        version: 1.0,
+        uuid: menuId,
+        MenuID: menuId,
+        Template: 'webPage',
+        enabled: false,
+        MenuName: res.MenuName || '',
+        MenuNo: res.MenuNo || '',
+        tables: [],
+        components: [],
+        viewType: 'menu',
+        style: {}
+      }
+
+      let param = {
+        func: 'sPC_TrdMenu_AddUpt',
+        FstID: parMenuId,
+        SndID: parMenuId,
+        ParentID: parMenuId,
+        MenuID: menuId,
+        MenuNo: res.MenuNo || '',
+        EasyCode: '',
+        Template: 'webPage',
+        TypeCharOne: sessionStorage.getItem('kei_no'),
+        Typename: sessionStorage.getItem('typename'),
+        MenuName: res.MenuName || '',
+        PageParam: JSON.stringify({Template: 'webPage'}),
+        open_edition: '',
+        LText: '',
+        LTexttb: ''
+      }
+
+      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+      param.secretkey = Utils.encrypt('', param.timestamp)
+      
+      if (!res.copymenuId) {
+        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
+
+        Api.getSystemConfig(param).then(result => {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          } else {
+            notification.success({
+              top: 92,
+              message: '鍒涘缓鎴愬姛',
+              duration: 5
+            })
+          }
+
+          this.setState({
+            visible: false,
+            loading: false
+          })
+
+          this.props.resetmenu()
+        })
+      } else {
+        Api.getSystemConfig({
+          func: 'sPC_Get_LongParam',
+          TypeCharOne: sessionStorage.getItem('kei_no'),
+          typename: sessionStorage.getItem('typename') || 'pc',
+          MenuID: res.copymenuId
+        }).then(result => {
+          if (!result.status) {
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+            this.setState({
+              loading: false
+            })
+            return
+          }
+
+          let _config = null
+          try {
+            _config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
+          } catch (e) {
+            console.warn('Parse Failure')
+            _config = null
+          }
+  
+          if (!_config) {
+            notification.warning({
+              top: 92,
+              message: '鏈幏鍙栧埌閰嶇疆淇℃伅锛�',
+              duration: 5
+            })
+            this.setState({
+              loading: false
+            })
+            return
+          }
+
+          if (_config.components) {
+            config.components = MenuUtils.resetConfig(_config.components)
+            config.tables = _config.tables || []
+            config.style = _config.style || {}
+          }
+  
+          param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
+
+          Api.getSystemConfig(param).then(result => {
+            if (!result.status) {
+              notification.warning({
+                top: 92,
+                message: result.message,
+                duration: 5
+              })
+            } else {
+              notification.success({
+                top: 92,
+                message: '鍒涘缓鎴愬姛',
+                duration: 5
+              })
+            }
+
+            this.setState({
+              visible: false,
+              loading: false
+            })
+
+            this.props.resetmenu()
+          })
+        })
+      }
+    })
+  }
+
+  render () {
+    const { config } = this.props
+    const { visible, dict, loading } = this.state
+
+    return (
+      <div className="create-view">
+        <Button icon="plus" className="mk-border-green" onClick={() => {this.setState({visible: true, loading: false})}}>鏂板缓椤甸潰</Button>
+        <Modal
+          title="鏂板缓椤甸潰"
+          visible={visible}
+          width={500}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          confirmLoading={loading}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            config={config}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default CreateView
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/pc/createview/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/pc/createview/index.scss
diff --git a/src/pc/createview/settingform/index.jsx b/src/pc/createview/settingform/index.jsx
new file mode 100644
index 0000000..87ee449
--- /dev/null
+++ b/src/pc/createview/settingform/index.jsx
@@ -0,0 +1,107 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select, Input } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,      // 瀛楀吀椤�
+  }
+
+  state = {
+    appMenus: []
+  }
+
+  UNSAFE_componentWillMount () {
+    let appMenus = sessionStorage.getItem('appMenus')
+    if (appMenus) {
+      try {
+        appMenus = JSON.parse(appMenus)
+      } catch {
+        appMenus = []
+      }
+    } else {
+      appMenus = []
+    }
+
+    this.setState({appMenus})
+  }
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { appMenus } = this.state
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout}>
+        <Row gutter={24}>
+          <Col span={20}>
+            <Form.Item label="鑿滃崟鍚嶇О">
+              {getFieldDecorator('MenuName', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + '鑿滃崟鍚嶇О!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={20}>
+            <Form.Item label="鑿滃崟鍙傛暟">
+              {getFieldDecorator('MenuNo', {
+                initialValue: '',
+                rules: [
+                  {
+                    required: true,
+                    message: this.props.dict['form.required.input'] + '鑿滃崟鍙傛暟!'
+                  }
+                ]
+              })(<Input placeholder="" autoComplete="off" />)}
+            </Form.Item>
+          </Col>
+          <Col span={20}>
+            <Form.Item label="澶嶅埗鑿滃崟">
+              {getFieldDecorator('copymenuId', {
+                initialValue: ''
+              })(
+                <Select allowClear showSearch filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
+                  {appMenus.map(option =>
+                    <Select.Option key={option.MenuID} value={option.MenuID}>{option.MenuName}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/pc/createview/settingform/index.scss b/src/pc/createview/settingform/index.scss
new file mode 100644
index 0000000..159130b
--- /dev/null
+++ b/src/pc/createview/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/pc/menushell/card.jsx b/src/pc/menushell/card.jsx
index 843c8c5..c3311f6 100644
--- a/src/pc/menushell/card.jsx
+++ b/src/pc/menushell/card.jsx
@@ -7,9 +7,12 @@
 const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
 const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
 const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
+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 PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
+const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
 const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
 const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
@@ -17,8 +20,10 @@
 const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
 const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
 const NormalNavbar = asyncComponent(() => import('@/pc/components/navbar/normal-navbar'))
+const NormalLogin = asyncComponent(() => import('@/pc/components/login/normal-login'))
 const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
+const Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 
 const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
   const originalIndex = findCard(id).index
@@ -53,8 +58,20 @@
     style = { opacity: 0.3}
   }
   let col = ' ant-col ant-col-' + (card.width || 24)
-  if (card.type === 'navbar') {
-    col = ''
+  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 = () => {
@@ -68,6 +85,12 @@
       return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'pie') {
       return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'dashboard') {
+      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'tree') {
+      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'scatter') {
+      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'tabs') {
       return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'card' && card.subtype === 'datacard') {
@@ -88,12 +111,21 @@
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'login') {
+      return (<NormalLogin card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
-  return (
-    <div className={`mk-component-card ${col}`} ref={node => drag(drop(node))} style={style}>
-      {getCardComponent()}
-    </div>
-  )
+
+  if (card.type === 'navbar') {
+    return getCardComponent()
+  } else {
+    return (
+      <div className={`mk-component-card ${col}`} ref={node => drag(drop(node))} style={style}>
+        {getCardComponent()}
+      </div>
+    )
+  }
 }
 export default Card
diff --git a/src/pc/menushell/index.jsx b/src/pc/menushell/index.jsx
index 29be748..24e3910 100644
--- a/src/pc/menushell/index.jsx
+++ b/src/pc/menushell/index.jsx
@@ -19,6 +19,10 @@
     handleList({...menu, components: _cards})
     setCards(_cards)
   }
+
+  if (menu.components.length > cards.length) {
+    setCards(menu.components)
+  }
   
   const findCard = id => {
     const card = cards.filter(c => `${c.uuid}` === id)[0]
@@ -49,13 +53,16 @@
     let uuids = MenuUtils.getDelButtonIds(card)
 
     confirm({
-      title: `纭畾鍒犻櫎銆�${card.name}銆嬪悧锛焋,
+      title: `纭畾鍒犻櫎${card.name ? `銆�${card.name}銆媊 : '缁勪欢'}鍚楋紵`,
       content: hasComponent ? '褰撳墠缁勪欢涓惈鏈夊瓙缁勪欢锛�' : '',
       onOk() {
-        MKEmitter.emit('delButtons', uuids)
         const _cards = cards.filter(item => item.uuid !== card.uuid)
         handleList({...menu, components: _cards})
         setCards(_cards)
+
+        if (uuids.length === 0) return
+        
+        MKEmitter.emit('delButtons', uuids)
       },
       onCancel() {}
     })
@@ -102,7 +109,10 @@
         code: '鑷畾涔�',
         navbar: '瀵艰埅鏍�',
         carousel: '杞挱',
-        card: '鍗$墖'
+        dashboard: '浠〃鐩�',
+        tree: '鏍戝舰鍒楄〃',
+        card: '鍗$墖',
+        login: '鐧诲綍'
       }
       let i = 1
       
diff --git a/src/pc/modulesource/index.jsx b/src/pc/modulesource/index.jsx
index f4705bf..f84cdd7 100644
--- a/src/pc/modulesource/index.jsx
+++ b/src/pc/modulesource/index.jsx
@@ -53,6 +53,7 @@
             c_id: item.uuid,
             images: '',
             c_name: item.title,
+            typename: sessionStorage.getItem('appType') || '',
             long_param: '',
             del_type: 'Y'
           }).then(result => {
diff --git a/src/pc/modulesource/option.jsx b/src/pc/modulesource/option.jsx
index 8e94aea..b7e6090 100644
--- a/src/pc/modulesource/option.jsx
+++ b/src/pc/modulesource/option.jsx
@@ -12,12 +12,18 @@
 import Editor from '@/assets/mobimg/editor.png'
 import SandBox from '@/assets/mobimg/sandbox.png'
 import Pie1 from '@/assets/mobimg/ring.png'
+import Pie3 from '@/assets/mobimg/nest.png'
 import Pie2 from '@/assets/mobimg/nightingale.png'
 import Mainsearch from '@/assets/mobimg/mainsearch.png'
 import Navbar from '@/assets/mobimg/navbar.png'
 import Carousel from '@/assets/mobimg/carousel.png'
 import Carousel1 from '@/assets/mobimg/carousel1.png'
 import form from '@/assets/mobimg/form.png'
+import Login from '@/assets/mobimg/login.png'
+import dashboard from '@/assets/mobimg/dashboard.png'
+import ratioboard from '@/assets/mobimg/ratioboard.png'
+import scatter from '@/assets/mobimg/scatter.png'
+import tree from '@/assets/mobimg/tree.png'
 
 // 缁勪欢閰嶇疆淇℃伅
 export const menuOptions = [
@@ -26,19 +32,26 @@
   { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24 },
   { 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: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟', width: 24 },
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24 },
   { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24 },
   { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 },
   { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 },
+  { type: 'menu', url: tree, component: 'tree', subtype: 'normaltree', title: '鏍戝舰鍒楄〃', width: 12 },
   { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 },
   { 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 },
   { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '鐜浘', width: 12 },
+  { type: 'menu', url: Pie3, component: 'pie', subtype: 'nest', title: '宓屽楗煎浘', width: 12 },
+  { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
+  { type: 'menu', url: dashboard, component: 'dashboard', subtype: 'dashboard', title: '浠〃鐩�', width: 12 },
+  { type: 'menu', url: ratioboard, component: 'dashboard', subtype: 'ratioboard', title: '鍗犳瘮鍥�', width: 12 },
+  { type: 'menu', url: scatter, component: 'scatter', subtype: 'scatter', title: '鏁g偣鍥�', width: 24 },
   { type: 'menu', url: Editor, component: 'editor', subtype: 'brafteditor', title: '瀵屾枃鏈�', width: 24 },
   { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '鑷畾涔�', width: 24 },
-  { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '鍗椾竵鏍煎皵鍥�', width: 12 },
   { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '鍒嗙粍', width: 24 },
+  { type: 'menu', url: Login, component: 'login', subtype: 'normallogin', title: '鐧诲綍', width: 24 },
 ]
diff --git a/src/pc/quotecomponent/index.jsx b/src/pc/quotecomponent/index.jsx
index 11426ac..a0bb263 100644
--- a/src/pc/quotecomponent/index.jsx
+++ b/src/pc/quotecomponent/index.jsx
@@ -51,7 +51,7 @@
       Api.getSystemConfig({
         func: 'sPC_Get_LongParam',
         TypeCharOne: sessionStorage.getItem('kei_no'),
-        typename: 'pc',
+        typename: sessionStorage.getItem('typename') || 'pc',
         MenuID: res.keys_id
       }).then(result => {
         if (!result.status) {
diff --git a/src/pc/transfer/index.jsx b/src/pc/transfer/index.jsx
new file mode 100644
index 0000000..d2fb44e
--- /dev/null
+++ b/src/pc/transfer/index.jsx
@@ -0,0 +1,132 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Button, Modal, notification } from 'antd'
+
+import zhCN from '@/locales/zh-CN/model.js'
+import enUS from '@/locales/en-US/model.js'
+import SettingForm from './settingform'
+import Api from '@/api'
+import './index.scss'
+
+class TransferWrap extends Component {
+  static propTpyes = {
+    MenuID: PropTypes.string
+  }
+
+  state = {
+    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    visible: false,
+    loading: false,
+    translist: []
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  verifySubmit = () => {
+    const { MenuID } = this.props
+
+    this.verifyRef.handleConfirm().then(res => {
+      let param = {
+        func: 's_sVersionDetail_CloudAdd',
+        kei_no: sessionStorage.getItem('kei_no'),
+        kei_no_detail: sessionStorage.getItem('typename'),
+        lang: sessionStorage.getItem('lang'),
+        BID: res.VersionName,
+        VType: 'mob_menu',
+        TrdMenuID: MenuID
+      }
+
+      this.setState({
+        loading: true
+      })
+      
+      Api.getCloudConfig(param).then(result => {
+        if (result.status) {
+          notification.success({
+            top: 92,
+            message: '鎿嶄綔鎴愬姛锛�',
+            duration: 3
+          })
+          this.setState({
+            loading: false,
+            visible: false
+          })
+        } else {
+          this.setState({
+            loading: false
+          })
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        }
+      }, () => {
+        this.setState({
+          loading: false
+        })
+      })
+    })
+  }
+
+  getTransList = () => {
+    let param = {
+      func: 's_get_sVersion',
+      dataM: 'Y',
+      PageSize: 9999,
+      PageIndex: 1,
+      OrderCol: 'ID desc'
+    }
+
+    this.setState({
+      visible: true,
+      loading: false
+    })
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        this.setState({
+          translist: result.data
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  render () {
+    const { visible, dict, loading, translist } = this.state
+
+    return (
+      <div className="transfer-wrap">
+        <Button icon="pull-request" className="mk-border-green" onClick={this.getTransList}>浼犺緭鍙�</Button>
+        <Modal
+          title="鍔犲叆浼犺緭鍙�"
+          visible={visible}
+          width={500}
+          maskClosable={false}
+          okText={dict['model.submit']}
+          onOk={this.verifySubmit}
+          onCancel={() => { this.setState({ visible: false }) }}
+          confirmLoading={loading}
+          destroyOnClose
+        >
+          <SettingForm
+            dict={dict}
+            translist={translist}
+            wrappedComponentRef={(inst) => this.verifyRef = inst}
+          />
+        </Modal>
+      </div>
+    )
+  }
+}
+
+export default TransferWrap
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/pc/transfer/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/pc/transfer/index.scss
diff --git a/src/pc/transfer/settingform/index.jsx b/src/pc/transfer/settingform/index.jsx
new file mode 100644
index 0000000..40d2fb0
--- /dev/null
+++ b/src/pc/transfer/settingform/index.jsx
@@ -0,0 +1,69 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Select } from 'antd'
+
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    translist: PropTypes.array,
+  }
+
+  state = {}
+
+  handleConfirm = () => {
+    // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
+    return new Promise((resolve, reject) => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        } else {
+          reject(err)
+        }
+      })
+    })
+  }
+
+  render() {
+    const { getFieldDecorator } = this.props.form
+    const { translist } = this.props
+
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 6 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 18 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout}>
+        <Row gutter={24}>
+          <Col span={22}>
+            <Form.Item label="浼犺緭鍙�">
+              {getFieldDecorator('VersionName', {
+                initialValue: '',
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨浼犺緭鍙凤紒'
+                }]
+              })(
+                <Select showSearch filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}>
+                  {translist.map(option =>
+                    <Select.Option key={option.VersionName} value={option.VersionName}>{`${option.ProgramName}(${option.VersionName})`}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/pc/transfer/settingform/index.scss b/src/pc/transfer/settingform/index.scss
new file mode 100644
index 0000000..159130b
--- /dev/null
+++ b/src/pc/transfer/settingform/index.scss
@@ -0,0 +1,11 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+}
\ No newline at end of file
diff --git a/src/router/index.js b/src/router/index.js
index 8f61de0..f496dec 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -18,6 +18,8 @@
 const MenuDesign = asyncLoadComponent(() => import('@/views/menudesign'))
 const BillPrint = asyncLoadComponent(() => import('@/views/billprint'))
 const PrintT = asyncLoadComponent(() => import('@/views/printTemplate'))
+const Interface = asyncLoadComponent(() => import('@/views/interface'))
+const RoleManage = asyncLoadComponent(() => import('@/views/rolemanage'))
 
 const routers = [
   {path: '/login', name: 'login', component: Login, auth: false},
@@ -31,7 +33,9 @@
   {path: '/mobdesign/:param', name: 'mobdesign', component: MobDesign, auth: true},
   {path: '/menudesign/:param', name: 'menudesign', component: MenuDesign, auth: true},
   {path: '/billprint/:param', name: 'billprint', component: BillPrint, auth: true},
-  {path: '/paramsmain/:param', name: 'pmain', component: Main, auth: true}
+  {path: '/paramsmain/:param', name: 'pmain', component: Main, auth: true},
+  {path: '/role/:param', name: 'role', component: RoleManage, auth: true},
+  {path: '/interface', name: 'interface', component: Interface, auth: true}
 ]
 
 export default class RouteConfig extends Component {
@@ -56,28 +60,13 @@
           _param.role_id && sessionStorage.setItem('role_id', _param.role_id)
           _param.dataM && sessionStorage.setItem('localRole_id', _param.dataM)
           _param.Member_Level && sessionStorage.setItem('Member_Level', _param.Member_Level)
+          _param.ThirdMenu && sessionStorage.setItem('ThirdMenu', _param.ThirdMenu)
 
-          if (_param.mainlogo) {
-            window.GLOB.mainlogo = _param.mainlogo
-          }
-          if (_param.navBar) {
-            window.GLOB.navBar = _param.navBar
-          }
+          window.GLOB.mainlogo = _param.mainlogo || ''
+          window.GLOB.navBar = _param.navBar || ''
+
           if (_param.mstyle && styles[_param.mstyle]) {
             document.body.className = styles[_param.mstyle]
-          }
-          if (_param.MainMenu) {
-            sessionStorage.setItem('MainMenu', _param.MainMenu)
-          }
-          if (_param.SubMenu) {
-            sessionStorage.setItem('SubMenu', _param.SubMenu)
-          }
-          if (_param.ThirdMenu) {
-            sessionStorage.setItem('ThirdMenu', _param.ThirdMenu)
-          }
-          if (_param.param) {
-            _param.param.ThirdMenu = _param.ThirdMenu
-            sessionStorage.setItem('MenuParam', JSON.stringify(_param.param))
           }
         }
       } catch {
@@ -105,15 +94,7 @@
     return (
       <HashRouter>
         <Switch>
-          {
-            routers.map((item, index) => {
-              return (
-                <Route key={index} path={item.path} name={item.name} exact render={ props => {
-                  return this.controlRoute(item, props)
-                }}/>
-              )
-            })
-          }
+          {routers.map((item, index) => <Route key={index} path={item.path} name={item.name} exact render={ props => this.controlRoute(item, props)}/>)}
           <Redirect exact from="/" to="login"/>
           <Route component= {NotFound}/>
         </Switch>
diff --git a/src/tabviews/calendar/index.jsx b/src/tabviews/calendar/index.jsx
index 6141c25..b8b7c2a 100644
--- a/src/tabviews/calendar/index.jsx
+++ b/src/tabviews/calendar/index.jsx
@@ -48,6 +48,7 @@
     visible: false,       // 鏍囩椤垫帶鍒�
     triggerTime: '',      // 鐐瑰嚮鏃堕棿
     calendarYear: moment().format('YYYY'), // 鏃ュ巻骞翠唤
+    hasReqFields: false
   }
 
   /**
@@ -119,22 +120,17 @@
         config.easyCode = _curUserConfig.easyCode || config.easyCode || ''
       }
 
-      // 瀛楁鏉冮檺榛戝悕鍗曘�佸繀濉�佸瓧娈甸�忚
-      let valid = true
-      let roleId = sessionStorage.getItem('role_id') || ''
+      config.search = Utils.initSearchVal(config.search)
+
+      // 瀛楁閫忚
+      let hasReqFields = false
       config.search = config.search.map(item => {
-        item.oriInitval = item.initval
-        if (['text', 'select', 'link'].includes(item.type) && param && param.$searchkey === item.field) {
+        if (['text', 'select', 'link'].includes(item.type) && param.$searchkey === item.field) {
           item.initval = param.$searchval
         }
 
-        if (item.required === 'true' && !item.initval) {
-          valid = false
-        }
-
-        if (!item.blacklist || item.blacklist.length === 0) return item
-        if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-          item.Hide = 'true'
+        if (item.required) {
+          hasReqFields = true
         }
 
         return item
@@ -169,6 +165,27 @@
           config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
           _customScript = _customScript.replace(/@\$|\$@/ig, '')
         }
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+
+        regs.forEach(cell => {
+          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
+          _customScript = _customScript.replace(cell.reg, cell.value)
+        })
+
         if (config.urlFields) {
           let _param = param || {}
           config.urlFields.forEach(field => {
@@ -183,6 +200,7 @@
       }
 
       this.setState({
+        hasReqFields,
         BID: param && param.$BID ? param.$BID : '',
         loadingview: false,
         config: config,
@@ -190,9 +208,9 @@
         setting: config.setting,
         searchlist: config.search,
         arr_field: config.columns.map(item => item.field).join(','),
-        search: Utils.initMainSearch(config.search) // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+        search: Utils.initMainSearch(config.search)
       }, () => {
-        if (config.setting.onload !== 'false' && valid) { // 鍒濆鍖栧彲鍔犺浇
+        if (config.setting.onload !== 'false') {
           this.loadmaindata()
         }
       })
@@ -213,20 +231,15 @@
    * @description 涓昏〃鏁版嵁鍔犺浇
    */ 
   async loadmaindata () {
-    const { setting, search, BID } = this.state
+    const { setting, search, BID, hasReqFields } = this.state
     let param = ''
-    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
 
-    if (requireFields.length > 0) {
-      let labels = requireFields.map(item => item.label)
-      labels = Array.from(new Set(labels))
-
-      notification.warning({
-        top: 92,
-        message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
-        duration: 3
-      })
-      return
+    if (hasReqFields) {
+      let requireFields = search.filter(item => item.required && item.value === '')
+  
+      if (requireFields.length > 0) {
+        return
+      }
     }
 
     this.setState({
@@ -523,13 +536,13 @@
 
   render() {
     const { menuType } = this.props
-    const { BID, searchlist, loadingview, viewlost, config, loading, data, triggerTime } = this.state
+    const { BID, setting, searchlist, loadingview, viewlost, config, loading, data, triggerTime } = this.state
 
     return (
       <div className="calendar-page" id={this.state.ContainerId}>
         {loadingview && <Spin size="large" />}
         {searchlist && searchlist.length > 0 ?
-          <MainSearch BID={BID} searchlist={searchlist} menuType={menuType} refreshdata={this.refreshbysearch}/> : null
+          <MainSearch BID={BID} searchlist={searchlist} setting={setting} menuType={menuType} refreshdata={this.refreshbysearch}/> : null
         }
         {config && config.calendar ? <CalendarComponent calendar={config.calendar} loading={loading} data={data} triggerDate={this.triggerDate} changeDate={this.changeDate}/> : null}
         {menuType !== 'HS' ? <PagemsgComponent menu={{MenuName: this.props.MenuName, MenuNo: this.props.MenuNo}} config={config} dict={this.state.dict} /> : null}
diff --git a/src/tabviews/commontable/index.jsx b/src/tabviews/commontable/index.jsx
index ce0938e..763405f 100644
--- a/src/tabviews/commontable/index.jsx
+++ b/src/tabviews/commontable/index.jsx
@@ -176,16 +176,17 @@
       }
       let chartId = config.charts[0] ? config.charts[0].uuid : ''
 
-      // 瀛楁鏉冮檺榛戝悕鍗�
+      config.search = Utils.initSearchVal(config.search)
+
+      // 瀛楁閫忚鍙婂繀濉爣蹇�
+      let hasReqFields = false
       config.search = config.search.map(item => {
-        item.oriInitval = item.initval
         if (['text', 'select', 'link'].includes(item.type) && param && param.$searchkey === item.field) {
           item.initval = param.$searchval
         }
 
-        if (!item.blacklist || item.blacklist.length === 0) return item
-        if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-          item.Hide = 'true'
+        if (item.required) {
+          hasReqFields = true
         }
 
         return item
@@ -223,8 +224,7 @@
   
         if (!config.setting.execute) { // 榛樿sql 涓嶆墽琛屾椂 缃┖
           config.setting.dataresource = ''
-        }
-        if (/\s/.test(config.setting.dataresource)) {
+        } else if (/\s/.test(config.setting.dataresource)) {
           config.setting.dataresource = '(' + config.setting.dataresource + ') tb'
         }
   
@@ -237,6 +237,27 @@
           config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
           config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
         }
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+
+        regs.forEach(cell => {
+          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
+          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
+        })
+
         if (config.urlFields) {
           let _param = param || {}
           config.urlFields.forEach(field => {
@@ -343,16 +364,6 @@
         _columns.push(config.gridBtn)
       }
 
-      let valid = true // 鎼滅储鏉′欢蹇呭~楠岃瘉, 鍒濆鎼滅储鏉′欢, 濡傞�氳繃涓婄骇閫忚锛屽啓鍏ユ悳绱㈡潯浠�
-      let hasReqFields = false
-      config.search.forEach(item => {
-        if (item.required !== 'true') return
-        if (!item.initval) {
-          valid = false
-        }
-        hasReqFields = true
-      })
-
       this.setState({
         loadingview: false,
         absFields,
@@ -366,10 +377,10 @@
         columns: _columns,
         arr_field: _arrField.join(','),
         BID: param && param.$BID ? param.$BID : '',
-        search: Utils.initMainSearch(config.search), // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+        search: Utils.initMainSearch(config.search),
         hasReqFields
       }, () => {
-        if (config.setting.onload !== 'false' && valid) { // 鍒濆鍖栧彲鍔犺浇
+        if (config.setting.onload !== 'false') { // 鍒濆鍖栧彲鍔犺浇
           this.loadData()
         }
         this.setShortcut()
@@ -430,11 +441,6 @@
 
   loadData = () => {
     const { setting, search, BIDs, loadCustomApi, hasReqFields } = this.state
-    let requireFields = []
-
-    if (hasReqFields) {
-      requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
-    }
 
     this.setState({
       selectedData: [],
@@ -445,17 +451,18 @@
       }
     })
 
-    if (requireFields.length > 0) {
-      let labels = requireFields.map(item => item.label)
-      labels = Array.from(new Set(labels))
+    if (hasReqFields) {
+      let requireFields = search.filter(item => item.required && item.value === '')
 
-      notification.warning({
-        top: 92,
-        message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
-        duration: 3
-      })
-      return
-    } else if (window.GLOB.systemType === 'production' && setting.interType === 'custom' && !setting.proInterface) {
+      if (requireFields.length > 0) {
+        this.setState({
+          loading: false
+        })
+        return
+      }
+    }
+
+    if (window.GLOB.systemType === 'production' && setting.interType === 'custom' && !setting.proInterface) {
       notification.warning({
         top: 92,
         message: '鏈缃寮忕郴缁熷湴鍧�!',
@@ -525,12 +532,12 @@
 
     let mkey = result.mk_api_key || ''
 
-    delete result.mk_ex_invoke
+    delete result.mk_ex_invoke // 鏄惁缁х画鎵ц
     delete result.status
     delete result.message
     delete result.ErrCode
     delete result.ErrMesg
-    delete result.mk_api_key
+    delete result.mk_api_key   // 褰撳墠璇锋眰鐨刱ey鍊硷紝鐢ㄤ簬鍥炶皟
 
     let param = {}
 
@@ -540,7 +547,7 @@
     })
 
     Api.directRequest(url, setting.method, param, setting.cross).then(res => {
-      if (typeof(res) !== 'object' || Array.isArray(res)) {
+      if (typeof(res) !== 'object') {
         let error = '鏈煡鐨勮繑鍥炵粨鏋滐紒'
 
         if (typeof(res) === 'string') {
@@ -555,6 +562,9 @@
 
         this.customCallbackRequest(_result)
       } else {
+        if (Array.isArray(res)) {
+          res = { data: res }
+        }
         res.mk_api_key = mkey
         this.customCallbackRequest(res)
       }
@@ -662,8 +672,13 @@
     let result = await Api.genericInterface(param)
 
     this.getStatFieldsValue()
-    
+
     if (result.status) {
+      let start = 1
+      if (setting.laypage) {
+        start = pageSize * (pageIndex - 1) + 1
+      }
+
       this.setState({
         data: result.data.map((item, index) => {
           if (absFields.length) {
@@ -678,6 +693,7 @@
           item.key = index
           item.$$uuid = item[setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = start + index + ''
 
           return item
         }),
@@ -736,6 +752,7 @@
           data = data.map(item => {
             if (item.$$uuid === _data.$$uuid) {
               _data.key = item.key
+              _data.$Index = item.$Index
               return _data
             } else {
               return item
@@ -896,13 +913,13 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { MenuName, MenuID } = this.props
     const { arr_field, orderBy, search, setting} = this.state
 
     if (MenuID !== menuId) return
 
-    MKEmitter.emit('execExcelout', MenuID, btnId, {
+    MKEmitter.emit('returnModuleParam', MenuID, btnId, {
       arr_field: arr_field,
       orderBy: orderBy || setting.order,
       search: search,
@@ -1019,7 +1036,7 @@
     MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('reloadMenuView', this.reloadMenuView)
     MKEmitter.addListener('resetActiveMenu', this.resetActiveMenu)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -1034,7 +1051,7 @@
     MKEmitter.removeListener('reloadData', this.reloadData)
     MKEmitter.removeListener('reloadMenuView', this.reloadMenuView)
     MKEmitter.removeListener('resetActiveMenu', this.resetActiveMenu)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -1046,7 +1063,7 @@
       <div className="commontable" id={this.state.ContainerId}>
         {loadingview ? <Spin size="large" /> : null}
         {searchlist && searchlist.length ?
-          <MainSearch BID={BID} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+          <MainSearch BID={BID} searchlist={searchlist} setting={setting} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
         }
         {setting ? <Row className="chart-view" gutter={16}>
           {/* 瑙嗗浘缁� */}
@@ -1076,7 +1093,7 @@
                   </div>
                   <div className="main-table-box">
                     {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && this.state.data && this.state.data.length > 0 ?
-                      <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={pickup} onChange={this.pickupChange} /> : null
+                      <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} /> : null
                     }
                     <MainTable
                       tableId="mainTable"
diff --git a/src/tabviews/custom/components/card/balcony/index.jsx b/src/tabviews/custom/components/card/balcony/index.jsx
new file mode 100644
index 0000000..879d8f5
--- /dev/null
+++ b/src/tabviews/custom/components/card/balcony/index.jsx
@@ -0,0 +1,301 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Spin, notification } from 'antd'
+
+import Api from '@/api'
+// import Utils from '@/utils/utils.js'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import asyncComponent from '@/utils/asyncComponent'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const CardCellComponent = asyncComponent(() => import('../cardcellList'))
+
+class BalconyComponent extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,
+    menu: PropTypes.object,
+    data: PropTypes.array,
+    config: PropTypes.object,
+    menuType: PropTypes.any,
+  }
+
+  state = {
+    BID: '',
+    config: null,
+    syncConfig: null,
+    loading: false,
+    sync: false,
+    data: {},
+    show: true
+  }
+
+  UNSAFE_componentWillMount () {
+    const { data, BID, menu } = this.props
+    let _config = fromJS(this.props.config).toJS()
+    let _cols = new Map()
+
+    let _data = {}
+    let _sync = false
+    
+    if (_config.setting && _config.wrap.datatype !== 'static') {
+      _sync = _config.setting.sync === 'true'
+
+      if (_sync && data) {
+        _data = data[_config.dataName] || {}
+        if (_data && Array.isArray(_data)) {
+          _data = _data[0] || {}
+        }
+        _sync = false
+      }
+    } else {
+      _data = {}
+    }
+
+    if (_data) {
+      _data.$$BID = BID || ''
+    }
+
+    _config.columns.forEach(item => {
+      _cols.set(item.field, item)
+    })
+
+    if (_config.wrap.position === 'fixed') {
+      _config.style.position = 'fixed'
+      _config.style.zIndex = 2
+      _config.style.left = _config.wrap.left || ''
+      _config.style.right = _config.wrap.right || ''
+      _config.style.top = _config.wrap.top || ''
+      _config.style.bottom = _config.wrap.bottom || ''
+      _config.style.transform = _config.wrap.transform || ''
+      _config.style.width = _config.wrap.realwidth || ''
+    }
+
+    let show = true
+    let syncConfig = null
+    if (_config.wrap.linkType === 'sync') {
+      _config.wrap.syncModule = _config.wrap.syncModule.pop()
+      
+      let filterComponent = (components) => {
+        components.forEach(item => {
+          if (syncConfig) return
+          if (item.type === 'tabs') {
+            item.subtabs.forEach(tab => {
+              filterComponent(tab.components)
+            })
+          } else if (item.type === 'group') {
+            filterComponent(item.components)
+          } else if (_config.wrap.syncModule === item.uuid) {
+            syncConfig = {
+              uuid: item.uuid,
+              wrap: item.wrap,
+              setting: item.setting,
+              columns: item.columns
+            }
+          }
+        })
+      }
+
+      filterComponent(menu.components)
+      _config.elements = _config.elements.map(item => {
+        if (item.eleType === 'button') {
+          item.$syncModule = _config.wrap.syncModule
+        }
+        return item
+      })
+    } else if (_config.wrap.linkType === 'sup') {
+      _config.wrap.supModule = _config.wrap.supModule.pop()
+      if (_config.wrap.supControl === 'hidden') {
+        show = false
+      }
+    }
+
+    this.setState({
+      show,
+      syncConfig,
+      sync: _sync,
+      data: _data,
+      BID: BID || '',
+      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') {
+        this.loadData()
+      }
+    })
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { sync, config, BID } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = {}
+      if (nextProps.data && nextProps.data[config.dataName]) {
+        _data = nextProps.data[config.dataName]
+        if (_data && Array.isArray(_data)) {
+          _data = _data[0]
+        }
+      }
+
+      if (_data) {
+        _data.$$BID = BID || ''
+      }
+
+      this.setState({sync: false, data: _data})
+    }
+  }
+
+  /**
+   * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂�
+   * @param {*} menuId     // 鑿滃崟Id
+   * @param {*} position   // 鍒锋柊浣嶇疆
+   * @param {*} btn        // 鎵ц鐨勬寜閽�
+   */
+  refreshByButtonResult = (menuId, position, btn) => {
+    const { config, BID, syncConfig } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData()                                                            // 鏁版嵁鍒锋柊
+
+    let supModule = config.wrap.supModule
+
+    if (syncConfig) {
+      supModule = syncConfig.setting.supModule
+
+      MKEmitter.emit('refreshByButtonResult', syncConfig.uuid, position, btn)
+    }
+
+    if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== supModule) {
+      MKEmitter.emit('reloadData', btn.syncComponentId)                        // 鍚岀骇鏍囩鍒锋柊
+    }
+
+    if (position === 'mainline' && supModule) {                 // 涓昏〃琛屽埛鏂�
+      MKEmitter.emit('reloadData', supModule, (BID || 'empty'))
+    } else if (position === 'popclose') {                                      // 鏍囩鍏抽棴鍒锋柊
+      supModule && MKEmitter.emit('reloadData', supModule, (BID || 'empty'))
+      btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId)
+    }
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config, syncConfig } = this.state
+
+    if (syncConfig) {
+      if (!syncConfig.setting.supModule || syncConfig.setting.supModule !== MenuID) return
+  
+      if (id !== this.state.BID) {
+        this.setState({ BID: id }, () => {
+          this.loadData()
+        })
+      }
+    } else {
+      if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
+  
+      if (config.wrap.supControl === 'hidden') {
+        this.setState({ show: id ? true : false })
+      }
+  
+      if (id !== this.state.BID) {
+        this.setState({ BID: id }, () => {
+          this.loadData()
+        })
+      }
+    }
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+
+    if (menuId !== config.uuid) return
+
+    this.loadData()
+  }
+
+  async loadData () {
+    const { menuType } = this.props
+    const { config, arr_field, BID } = this.state
+
+    if (config.wrap.datatype === 'static') {
+      this.setState({
+        data: {$$BID: BID || ''},
+      })
+      return
+    } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: {$$BID: BID || ''},
+      })
+      return
+    }
+
+    let searches = []
+
+    this.setState({
+      loading: true
+    })
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, 1, BID, menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      let _data = result.data && result.data[0] ? result.data[0] : {}
+      _data.$$BID = BID || ''
+
+      this.setState({
+        data: _data,
+        loading: false
+      })
+    } else {
+      this.setState({
+        loading: false,
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  render() {
+    const { config, loading, data, show, syncConfig } = this.state
+
+    return (
+      <div className={'custom-balcony-box' + (!show ? ' hidden' : '')} style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        <CardCellComponent data={data} cards={syncConfig || config} cardCell={config} elements={config.elements}/>
+      </div>
+    )
+  }
+}
+
+export default BalconyComponent
\ No newline at end of file
diff --git a/src/tabviews/custom/components/card/balcony/index.scss b/src/tabviews/custom/components/card/balcony/index.scss
new file mode 100644
index 0000000..37c4a31
--- /dev/null
+++ b/src/tabviews/custom/components/card/balcony/index.scss
@@ -0,0 +1,65 @@
+.custom-balcony-box {
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  position: relative;
+
+  .card-row-list::after {
+    content: ' ';
+    display: block;
+    clear: both;
+  }
+
+  .card-row-list {
+    .card-item-box {
+      background-color: #ffffff;
+      transition: all 0.3s;
+    }
+    >.pointer {
+      cursor: pointer;
+    }
+    >.active >.card-item-box {
+      border-color: #1890ff!important;
+      box-shadow: 0 0 4px #1890ff;
+    }
+  }
+
+  .card-item-box {
+    position: relative;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    transition: all 0.3s;
+  }
+
+  .loading-mask {
+    position: absolute;
+    left: 40px;
+    top: 0;
+    right: 40px;
+    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;
+    }
+  }
+}
+.custom-balcony-box.hidden {
+  display: none;
+}
+
+.custom-balcony-box::after {
+  content: ' ';
+  display: block;
+  clear: both;
+}
diff --git a/src/tabviews/custom/components/card/cardcellList/index.jsx b/src/tabviews/custom/components/card/cardcellList/index.jsx
index 525c471..8b5fa84 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.jsx
+++ b/src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -21,10 +21,14 @@
 const BarCode = asyncElementComponent(() => import('@/components/barcode'))
 const QrCode = asyncElementComponent(() => import('@/components/qrcode'))
 const Video = asyncComponent(() => import('@/components/video'))
+const PicRadio = {
+  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
+  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
+  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
+}
 
 class CardCellComponent extends Component {
   static propTpyes = {
-    seq: PropTypes.any,              // 搴忓彿
     cards: PropTypes.object,         // 鑿滃崟閰嶇疆淇℃伅
     cardCell: PropTypes.object,
     data: PropTypes.object,
@@ -260,13 +264,20 @@
   }
 
   getContent = (card) => {
-    const { data, cards, seq } = this.props
+    const { data, cards } = this.props
 
     if (card.eleType === 'sequence') {
+      let _style = {}
+      if (card.marks) {
+        _style.width = card.innerHeight
+        _style.height = card.innerHeight
+        _style.lineHeight = card.innerHeight + 'px'
+        this.getMark(card.marks, _style)
+      }
       return (
         <Col key={card.uuid} span={card.width}>
           <div style={card.style}>
-            <div className={'ant-mk-text'}>{seq}</div>
+            <div className="ant-mk-text"><span className="sequence-wrap" style={_style}>{data.$Index || ''}</span></div>
           </div>
         </Col>
       )
@@ -307,7 +318,7 @@
       return (
         <Col key={card.uuid} span={card.width}>
           <div style={_style} onClick={(e) => {this.openNewView(e, card)}}>
-            <div className={'ant-mk-text line' + card.height} style={{height: card.innerHeight || 'auto'}}>{val}</div>
+            <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
           </div>
         </Col>
       )
@@ -359,7 +370,7 @@
       return (
         <Col key={card.uuid} span={card.width}>
           <div style={_style}>
-            <div className={'ant-mk-text line' + card.height} style={{height: card.innerHeight || 'auto'}}>{val}</div>
+            <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
           </div>
         </Col>
       )
@@ -424,8 +435,17 @@
       )
     } else if (card.eleType === 'picture') {
       let _imagestyle = {}
-      let _style = card.style ? {...card.style} : {}
+      let _style = card.style ? {margin: '0 auto', ...card.style} : {}
       let url = ''
+      if (card.maxWidth) {
+        _style.maxWidth = card.maxWidth
+        if (_style.marginLeft === '0px') {
+          delete _style.marginLeft
+        }
+        if (_style.marginRight === '0px') {
+          delete _style.marginRight
+        }
+      }
 
       if (card.datatype === 'static') {
         url = card.url
@@ -443,12 +463,8 @@
         _imagestyle.borderRadius = _style.borderRadius
       }
 
-      if (card.lenWidRadio === '16:9') {
-        _imagestyle.paddingTop = '56.25%'
-      } else if (card.lenWidRadio === '3:2') {
-        _imagestyle.paddingTop = '66.67%'
-      } else if (card.lenWidRadio === '4:3') {
-        _imagestyle.paddingTop = '75%'
+      if (PicRadio[card.lenWidRadio]) {
+        _imagestyle.paddingTop = PicRadio[card.lenWidRadio]
       } else {
         _imagestyle.paddingTop = '100%'
       }
@@ -534,128 +550,116 @@
         </Col>
       )
     } else if (card.eleType === 'button') {
+      let _data = data.$$type === 'extendCard' ? [] : [data]
+
       if (['exec', 'prompt', 'pop'].includes(card.OpenType)) {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <NormalButton
-                BID={data.$$BID}
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-                columns={cards.columns}
-                selectedData={[data]}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <NormalButton
+              BID={data.$$BID}
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+              columns={cards.columns}
+              selectedData={_data}
+            />
           </Col>
         )
       } else if (card.OpenType === 'excelIn') {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <ExcelInButton
-                BID={data.$$BID}
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-                selectedData={[data]}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <ExcelInButton
+              BID={data.$$BID}
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+              selectedData={_data}
+            />
           </Col>
         )
       } else if (card.OpenType === 'excelOut') {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <ExcelOutButton
-                BID={data.$$BID}
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <ExcelOutButton
+              BID={data.$$BID}
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+            />
           </Col>
         )
       } else if (card.OpenType === 'popview') {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <PopupButton
-                BID={data.$$BID}
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-                selectedData={[data]}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <PopupButton
+              BID={data.$$BID}
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+              selectedData={_data}
+            />
           </Col>
         )
       } else if (card.OpenType === 'tab') {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <TabButton
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-                selectedData={[data]}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <TabButton
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+              selectedData={_data}
+            />
           </Col>
         )
       } else if (card.OpenType === 'innerpage') {
         return (
-          <Col key={card.uuid} span={card.width}>
-            <div style={card.style}>
-              <NewPageButton
-                btn={card}
-                show={card.show}
-                style={card.btnstyle}
-                setting={cards.setting}
-                selectedData={[data]}
-              />
-            </div>
+          <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+            <NewPageButton
+              btn={card}
+              show={card.show}
+              style={card.style}
+              setting={cards.setting}
+              selectedData={_data}
+            />
           </Col>
         )
       } else if (card.OpenType === 'funcbutton') {
         if (card.funcType === 'changeuser') {
           return (
-            <Col key={card.uuid} span={card.width}>
-              <div style={card.style}>
-                <ChangeUserButton
-                  BID={data.$$BID}
-                  btn={card}
-                  show={card.show}
-                  style={card.btnstyle}
-                  setting={cards.setting}
-                  selectedData={[data]}
-                />
-              </div>
+            <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+              <ChangeUserButton
+                BID={data.$$BID}
+                btn={card}
+                show={card.show}
+                style={card.style}
+                setting={cards.setting}
+                selectedData={_data}
+              />
             </Col>
           )
         } else if (card.funcType === 'print') {
           return (
-            <Col key={card.uuid} span={card.width}>
-              <div style={card.style}>
-                <PrintButton
-                  BID={data.$$BID}
-                  btn={card}
-                  show={card.show}
-                  style={card.btnstyle}
-                  setting={cards.setting}
-                  selectedData={[data]}
-                />
-              </div>
+            <Col key={card.uuid} className="mk-cell-btn" span={card.width}>
+              <PrintButton
+                BID={data.$$BID}
+                btn={card}
+                show={card.show}
+                style={card.style}
+                setting={cards.setting}
+                selectedData={_data}
+              />
             </Col>
           )
         }
       }
     }
+
+    return null
   }
 
   render() {
diff --git a/src/tabviews/custom/components/card/cardcellList/index.scss b/src/tabviews/custom/components/card/cardcellList/index.scss
index 2684266..97c3ab3 100644
--- a/src/tabviews/custom/components/card/cardcellList/index.scss
+++ b/src/tabviews/custom/components/card/cardcellList/index.scss
@@ -1,11 +1,22 @@
 
 .card-cell-list {
   position: relative;
-
+  .ant-btn {
+    padding: 0;
+  }
   .ant-mk-text {
     font-style: inherit;
     font-weight: inherit;
     text-decoration: inherit;
+    .sequence-wrap {
+      display: inline-block;
+      width: 22px;
+      height: 22px;
+      line-height: 22px;
+      white-space: nowrap;
+      border-radius: 50%;
+      overflow: visible;
+    }
   }
   .ant-mk-text:not(.line1):not(.line) {
     word-break: break-word;
@@ -46,9 +57,13 @@
   .line10 {
     -webkit-line-clamp: 10;
   }
-  button {
-    height: auto;
-    min-height: 32px;
+  .mk-cell-btn {
+    > div {width: 100%;}
+    button {
+      width: 100%;
+      height: auto;
+      min-height: 32px;
+    }
   }
   .ant-mk-slider {
     box-sizing: border-box;
diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx
index 59935cd..9272285 100644
--- a/src/tabviews/custom/components/card/data-card/index.jsx
+++ b/src/tabviews/custom/components/card/data-card/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { connect } from 'react-redux'
-import { Spin, Empty, notification, Col, Pagination } from 'antd'
+import { Spin, Empty, notification, Row, Col, Pagination } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -40,13 +40,39 @@
     sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
     card: null,                // 鍗$墖璁剧疆
     data: null,                // 鏁版嵁
-    total: null
+    total: null,
+    precards: [],
+    nextcards: [],
   }
 
   UNSAFE_componentWillMount () {
     const { data, initdata, BID } = this.props
     let _config = fromJS(this.props.config).toJS()
-    let _card = _config.subcards[0]
+
+    let _card = null
+    let precards = []
+    let nextcards = []
+
+    _config.subcards.forEach(item => {
+      item.setting.$click = ''
+      if (item.setting.click === 'button') {
+        if (item.elements.filter(ele => ele.eleType === 'button').length < 2) {
+          item.setting.$click = ' trigger-button'
+        }
+        item.setting.click = ''
+      }
+
+      if (item.$cardType !== 'extendCard') {
+        _card = item
+      } else if (!_card) {
+        precards.push(item)
+      } else {
+        nextcards.push(item)
+      }
+    })
+
+    _config.subcards = null
+    
     let _cols = new Map()
 
     let _data = null
@@ -60,11 +86,26 @@
       _sync = false
     }
 
+    if (_config.wrap.cardFloat && _config.wrap.cardFloat !== 'left') {
+      let _width = 0
+      precards.forEach(card => {
+        _width += card.setting.width
+      })
+      nextcards.forEach(card => {
+        _width += card.setting.width
+      })
+      
+      _config.$offset = _width
+    } else {
+      _config.wrap.cardFloat = null
+    }
+
     if (_data) {
       _data = _data.map((item, index) => {
         item.key = index
         item.$$uuid = item[_config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
     }
@@ -87,6 +128,8 @@
     })
 
     this.setState({
+      precards,
+      nextcards,
       sync: _sync,
       data: _data,
       BID: BID || '',
@@ -103,8 +146,9 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('getSyncData', this.getSyncData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -125,16 +169,15 @@
         item.key = index
         item.$$uuid = item[config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({pageIndex: 1}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -143,9 +186,18 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('getSyncData', this.getSyncData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  getSyncData = (syncModule, btnId) => {
+    const { config, selectedData } = this.state
+
+    if (config.uuid !== syncModule) return
+
+    MKEmitter.emit('triggerBtnId', btnId, (selectedData || []))
   }
 
   /**
@@ -159,7 +211,15 @@
 
     if (config.uuid !== menuId) return
 
-    this.loadData(btn)                                                         // 鏁版嵁鍒锋柊
+    if (!btn || btn.resetPageIndex !== 'false') {
+      this.setState({
+        pageIndex: 1
+      }, () => {
+        this.loadData()
+      })
+    } else {
+      this.loadData()
+    }
 
     if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) {
       MKEmitter.emit('reloadData', btn.syncComponentId)                        // 鍚岀骇鏍囩鍒锋柊
@@ -191,7 +251,7 @@
 
     if (!config.setting.supModule || config.setting.supModule !== MenuID) return
     if (id !== this.state.BID) {
-      this.setState({ BID: id, BData: data }, () => {
+      this.setState({ BID: id, BData: data, pageIndex: 1 }, () => {
         this.loadData()
       })
     }
@@ -200,14 +260,14 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { mainSearch } = this.props
     const { arr_field, config, search } = this.state
 
     if (config.uuid !== menuId) return
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -216,7 +276,7 @@
       })
     }
 
-    MKEmitter.emit('execExcelout', config.uuid, btnId, {
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
       arr_field: arr_field,
       orderBy: config.setting.order || '',
       search: searches,
@@ -238,17 +298,23 @@
         total: 0,
         loading: false
       })
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
       return
     }
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
       let keys = searches.map(item => item.key.toLowerCase())
       mainSearch.forEach(item => {
         if (!keys.includes(item.key.toLowerCase())) {
           searches.push(item)
         }
       })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
@@ -260,6 +326,11 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
+      let start = 1
+      if (config.setting.laypage) {
+        start = config.setting.pageSize * (pageIndex - 1) + 1
+      }
+
       this.setState({
         activeKey: '',
         selectKeys: [],
@@ -268,11 +339,13 @@
           item.key = index
           item.$$uuid = item[config.setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = index + start + ''
           return item
         }),
         total: result.total,
         loading: false
       })
+      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
     } else {
       this.setState({
         loading: false
@@ -293,7 +366,7 @@
     const { config, arr_field, pageIndex, search, BID } = this.state
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -325,6 +398,7 @@
               _data.key = item.key
               _data.$$uuid = _data[config.setting.primaryKey] || ''
               _data.$$BID = BID || ''
+              _data.$Index = item.$Index
               return _data
             } else {
               return item
@@ -514,7 +588,7 @@
   }
 
   render() {
-    const { config, loading, data, pageIndex, total, card, activeKey, BID, BData, selectedData, selectKeys } = this.state
+    const { config, precards, nextcards, loading, data, pageIndex, total, card, activeKey, BID, BData, selectedData, selectKeys } = this.state
 
     let _total = 0
     let switchable = false
@@ -523,9 +597,11 @@
       switchable = true
     }
     let offset = 0
-    if (config.wrap.cardFloat && config.wrap.cardFloat !== 'left') {
-      if (data && card.setting.width * data.length < 24) {
-        offset = 24 - card.setting.width * data.length
+
+    if (config.wrap.cardFloat) {
+      let length = data ? data.length : 0
+      if (card.setting.width * length + config.$offset < 24) {
+        offset = 24 - card.setting.width * length - config.$offset
         if (config.wrap.cardFloat === 'center') {
           offset = Math.floor(offset / 2)
         }
@@ -533,7 +609,7 @@
     }
 
     return (
-      <div className="custom-data-card-box" style={{...config.style, minHeight: config.wrap.minHeight}}>
+      <div className="custom-data-card-box" style={config.style}>
         {loading ?
           <div className="loading-mask">
             {data ? <div className="ant-spin-blur"></div> : null}
@@ -549,20 +625,30 @@
             actions={config.action}
             columns={config.columns}
             selectedData={selectedData}
-            refreshdata={this.refreshbyaction}
           /> : null
         }
         <div className={`data-zoom ${config.wrap.cardType || ''} ${config.wrap.scale || ''}`}>
           {switchable ? <div className={'prev-page ' + (pageIndex === 1 ? 'disabled' : '')} onClick={this.prevPage}><div><div><img src={preImg} alt=""/></div></div></div> : null}
-          {data && data.length > 0 ? <div className="card-row-list">
-            {data.map((item, index) => (
-              <Col className={(activeKey === index ? 'active' : (selectKeys.indexOf(index) > -1 ? 'selected' : '')) + (card.setting.click ? ' pointer' : '')} key={index} span={card.setting.width} offset={!index ? offset : 0} onClick={() => {this.changeCard(index, item)}}>
+          <Row className="card-row-list">
+            {offset ? <Col span={offset} style={{height: '10px'}}> </Col> : null}
+            {precards.map((item, index) => (
+              <Col key={'pre' + index} className={item.setting.$click} span={item.setting.width || 6}>
+                <CardItem card={item} cards={config} data={{$$BID: BID, $$type: 'extendCard'}}/>
+              </Col>
+            ))}
+            {data && data.map((item, index) => (
+              <Col className={(activeKey === index ? ' active' : (selectKeys.indexOf(index) > -1 ? ' selected' : '')) + (card.setting.$click ? ' pointer' : '') + card.setting.$click} key={index} span={card.setting.width} onClick={() => {this.changeCard(index, item)}}>
                 <CardItem card={card} cards={config} data={item}/>
               </Col>
             ))}
-          </div> : null}
+            {nextcards.map((item, index) => (
+              <Col key={'next' + index} className={item.setting.$click} span={item.setting.width || 6}>
+                <CardItem card={item} cards={config} data={{$$BID: BID, $$type: 'extendCard'}}/>
+              </Col>
+            ))}
+          </Row>
           {switchable ? <div className={'prev-page ' + (total <= _total ? 'disabled' : '')} onClick={this.nextPage}><div><div><img src={nextImg} alt=""/></div></div></div> : null}
-          {!data || data.length === 0 ? <Empty description={false}/> : null}
+          {precards.length === 0 && nextcards.length === 0 && (!data || data.length === 0) ? <Empty description={false}/> : null}
         </div>
         {config.wrap.pagestyle !== 'switch' && config.setting.laypage && data ? <Pagination size="small" total={total} showTotal={t => `鍏� ${t} 鏉} pageSize={config.setting.pageSize} onChange={this.changePageIndex} current={pageIndex}/> : null}
       </div>
diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss
index 49e69ef..9e0798f 100644
--- a/src/tabviews/custom/components/card/data-card/index.scss
+++ b/src/tabviews/custom/components/card/data-card/index.scss
@@ -125,6 +125,28 @@
     margin: 10px;
     text-align: right;
   }
+  .trigger-button {
+    .card-item-box {
+      .card-cell-list {
+        position: unset;
+        .mk-cell-btn {
+          position: unset;
+          .ant-btn {
+            position: unset;
+          }
+          .ant-btn::after {
+            content: ' ';
+            position: absolute;
+            top: 0;
+            bottom: 0;
+            left: 0;
+            right: 0;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+  }
 }
 
 .custom-card-box::after {
diff --git a/src/tabviews/custom/components/card/prop-card/index.jsx b/src/tabviews/custom/components/card/prop-card/index.jsx
index 0c85678..fc110d8 100644
--- a/src/tabviews/custom/components/card/prop-card/index.jsx
+++ b/src/tabviews/custom/components/card/prop-card/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { connect } from 'react-redux'
-import { Spin, notification, Col } from 'antd'
+import { Spin, notification, Col, Row } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -73,6 +73,13 @@
 
     let _width = 0
     _config.subcards.forEach(card => {
+      card.setting.$click = ''
+      if (card.setting.click === 'button') {
+        if (card.elements.filter(ele => ele.eleType === 'button').length < 2) {
+          card.setting.$click = ' trigger-button'
+        }
+        card.setting.click = ''
+      }
       _width += card.setting.width
       card.elements = card.elements.map(item => {
         if (item.field && _cols.has(item.field)) {
@@ -113,7 +120,7 @@
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
     this.handleTimer()
   }
 
@@ -151,12 +158,10 @@
       }
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if ( config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -165,16 +170,7 @@
 
     if (!config.timer) return
 
-    const _change = {
-      '15s': 15000,
-      '30s': 30000,
-      '1min': 60000,
-      '5min': 300000,
-      '10min': 600000,
-      '15min': 900000,
-      '30min': 1800000,
-      '1hour': 3600000
-    }
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
 
     let timer = _change[config.timer]
 
@@ -270,25 +266,20 @@
     if (config.wrap.datatype === 'static') {
       this.setState({
         data: {$$BID: BID || ''},
-        loading: false
       })
       return
     } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
         data: {$$BID: BID || ''},
-        loading: false
       })
       return
     }
 
-    let searches = []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
-      let keys = searches.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searches.push(item)
-        }
-      })
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     if (!hastimer) {
@@ -417,7 +408,7 @@
     const { config, loading, data, activeKey } = this.state
 
     return (
-      <div className="custom-prop-card-box" style={{...config.style, minHeight: config.wrap.minHeight}}>
+      <div className="custom-prop-card-box" style={config.style}>
         {loading ?
           <div className="loading-mask">
             <div className="ant-spin-blur"></div>
@@ -425,13 +416,13 @@
           </div> : null
         }
         <NormalHeader config={config}/>
-        <div className={`card-row-list ${config.wrap.cardType || ''} ${config.wrap.scale || ''}`}>
+        <Row className={`card-row-list ${config.wrap.cardType || ''} ${config.wrap.scale || ''}`}>
           {config.subcards.map((item, index) => (
-            <Col className={(activeKey === index ? 'active' : '') + (item.setting.click ? ' pointer' : '')} key={index} span={item.setting.width || 6} offset={item.offset || 0} onClick={() => {this.changeCard(index, item)}}>
+            <Col className={(activeKey === index ? 'active' : '') + (item.setting.click ? ' pointer' : '') + item.setting.$click} key={index} span={item.setting.width || 6} offset={item.offset || 0} onClick={() => {this.changeCard(index, item)}}>
               <CardItem card={item} cards={config} data={data}/>
             </Col>
           ))}
-        </div>
+        </Row>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/card/prop-card/index.scss b/src/tabviews/custom/components/card/prop-card/index.scss
index 12c5e88..bb919f8 100644
--- a/src/tabviews/custom/components/card/prop-card/index.scss
+++ b/src/tabviews/custom/components/card/prop-card/index.scss
@@ -70,6 +70,28 @@
       background: #ffffff;
     }
   }
+  .trigger-button {
+    .card-item-box {
+      .card-cell-list {
+        position: unset;
+        .mk-cell-btn {
+          position: unset;
+          .ant-btn {
+            position: unset;
+          }
+          .ant-btn::after {
+            content: ' ';
+            position: absolute;
+            top: 0;
+            bottom: 0;
+            left: 0;
+            right: 0;
+            cursor: pointer;
+          }
+        }
+      }
+    }
+  }
 }
 
 .custom-card-box::after {
diff --git a/src/tabviews/custom/components/card/table-card/index.jsx b/src/tabviews/custom/components/card/table-card/index.jsx
index a557611..609d46e 100644
--- a/src/tabviews/custom/components/card/table-card/index.jsx
+++ b/src/tabviews/custom/components/card/table-card/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Spin, notification, Col, Empty, Pagination } from 'antd'
+import { Spin, notification, Row, Col, Empty, Pagination } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -27,7 +27,6 @@
     config: null,              // 鍥捐〃閰嶇疆淇℃伅
     loading: false,            // 鏁版嵁鍔犺浇鐘舵��
     search: null,              // 鎼滅储鏉′欢
-    preIndex: 0,               // 寮�濮嬬储寮�
     pageIndex: 1,              // 椤电爜
     total: 0,                  // 鎬绘暟
     sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
@@ -59,6 +58,7 @@
         item.key = index
         item.$$uuid = item[_config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
     }
@@ -69,9 +69,9 @@
     }
 
     if (_config.setting.laypage) {
-      _config.wrap.contentHeight = _config.wrap.height - (showHeader ? 85 : 40)
+      _config.wrap.contentHeight = showHeader ? 'calc(100% - 85px)' : 'calc(100% - 40px)'
     } else {
-      _config.wrap.contentHeight = _config.wrap.height - (showHeader ? 45 : 0)
+      _config.wrap.contentHeight = showHeader ? 'calc(100% - 45px)' : '100%'
     }
 
     _config.columns.forEach(item => {
@@ -104,7 +104,7 @@
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -118,7 +118,7 @@
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -138,16 +138,15 @@
         item.key = index
         item.$$uuid = item[config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -181,7 +180,7 @@
 
     if (!config.setting.supModule || config.setting.supModule !== MenuID) return
     if (id !== this.state.BID) {
-      this.setState({ BID: id }, () => {
+      this.setState({ BID: id, pageIndex: 1 }, () => {
         this.loadData()
       })
     }
@@ -198,14 +197,14 @@
    /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { mainSearch } = this.props
     const { arr_field, config, search } = this.state
 
     if (config.uuid !== menuId) return
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -214,7 +213,7 @@
       })
     }
 
-    MKEmitter.emit('execExcelout', config.uuid, btnId, {
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
       arr_field: arr_field,
       orderBy: config.setting.order || '',
       search: searches,
@@ -229,20 +228,24 @@
     if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
         data: [],
-        total: 0,
-        preIndex: 0
+        total: 0
       })
       return
     }
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
       let keys = searches.map(item => item.key)
       mainSearch.forEach(item => {
         if (!keys.includes(item.key)) {
           searches.push(item)
         }
       })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
@@ -254,9 +257,9 @@
 
     let result = await Api.genericInterface(param)
     if (result.status) {
-      let _preIndex = 0
+      let start = 1
       if (config.setting.laypage) {
-        _preIndex = config.setting.pageSize * (pageIndex - 1)
+        start = config.setting.pageSize * (pageIndex - 1) + 1
       }
 
       this.setState({
@@ -264,10 +267,10 @@
           item.key = index
           item.$$uuid = item[config.setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = index + start + ''
           return item
         }),
         total: result.total,
-        preIndex: _preIndex,
         loading: false
       })
     } else {
@@ -290,7 +293,7 @@
     })
   }
 
-  getLines = (data, seq) => {
+  getLines = (data) => {
     const { config } = this.state
 
     let line = []
@@ -321,7 +324,7 @@
       line.push(
         <Col key={index} span={24}>
           <div className="card-item-box" style={item.style}>
-            <CardCellComponent seq={seq} data={data} cards={config} cardCell={item} elements={item.elements}/>
+            <CardCellComponent data={data} cards={config} cardCell={item} elements={item.elements}/>
           </div>
         </Col>
       )
@@ -340,10 +343,10 @@
   }
 
   render() {
-    const { config, loading, data, BID, pageIndex, preIndex, total } = this.state
+    const { config, loading, data, BID, pageIndex, total } = this.state
 
     return (
-      <div className="custom-table-card-box" style={{...config.style, height: config.wrap.height}}>
+      <div className="custom-table-card-box" style={{...config.style}}>
         {loading ?
           <div className="loading-mask">
             {data ? <div className="ant-spin-blur"></div> : null}
@@ -351,9 +354,9 @@
           </div> : null
         }
         <NormalHeader config={config} BID={BID} menuType={this.props.menuType} refresh={this.refreshSearch} />
-        {data && data.length > 0 ? <div className="card-row-list" style={{height: config.wrap.contentHeight}}>
-          {data.map((item, index) => this.getLines(item, preIndex + index + 1))}
-        </div> : null}
+        {data && data.length > 0 ? <Row className="card-row-list" style={{height: config.wrap.contentHeight}}>
+          {data.map(item => this.getLines(item))}
+        </Row> : null}
         {data && data.length === 0 ? <div className="card-row-list" style={{height: config.wrap.contentHeight}}>
           <Empty description={false}/>
         </div> : null}
diff --git a/src/tabviews/custom/components/carousel/data-card/index.jsx b/src/tabviews/custom/components/carousel/data-card/index.jsx
index 1e6e1aa..e4c768a 100644
--- a/src/tabviews/custom/components/carousel/data-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/data-card/index.jsx
@@ -92,7 +92,7 @@
 
   componentDidMount () {
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -117,12 +117,10 @@
       })
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -131,7 +129,7 @@
       return
     }
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -174,15 +172,15 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { mainSearch } = this.props
     const { arr_field, config } = this.state
 
     if (config.uuid !== menuId) return
 
-    let searches = mainSearch ? fromJS(mainSearch).toJS() : []
+    let searches = config.setting.useMSearch && mainSearch ? fromJS(mainSearch).toJS() : []
 
-    MKEmitter.emit('execExcelout', config.uuid, btnId, {
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
       arr_field: arr_field,
       orderBy: config.setting.order || '',
       search: searches,
@@ -202,7 +200,11 @@
       return
     }
 
-    let searches = mainSearch ? fromJS(mainSearch).toJS() : []
+    let searches = config.setting.useMSearch && mainSearch ? fromJS(mainSearch).toJS() : []
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
 
     this.setState({
       loading: true
@@ -315,7 +317,7 @@
     const { config, loading, data, card } = this.state
 
     return (
-      <div className="custom-data-carousel-box" style={{...config.style, minHeight: config.wrap.minHeight}}>
+      <div className="custom-data-carousel-box" style={config.style}>
         {loading ?
           <div className="loading-mask">
             {data ? <div className="ant-spin-blur"></div> : null}
diff --git a/src/tabviews/custom/components/carousel/data-card/index.scss b/src/tabviews/custom/components/carousel/data-card/index.scss
index 15319b2..eabde18 100644
--- a/src/tabviews/custom/components/carousel/data-card/index.scss
+++ b/src/tabviews/custom/components/carousel/data-card/index.scss
@@ -4,6 +4,7 @@
   background-repeat: no-repeat;
   background-size: cover;
   min-height: 30px;
+  overflow: hidden;
 
   .card-item-box {
     background-position: center center;
diff --git a/src/tabviews/custom/components/carousel/prop-card/index.jsx b/src/tabviews/custom/components/carousel/prop-card/index.jsx
index d519d08..8402eb6 100644
--- a/src/tabviews/custom/components/carousel/prop-card/index.jsx
+++ b/src/tabviews/custom/components/carousel/prop-card/index.jsx
@@ -133,12 +133,10 @@
       }
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -192,26 +190,21 @@
 
     if (config.wrap.datatype === 'static') {
       this.setState({
-        data: {$$BID: BID || ''},
-        loading: false
+        data: {$$BID: BID || ''}
       })
       return
     } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
-        data: {$$BID: BID || ''},
-        loading: false
+        data: {$$BID: BID || ''}
       })
       return
     }
 
-    let searches = []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
-      let keys = searches.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searches.push(item)
-        }
-      })
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
diff --git a/src/tabviews/custom/components/carousel/prop-card/index.scss b/src/tabviews/custom/components/carousel/prop-card/index.scss
index b5e46e6..68b6eb3 100644
--- a/src/tabviews/custom/components/carousel/prop-card/index.scss
+++ b/src/tabviews/custom/components/carousel/prop-card/index.scss
@@ -5,6 +5,7 @@
   background-size: cover;
   min-height: 30px;
   position: relative;
+  overflow: hidden;
 
   .card-item-box {
     position: relative;
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 01878f0..f279ed3 100644
--- a/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -2,9 +2,8 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { Chart } from '@antv/g2'
-import { connect } from 'react-redux'
 import DataSet from '@antv/data-set'
-import { Spin, Empty, Select, notification } from 'antd'
+import { Spin, Empty, notification } from 'antd'
 import moment from 'moment'
 
 import asyncComponent from './asyncButtonComponent'
@@ -12,7 +11,6 @@
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
 import UtilsDM from '@/utils/utils-datamanage.js'
-import { modifyTabview } from '@/store/action'
 import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
@@ -42,9 +40,6 @@
     search: null,              // 鎼滅储鏉′欢
     vFields: [],               // 鏁板�煎瓧娈�
     vstFields: null,           // 缁熻鏁版嵁鍊煎瓧娈典俊鎭�
-    chartData: [],             // 鍥捐〃鏁版嵁
-    chartFields: [],           // 缁熻鍥捐〃鐢熸垚瀛楁闆�
-    selectFields: [],          // 缁熻鍥捐〃閫夋嫨瀛楁
   }
 
   UNSAFE_componentWillMount () {
@@ -65,6 +60,7 @@
     let vstFields = null
 
     if (_config.plot.datatype === 'statistics') {
+      _config.plot.enabled = 'false'
       let _column = _config.columns.filter(col => _config.plot.InfoValue === col.field)[0]
       if (_column) {
         let decimal = 0
@@ -98,17 +94,22 @@
       })
     }
 
-    if (config.plot.title || config.search.length > 0) {
-      _config.plot.height = _config.plot.height - 80
-    } else {
-      _config.plot.height = _config.plot.height - 30
+    let padding = 0
+    if (_config.style.paddingTop && !isNaN(parseInt(_config.style.paddingTop))) {
+      padding += parseInt(_config.style.paddingTop)
+    }
+    if (_config.style.paddingBottom && !isNaN(parseInt(_config.style.paddingBottom))) {
+      padding += parseInt(_config.style.paddingBottom)
     }
 
-    if (_config.style) {
-      _config.style = {..._config.style, minHeight: (config.plot.height || 400)}
+    let height = config.plot.height || 400
+    if (config.plot.title || config.search.length > 0) {
+      _config.plot.height = height - 70 - padding
     } else {
-      _config.style = {minHeight: (config.plot.height || 400)}
+      _config.plot.height = height - 25 - padding
     }
+
+    _config.style.height = height
 
     let transfield = {}
     _config.columns.forEach(col => {
@@ -117,51 +118,180 @@
       }
     })
 
-    _config.plot.color = _config.plot.color || 'rgba(0, 0, 0, 0.85)'
+    _config.plot.color = _config.plot.color || 'rgba(0, 0, 0, 0.65)'
 
+    let bars = {}
     if (_config.plot.enabled === 'true' && _config.plot.customs && _config.plot.customs.length > 0) {
-      let colors = new Map()
+      let Bar_axis = []
+      _config.plot.customs = _config.plot.customs.map(item => {
+        item.name = transfield[item.type] || item.type
+        item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
+        item.shape = item.shape ? (item.shape[1] || '') : ''
+
+        if (item.chartType === 'bar') {
+          bars[item.type] = true
+          Bar_axis.push(item.type)
+        }
+
+        return item
+      })
+
+      _config.plot.hasBar = Bar_axis.length > 0
+
+      if (_config.plot.mutilBar !== 'overlap') {
+        _config.plot.Bar_axis = Bar_axis
+      }
+    } else {
+      _config.plot.enabled = 'false'
+    }
+
+    let colors = new Map()
+
+    if (_config.plot.colors && _config.plot.colors.length > 0) { // 棰滆壊璁剧疆
+      if (_config.plot.datatype === 'statistics') {
+        if (_config.plot.ramp === 'true') {
+          let _s = 'l(0) '
+          if (_config.plot.chartType === 'bar' || (_config.plot.chartType === 'line' && _config.plot.rampDirection === 'vertical')) {
+            _s = 'l(90) '
+          }
+          _config.plot.colors.forEach(item => {
+            if (!colors.has(item.type)) {
+              colors.set(item.type, _s + `0:${item.color} 1:${item.color1}`)
+            }
+          })
+        } else {
+          _config.plot.colors.forEach(item => {
+            if (!colors.has(item.type)) {
+              colors.set(item.type, item.color)
+            }
+          })
+        }
+      } else if (_config.plot.enabled === 'true') {
+        if (_config.plot.ramp === 'true') {
+          _config.plot.colors.forEach(item => {
+            let _type = transfield[item.type] || item.type
+            if (!colors.has(_type)) {
+              if (bars[item.type]) {
+                colors.set(_type, `l(90) 0:${item.color} 1:${item.color1}` )
+              } else {
+                colors.set(_type, `l(0) 0:${item.color} 1:${item.color1}` )
+              }
+            }
+          })
+        } else {
+          _config.plot.colors.forEach(item => {
+            let _type = transfield[item.type] || item.type
+            if (!colors.has(_type)) {
+              colors.set(_type, item.color)
+            }
+          })
+        }
+      } else {
+        if (_config.plot.ramp === 'true') {
+          let _s = 'l(0) '
+          if (_config.plot.chartType === 'bar' || (_config.plot.chartType === 'line' && _config.plot.rampDirection === 'vertical')) {
+            _s = 'l(90) '
+          }
+          _config.plot.colors.forEach(item => {
+            if (!transfield[item.type]) return
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], _s + `0:${item.color} 1:${item.color1}` )
+            }
+          })
+        } else {
+          _config.plot.colors.forEach(item => {
+            if (!transfield[item.type]) return
+            if (!colors.has(transfield[item.type])) {
+              colors.set(transfield[item.type], item.color)
+            }
+          })
+        }
+      }
+      _config.plot.$colors = colors
+    }
+
+    let xc = {label: {
+      formatter: (val) => {
+        if (!val || /^\s*$/.test(val)) return val
+        let _val = `${val}`
+        if (_val.length <= 11) return val
+        return _val.substring(0, 8) + '...'
+      },
+      style: { fill: _config.plot.color }
+    }}
+    let yc = {label: { style: { fill: _config.plot.color } }}
+    if (_config.plot.grid === 'hidden') {
+      yc.grid = null
+    }
+    if (_config.plot.y_line === 'show') {
+      yc.line = {style: { stroke: '#D1D2CE' }}
+    }
+    if (_config.plot.lineColor) {
+      xc.tickLine = {style: { stroke: _config.plot.lineColor }}
+      xc.line = { style: { stroke: _config.plot.lineColor } }
+      if (yc.grid !== null) {
+        yc.grid = { line: { style: { stroke: _config.plot.lineColor } }}
+      }
+      if (yc.line) {
+        yc.line = { style: { stroke: _config.plot.lineColor } }
+      }
+    }
+
+    _config.plot.$xc = xc
+    _config.plot.$yc = yc
+
+    _config.plot.$paddingLeft = 30
+    _config.plot.$paddingRight = 30
+
+    if (_config.plot.enabled === 'true') {
       let colorIndex = 0
       let limit = chartColors.length
-  
-      if (_config.plot.colors && _config.plot.colors.length > 0) {
-        _config.plot.colors.forEach(item => {
-          if (!colors.has(item.type)) {
-            colors.set(item.type, item.color)
-          }
-        })
-      }
-  
       let axisIndex = 0
-      let hasBar = false
       let fields = []
       let legends = []
   
       _config.plot.customs.forEach(item => {
-        item.name = transfield[item.type] || item.type
-        item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
-        item.shape = item.shape ? (item.shape[1] || '') : ''
-  
-        if (colors.get(item.type)) {
-          item.color = colors.get(item.type)
+        if (colors.has(item.name)) {
+          item.color = colors.get(item.name)
         } else {
           item.color = chartColors[colorIndex % limit]
           colorIndex++
         }
   
-        if (item.chartType === 'bar' && !hasBar) {
-          hasBar = true
-        } else if (item.chartType === 'bar') {
-          item.chartType = 'line'
-          item.shape = 'smooth'
-        }
-  
         if (item.axis === 'true' && axisIndex < 2) {
           if (axisIndex === 0) {
-            item.axis = { grid: {style: { fill: _config.plot.color }}, title: { style: { fill: _config.plot.color } }, label: {style: { fill: _config.plot.color }} }
+            item.axis = { label: {style: { fill: _config.plot.color }} }
+            if (item.title !== 'false') {
+              item.axis.title = { style: { fill: _config.plot.color } }
+              _config.plot.$paddingLeft = 50
+            }
+            if (_config.plot.grid === 'hidden') {
+              item.axis.grid = null
+            }
+            if (_config.plot.y_line === 'show') {
+              item.axis.line = {style: { stroke: '#D1D2CE' }}
+            }
+            if (_config.plot.lineColor) {
+              if (item.axis.grid !== null) {
+                item.axis.grid = { line: { style: { stroke: _config.plot.lineColor } }}
+              }
+              if (item.axis.line) {
+                item.axis.line = { style: { stroke: _config.plot.lineColor } }
+              }
+            }
             fields.unshift(item)
           } else {
-            item.axis = { grid: null, title: {style: { fill: _config.plot.color }}, label: {style: { fill: _config.plot.color }} }
+            item.axis = { grid: null, label: {style: { fill: _config.plot.color }} }
+            if (item.title !== 'false') {
+              item.axis.title = { style: { fill: _config.plot.color } }
+              _config.plot.$paddingRight = 60
+            }
+            if (_config.plot.y_line === 'show') {
+              item.axis.line = {style: { stroke: '#D1D2CE' }}
+            }
+            if (_config.plot.lineColor && item.axis.line) {
+              item.axis.line = { style: { stroke: _config.plot.lineColor } }
+            }
             fields.splice(1, 0, item)
           }
           axisIndex++
@@ -179,9 +309,7 @@
       })
       _config.plot.customs = fields
       _config.plot.legends = legends
-      _config.plot.hasBar = hasBar
-    } else {
-      _config.plot.enabled = 'false'
+      _config.plot.axisIndex = axisIndex
     }
 
     this.setState({
@@ -219,12 +347,10 @@
       this.setState({sync: false, data: _data}, () => {
         this.handleData()
       })
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -235,7 +361,7 @@
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
     this.handleTimer()
   }
@@ -250,7 +376,7 @@
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -259,16 +385,7 @@
 
     if (!config.timer) return
 
-    const _change = {
-      '15s': 15000,
-      '30s': 30000,
-      '1min': 60000,
-      '5min': 300000,
-      '10min': 600000,
-      '15min': 900000,
-      '30min': 1800000,
-      '1hour': 3600000
-    }
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
 
     let timer = _change[config.timer]
 
@@ -360,14 +477,14 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { mainSearch } = this.props
     const { arr_field, config, search } = this.state
 
     if (config.uuid !== menuId) return
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -376,7 +493,7 @@
       })
     }
 
-    MKEmitter.emit('execExcelout', config.uuid, btnId, {
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
       arr_field: arr_field,
       orderBy: config.setting.order || '',
       search: searches,
@@ -401,13 +518,18 @@
     }
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
       let keys = searches.map(item => item.key)
       mainSearch.forEach(item => {
         if (!keys.includes(item.key)) {
           searches.push(item)
         }
       })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     if (!hastimer) {
@@ -444,29 +566,11 @@
    * @description 鏁版嵁棰勫鐞嗭紝缁熻鏁版嵁闇�瑕侀噸缃�
    */
   handleData = () => {
-    const { data, plot } = this.state
-
-    if (plot.datatype === 'statistics') {
-      let result = this.getStaticMsg(data)
-      
-      this.setState({
-        chartData: result.data,
-        chartFields: result.chartFields,
-        selectFields: result.selectFields
-      }, () => {
-        let _element = document.getElementById(this.state.chartId)
-        if (_element) {
-          _element.innerHTML = ''
-        }
-        this.viewrender()
-      })
-    } else {
-      let _element = document.getElementById(this.state.chartId)
-      if (_element) {
-        _element.innerHTML = ''
-      }
-      this.viewrender()
+    let _element = document.getElementById(this.state.chartId)
+    if (_element) {
+      _element.innerHTML = ''
     }
+    this.viewrender()
   }
 
   /**
@@ -476,9 +580,9 @@
    * 3銆佹煴鐘跺浘鏁版嵁琛ラ綈
    */
   getdata = () => {
-    const { data, plot, vFields } = this.state
+    const { data, plot, vFields, config } = this.state
 
-    if (!data) {
+    if (!data || data.length === 0) {
       this.setState({empty: true})
       return []
     }
@@ -489,6 +593,8 @@
     if (plot.repeat === 'average') {
       let _mdata = new Map()
       _cdata.forEach(item => {
+        if (!item[plot.Xaxis]) return
+
         vFields.forEach(col => {
           if (typeof(item[col.field]) !== 'number') {
             item[col.field] = parseFloat(item[col.field])
@@ -501,10 +607,15 @@
           }
         })
 
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
+        // dodge is not support linear attribute, please use category attribute! 鏃堕棿鏍煎紡
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
+
+        if (!_mdata.has(item[plot.Xaxis])) {
           item.$count = 1
           _mdata.set(item[plot.Xaxis], item)
-        } else if (item[plot.Xaxis]) {
+        } else {
           let _item = _mdata.get(item[plot.Xaxis])
           _item.$count++
           vFields.forEach(col => {
@@ -521,11 +632,14 @@
           item[col.field] = item[col.field].toFixed(col.decimal)
           item[col.field] = +item[col.field]
         })
+        item.$$uuid = item[config.setting.primaryKey] || ''
         return item
       })
     } else if (plot.repeat === 'cumsum') {
       let _mdata = new Map()
       _cdata.forEach(item => {
+        if (!item[plot.Xaxis]) return
+
         vFields.forEach(col => {
           if (typeof(item[col.field]) !== 'number') {
             item[col.field] = parseFloat(item[col.field])
@@ -538,9 +652,13 @@
           }
         })
 
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
+
+        if (!_mdata.has(item[plot.Xaxis])) {
           _mdata.set(item[plot.Xaxis], item)
-        } else if (item[plot.Xaxis]) {
+        } else {
           let _item = _mdata.get(item[plot.Xaxis])
           vFields.forEach(col => {
             _item[col.field] += item[col.field]
@@ -555,12 +673,19 @@
           item[col.field] = item[col.field].toFixed(col.decimal)
           item[col.field] = +item[col.field]
         })
+        item.$$uuid = item[config.setting.primaryKey] || ''
         return item
       })
     } else { // plot.repeat === 'unrepeat'
       let _mdata = new Map()
       _cdata.forEach(item => {
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
+        if (!item[plot.Xaxis]) return
+
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
+
+        if (!_mdata.has(item[plot.Xaxis])) {
           vFields.forEach(col => {
             if (typeof(item[col.field]) !== 'number') {
               item[col.field] = parseFloat(item[col.field])
@@ -574,6 +699,8 @@
             item[col.field] = item[col.field].toFixed(col.decimal)
             item[col.field] = +item[col.field]
           })
+          
+          item.$$uuid = item[config.setting.primaryKey] || ''
           _mdata.set(item[plot.Xaxis], item)
         }
       })
@@ -586,36 +713,34 @@
   }
 
   /**
-   * @description 缁熻鏁版嵁棰勫鐞嗭紝鍔ㄦ�佺敓鎴愮粺璁″瓧娈靛苟杩涜鏁版嵁杞崲
+   * @description 缁熻鏁版嵁棰勫鐞�
    */
-  getStaticMsg = (data) => {
-    const { plot, vstFields } = this.state
+  getStaticMsg = () => {
+    const { plot, vstFields, data } = this.state
 
     let percent = false
-    let decimal = 0
+    let decimal = vstFields ? vstFields.decimal : 0
 
     if (plot.show === 'percent') {
       percent = true
     }
-    if (vstFields) {
-      decimal = vstFields.decimal
-    }
 
-    if (!data) {
+    if (!data || data.length === 0) {
       this.setState({empty: true})
-      return {data: [], chartFields: [], selectFields: []}
+      return []
     }
 
     let _data = []
     let _cdata = fromJS(data).toJS()
-    let _chartFields = []
-    let _selectFields = []
 
     if (plot.repeat === 'average') {
       let _mdata = new Map()
       _cdata.forEach(item => {
         if (!item[plot.InfoType] || !item[plot.Xaxis]) return
-        _chartFields.push(item[plot.InfoType])
+
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
 
         item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
         if (typeof(item[plot.InfoValue]) !== 'number') {
@@ -651,7 +776,10 @@
       let _mdata = new Map()
       _cdata.forEach(item => {
         if (!item[plot.InfoType] || !item[plot.Xaxis]) return
-        _chartFields.push(item[plot.InfoType])
+
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
 
         item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
 
@@ -685,7 +813,10 @@
       let _mdata = new Map()
       _cdata.forEach(item => {
         if (!item[plot.InfoType] || !item[plot.Xaxis]) return
-        _chartFields.push(item[plot.InfoType])
+
+        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
+          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
+        }
 
         item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
 
@@ -710,31 +841,8 @@
       _data = [..._mdata.values()]
     }
 
-    _chartFields = Array.from(new Set(_chartFields))
-
-    if (plot.InfoDefNumber >= _chartFields.length) {
-      _selectFields = _chartFields
-    } else {
-      _selectFields = _chartFields.slice(0, plot.InfoDefNumber)
-    }
-
-    return {data: _data, chartFields: _chartFields, selectFields: _selectFields}
-  }
-
-  /**
-   * @description 鑾峰彇缁熻鍥捐〃灞曠ず鏁版嵁锛岄�氳繃閫夋嫨绫诲瀷绛涢��
-   */
-  getStaticData = () => {
-    const { plot, chartData, chartFields, selectFields } = this.state
-
-    let _data = []
-    if (selectFields.length === chartFields.length) {
-      _data = chartData
-    } else {
-      _data = chartData.filter(item => selectFields.includes(item[plot.InfoType]))
-    }
-
     this.setState({empty: _data.length === 0})
+
     return _data
   }
 
@@ -760,37 +868,19 @@
     let _data = []
     let _valfield = 'value'
     let _typefield = 'key'
-
-    let colors = new Map()
     let colorIndex = 0
 
     if (plot.datatype === 'statistics') {
       _valfield = plot.InfoValue
       _typefield = plot.InfoType
 
-      if (plot.colors && plot.colors.length > 0) { // 棰滆壊璁剧疆
-        plot.colors.forEach(item => {
-          if (!colors.has(item.type)) {
-            colors.set(item.type, item.color)
-          }
-        })
-      }
-
-      _data = this.getStaticData()
+      _data = this.getStaticMsg()
     } else {
       let data = this.getdata()
 
       if (plot.enabled === 'true') {
         this.customrender(data)
         return
-      }
-
-      if (plot.colors && plot.colors.length > 0) { // 棰滆壊璁剧疆
-        plot.colors.forEach(item => {
-          if (!colors.has(transfield[item.type])) {
-            colors.set(transfield[item.type], item.color)
-          }
-        })
       }
   
       const ds = new DataSet()
@@ -820,7 +910,7 @@
     const chart = new Chart({
       container: this.state.chartId,
       autoFit: true,
-      height: plot.height || 400
+      height: plot.height
     })
 
     chart.data(_data)
@@ -830,25 +920,22 @@
         range: [0, 1]
       })
     }
-    chart.scale(_valfield, {
+
+    let c = {
       nice: true,
-      range: [0, 0.93]
-    })
-    
-    // 鍧愭爣杞存牸寮忓寲
-    chart.axis(plot.Xaxis, {
-      label: {
-        formatter: (val) => {
-          if (!val || /^\s*$/.test(val)) return val
-          let _val = `${val}`
-          if (_val.length <= 11) return val
-          return _val.substring(0, 8) + '...'
-        },
-        style: { fill: plot.color }
-      },
-      line: { style: { fill: plot.color } }
-    })
-    chart.axis(_valfield, { grid: { style: { fill: plot.color } }, label: { style: { fill: plot.color } } })
+      range: [0, 0.9]
+    }
+
+    if (plot.min || plot.min === 0) {
+      c.min = plot.min
+    }
+    if (plot.max || plot.max === 0) {
+      c.max = plot.max
+    }
+    chart.scale(_valfield, c)
+
+    chart.axis(plot.Xaxis, plot.$xc)
+    chart.axis(_valfield, plot.$yc)
 
     if (!plot.legend || plot.legend === 'hidden') {
       chart.legend(false)
@@ -889,20 +976,23 @@
         }
       })
 
-    if (plot.colors && plot.colors.length > 0) {
+    if (plot.$colors) {
       let limit = chartColors.length
       _chart.color(_typefield, (key) => {
-        if (colors.get(key)) {
-          return colors.get(key)
+        if (plot.$colors.has(key)) {
+          if (plot.area === 'true' && plot.rampDirection === 'vertical') {
+            return plot.$colors.get(key).replace(/l\(9?0\) 0:|\s1:.*/ig, '')
+          }
+          return plot.$colors.get(key)
         } else {
-          colors.set(key, chartColors[colorIndex % limit])
           colorIndex++
+          return chartColors[(colorIndex - 1) % limit]
         }
       })
     } else {
       _chart.color(_typefield)
     }
-    if (plot.label === 'true') {
+    if (plot.label !== 'false') {
       _chart.label(_valfield, (value) => {
         if (plot.show === 'percent') {
           value = value + '%'
@@ -916,28 +1006,57 @@
       })
     }
 
-    if (plot.point === 'true' && plot.colors && plot.colors.length > 0) {
-      let limit = chartColors.length
-      chart
+    if (plot.point === 'true') {
+      let _chart = chart
         .point()
         .position(`${plot.Xaxis}*${_valfield}`)
-        .color(_typefield, (key) => {
-          if (colors.get(key)) {
-            return colors.get(key)
+        .size(3)
+        .shape('circle')
+
+      if (plot.$colors) {
+        let limit = chartColors.length
+        _chart.color(_typefield, (key) => {
+          if (plot.$colors.has(key)) {
+            return plot.$colors.get(key)
           } else {
-            colors.set(key, chartColors[colorIndex % limit])
             colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
           }
         })
-        .size(3)
-        .shape('circle')
-    } else if (plot.point === 'true') {
-      chart
-        .point()
+      } else {
+        _chart.color(_typefield)
+      }
+    }
+
+    if (plot.area === 'true') {
+      let area = chart
+        .area()
+        // .shape(plot.shape || 'smooth')
         .position(`${plot.Xaxis}*${_valfield}`)
-        .color(_typefield)
-        .size(3)
-        .shape('circle')
+        .tooltip(false)
+
+      if (plot.shape === 'smooth') {
+        area.shape('smooth')
+      }
+      if (plot.$colors) {
+        let limit = chartColors.length
+        area.color(_typefield, (key) => {
+          if (plot.$colors.has(key)) {
+            return plot.$colors.get(key)
+          } else {
+            colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
+          }
+        })
+      } else {
+        area.color(_typefield)
+      }
+    }
+
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
     }
     
     chart.render()
@@ -947,9 +1066,10 @@
    * @description 鑷畾涔夋覆鏌�
    */
   customrender = (data) => {
-    const { plot } = this.state
+    const { plot, transfield } = this.state
     const ds = new DataSet()
     const dv = ds.createView().source(data)
+
     dv.transform({
       type: 'map',
       callback(row) {
@@ -960,46 +1080,26 @@
       }
     })
 
+    let padding = [10, 30, 30, 30]
+
+    if (!plot.Bar_axis) {
+      padding = [10, plot.$paddingRight, 30, plot.$paddingLeft]
+    }
+
     const chart = new Chart({
       container: this.state.chartId,
       autoFit: true,
-      height: plot.height || 400
+      height: plot.height
     })
-
-    let _data = dv.rows
-    // dodge is not support linear attribute, please use category attribute! 鏃堕棿鏍煎紡
-    if (_data[0] && _data[0][plot.Xaxis] && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(_data[0][plot.Xaxis])) {
-      for (let i = 1; i < 12; i++) {
-        if (_data[i] && _data[i][plot.Xaxis] === _data[0][plot.Xaxis]) {
-          _data[i][plot.Xaxis] += ' '
-        } else {
-          break;
-        }
-      }
-      _data[0][plot.Xaxis] += ' '
-    }
-
-    chart.data(_data)
+    
+    // 鍧愭爣杞存牸寮忓寲
+    chart.axis(plot.Xaxis, plot.$xc)
 
     if (!plot.hasBar) {
       chart.scale(plot.Xaxis, {
         range: [0, 1]
       })
     }
-    
-    // 鍧愭爣杞存牸寮忓寲
-    chart.axis(plot.Xaxis, {
-      label: {
-        formatter: (val) => {
-          if (!val || /^\s*$/.test(val)) return val
-          let _val = `${val}`
-          if (_val.length <= 11) return val
-          return _val.substring(0, 8) + '...'
-        },
-        style: { fill: plot.color }
-      },
-      line: { style: { fill: plot.color } }
-    })
 
     if (!plot.legend || plot.legend === 'hidden') {
       chart.legend(false)
@@ -1020,16 +1120,215 @@
       })
     }
 
-    plot.customs.forEach((item, i) => {
-      chart.axis(item.name, item.axis)
-      
-      chart.scale(item.name, {
-        nice: true,
-        range: [0, 0.93]
+    chart.scale({
+      nice: true
+    })
+
+    let lablecfg = {
+      position: 'top',
+      offset: 2,
+      style: {
+        fill: '#fff'
+      }
+    }
+
+    if (plot.label === 'top') {
+      lablecfg.offset = -5
+      lablecfg.style.textBaseline = 'top'
+    } else if (plot.label === 'middle') {
+      lablecfg.position = 'middle'
+      lablecfg.offset = 0
+    } else if (plot.label === 'bottom') {
+      lablecfg.position = 'bottom'
+      lablecfg.offset = 0
+    } else if (plot.label === 'true') {
+      lablecfg.style.fill = plot.color
+    }
+
+    if (plot.Bar_axis) {
+      const view1 = chart.createView({
+        region: {
+          start: { x: 0, y: 0 },
+          end: { x: 1, y: 1 }
+        },
+        padding
+      })
+      const dst = new DataSet()
+      const dvt = dst.createView().source(data)
+  
+      dvt.transform({
+        type: 'fold',
+        fields: [...plot.Bar_axis],
+        key: 'key',
+        value: 'value'
+      })
+  
+      dvt.transform({
+        type: 'map',
+        callback(row) {
+          row.key = transfield[row.key] || row.key
+          return row
+        },
       })
 
-      if (item.chartType === 'bar') {
-        let _chart = chart
+      view1.data(dvt.rows)
+
+      let c = {
+        nice: true,
+        range: [0, 0.9]
+      }
+  
+      if (plot.min || plot.min === 0) {
+        c.min = plot.min
+      }
+      if (plot.max || plot.max === 0) {
+        c.max = plot.max
+      }
+      view1.scale('value', c)
+      view1.axis('value', plot.$yc)
+  
+      view1.legend(false)
+
+      let colorIndex = 0
+  
+      if (plot.adjust !== 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust([
+            {
+              type: 'dodge',
+              marginRatio: 0
+            }
+          ])
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: key,
+              value: value
+            }
+          })
+
+        if (plot.$colors) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+
+            if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
+              lablecfg.style.fill = plot.$colors.get(key)
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      } else if (plot.adjust === 'stack') {
+        let _chart = view1
+          .interval()
+          .position(`${plot.Xaxis}*value`)
+          .adjust('stack')
+          .shape(plot.shape || 'rect')
+          .tooltip(`${plot.Xaxis}*value*key`, (name, value, type) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            return {
+              name: type,
+              value: value
+            }
+          })
+  
+        if (plot.$colors) {
+          let limit = chartColors.length
+          _chart.color('key', (key) => {
+            if (plot.$colors.has(key)) {
+              return plot.$colors.get(key)
+            } else {
+              colorIndex++
+              return chartColors[(colorIndex - 1) % limit]
+            }
+          })
+        } else {
+          _chart.color('key')
+        }
+        if (plot.label !== 'false') {
+          _chart.label('value*key', (value, key) => {
+            if (plot.show === 'percent') {
+              value = value + '%'
+            }
+            if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
+              lablecfg.style.fill = plot.$colors.get(key)
+            }
+            return {
+              content: value,
+              ...lablecfg
+            }
+          })
+        }
+
+        if (plot.barSize || plot.correction) {
+          _chart.size(plot.barSize || 35)
+        }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
+      }
+    }
+
+    const view2 = chart.createView({
+      region: {
+        start: { x: 0, y: 0 },
+        end: { x: 1, y: 1 }
+      },
+      padding
+    })
+
+    view2.data(dv.rows)
+    view2.legend(false)
+
+    plot.customs.forEach((item, i) => {
+      if (item.chartType === 'bar' && !plot.Bar_axis) {
+        view2.axis(item.name, item.axis)
+      
+        let c = {
+          nice: true,
+          range: [0, 0.9]
+        }
+    
+        if (item.min || item.min === 0) {
+          c.min = item.min
+        }
+        if (item.max || item.max === 0) {
+          c.max = item.max
+        }
+
+        view2.scale(item.name, c)
+        let _chart = view2
           .interval()
           .position(`${plot.Xaxis}*${item.name}`)
           .color(item.color)
@@ -1044,21 +1343,43 @@
         if (plot.barSize) {
           _chart.size(plot.barSize || 35)
         }
-        if (item.label === 'true') {
+        if (item.label !== 'false') {
           _chart.label(item.name, (value) => {
             if (plot.show === 'percent') {
               value = value + '%'
             }
+            if (plot.label === 'true' && plot.labelColor === 'custom' && item.color) {
+              lablecfg.style.fill = item.color
+            }
             return {
               content: value,
-              style: {
-                fill: plot.color
-              }
+              ...lablecfg
             }
           })
         }
+        if (plot.barRadius) {
+          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+        }
       } else if (item.chartType === 'line') {
-        let _chart = chart
+        if (!plot.Bar_axis) {
+          view2.axis(item.name, item.axis)
+        } else {
+          view2.axis(item.name, { grid: null, title: null, label: null })
+        }
+        let c = {
+          nice: true,
+          range: [0, 0.9]
+        }
+    
+        if (item.min || item.min === 0) {
+          c.min = item.min
+        }
+        if (item.max || item.max === 0) {
+          c.max = item.max
+        }
+
+        view2.scale(item.name, c)
+        let _chart = view2
           .line()
           .position(`${plot.Xaxis}*${item.name}`)
           .color(item.color)
@@ -1095,6 +1416,14 @@
       }
     })
 
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        if (t === 'element-active' || t === 'element-highlight') {
+          chart.interaction(t)
+        }
+      })
+    }
+
     chart.render()
   }
 
@@ -1102,42 +1431,24 @@
    * @description 鏌辩姸鍥炬覆鏌�
    */
   barrender = () => {
-    const { plot, transfield } = this.state
+    const { plot, transfield, config } = this.state
 
     let _data = []
     let _valfield = 'value'
     let _typefield = 'key'
-
-    let colors = new Map()
     let colorIndex = 0
 
     if (plot.datatype === 'statistics') {
       _valfield = plot.InfoValue
       _typefield = plot.InfoType
 
-      if (plot.colors && plot.colors.length > 0) { // 棰滆壊璁剧疆
-        plot.colors.forEach(item => {
-          if (!colors.has(item.type)) {
-            colors.set(item.type, item.color)
-          }
-        })
-      }
-
-      _data = this.getStaticData()
+      _data = this.getStaticMsg()
     } else {
       let data = this.getdata()
 
       if (plot.enabled === 'true') {
         this.customrender(data)
         return
-      }
-
-      if (plot.colors && plot.colors.length > 0) { // 棰滆壊璁剧疆
-        plot.colors.forEach(item => {
-          if (!colors.has(transfield[item.type])) {
-            colors.set(transfield[item.type], item.color)
-          }
-        })
       }
 
       const ds = new DataSet()
@@ -1166,42 +1477,26 @@
     const chart = new Chart({
       container: this.state.chartId,
       autoFit: true,
-      height: plot.height || 400
+      height: plot.height
     })
-
-    // dodge is not support linear attribute, please use category attribute! 鏃堕棿鏍煎紡
-    if (_data[0] && _data[0][plot.Xaxis] && /^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(_data[0][plot.Xaxis])) {
-      for (let i = 1; i < 12; i++) {
-        if (_data[i] && _data[i][plot.Xaxis] === _data[0][plot.Xaxis]) {
-          _data[i][plot.Xaxis] += ' '
-        } else {
-          break;
-        }
-      }
-      _data[0][plot.Xaxis] += ' '
-    }
 
     chart.data(_data)
 
-    chart.scale(_valfield, {
+    let c = {
       nice: true,
-      range: [0, 0.93]
-    })
+      range: [0, 0.9]
+    }
 
-    // 鍧愭爣杞存牸寮忓寲
-    chart.axis(plot.Xaxis, {
-      label: {
-        formatter: (val) => {
-          if (!val || /^\s*$/.test(val)) return val
-          let _val = `${val}`
-          if (_val.length <= 11) return val
-          return _val.substring(0, 8) + '...'
-        },
-        style: { fill: plot.color }
-      },
-      line: { style: { fill: plot.color } }
-    })
-    chart.axis(_valfield, { grid: { style: { fill: plot.color } }, label: { style: { fill: plot.color } } })
+    if (plot.min || plot.min === 0) {
+      c.min = plot.min
+    }
+    if (plot.max || plot.max === 0) {
+      c.max = plot.max
+    }
+    chart.scale(_valfield, c)
+
+    chart.axis(plot.Xaxis, plot.$xc)
+    chart.axis(_valfield, plot.$yc)
 
     if (!plot.legend || plot.legend === 'hidden') {
       chart.legend(false)
@@ -1221,8 +1516,44 @@
       })
     }
 
+    let lablecfg = {
+      position: 'top',
+      offset: 2,
+      style: {
+        fill: '#fff'
+      }
+    }
+
+    if (plot.label === 'top') {
+      lablecfg.offset = -5
+      lablecfg.style.textBaseline = 'top'
+    } else if (plot.label === 'middle') {
+      lablecfg.position = 'middle'
+      lablecfg.offset = 0
+    } else if (plot.label === 'bottom') {
+      lablecfg.position = 'bottom'
+      lablecfg.offset = 0
+    } else if (plot.label === 'true') {
+      lablecfg.style.fill = plot.color
+    }
+
     if (plot.transpose === 'true') {
       chart.coordinate().transpose()
+      if (plot.label === 'top') {
+        delete lablecfg.style.textBaseline
+        lablecfg.position = 'right'
+        lablecfg.offset = -3
+        lablecfg.style.textAlign = 'end'
+      } else if (plot.label === 'middle') {
+        lablecfg.position = 'middle'
+        lablecfg.offset = 0
+      } else if (plot.label === 'bottom') {
+        lablecfg.position = 'left'
+        lablecfg.offset = 2
+      } else if (plot.label === 'true') {
+        lablecfg.position = 'right'
+        lablecfg.offset = 2
+      }
     }
 
     if (plot.coordinate === 'polar') {
@@ -1250,35 +1581,50 @@
           }
         })
 
-      if (plot.colors && plot.colors.length > 0) {
+      if (plot.$colors) {
         let limit = chartColors.length
         _chart.color(_typefield, (key) => {
-          if (colors.get(key)) {
-            return colors.get(key)
+          if (plot.$colors.has(key)) {
+            return plot.$colors.get(key)
           } else {
-            colors.set(key, chartColors[colorIndex % limit])
             colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
           }
         })
       } else {
         _chart.color(_typefield)
       }
-      if (plot.label === 'true') {
-        _chart.label(_valfield, (value) => {
+      if (plot.label !== 'false') {
+        _chart.label(`${_valfield}*${_typefield}`, (value, key) => {
           if (plot.show === 'percent') {
             value = value + '%'
           }
+
+          if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
+            lablecfg.style.fill = plot.$colors.get(key)
+          }
+
           return {
             content: value,
-            style: {
-              fill: plot.color
-            }
+            ...lablecfg
           }
         })
       }
 
       if (plot.barSize || plot.correction) {
         _chart.size(plot.barSize || 35)
+      }
+      if (plot.selectColor) {
+        _chart.state({
+          selected: {
+            style: {
+              fill: plot.selectColor,
+            }
+          }
+        })
+      }
+      if (plot.barRadius) {
+        _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
       }
     } else if (plot.adjust === 'stack') {
       let _chart = chart
@@ -1293,29 +1639,32 @@
           }
         })
 
-      if (plot.colors && plot.colors.length > 0) {
+      if (plot.$colors) {
         let limit = chartColors.length
         _chart.color(_typefield, (key) => {
-          if (colors.get(key)) {
-            return colors.get(key)
+          if (plot.$colors.has(key)) {
+            return plot.$colors.get(key)
           } else {
-            colors.set(key, chartColors[colorIndex % limit])
             colorIndex++
+            return chartColors[(colorIndex - 1) % limit]
           }
         })
       } else {
         _chart.color(_typefield)
       }
-      if (plot.label === 'true') {
-        _chart.label(_valfield, (value) => {
+      if (plot.label !== 'false') {
+        _chart.label(`${_valfield}*${_typefield}`, (value, key) => {
           if (plot.show === 'percent') {
             value = value + '%'
           }
+
+          if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
+            lablecfg.style.fill = plot.$colors.get(key)
+          }
+
           return {
             content: value,
-            style: {
-              fill: plot.color
-            }
+            ...lablecfg
           }
         })
       }
@@ -1323,70 +1672,32 @@
       if (plot.barSize || plot.correction) {
         _chart.size(plot.barSize || 35)
       }
-    }
-
-    if (plot.linkmenu && plot.linkmenu.length > 0) {
-      let menu_id = plot.linkmenu.slice(-1)[0]
-      let menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || ''
-
-      chart.on('element:dblclick', (ev) => {
-        if (!menu) {
-          notification.warning({
-            top: 92,
-            message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�',
-            duration: 5
-          })
-          return
-        }
-
-        try {
-          let data = ev.data.data
-          let primaryId = ''
-          if (this.state.config.setting.primaryKey && data) {
-            primaryId = data[this.state.config.setting.primaryKey] || ''
-          }
-
-          let newtab = {
-            ...menu,
-            selected: true,
-            param: {
-              $BID: primaryId
+      if (plot.selectColor) {
+        _chart.state({
+          selected: {
+            style: {
+              fill: plot.selectColor,
             }
           }
-  
-          let tabs = this.props.tabviews.filter(tab => {
-            tab.selected = false
-            return tab.MenuID !== newtab.MenuID
-          })
-  
-          if (this.props.tabviews.length > tabs.length) {
-            this.props.modifyTabview(fromJS(tabs).toJS())
-          }
-  
-          this.setState({}, () => {
-            tabs.push(newtab)
-            this.props.modifyTabview(tabs)
-          })
-        } catch {
-          console.warn('鑿滃崟鎵撳紑澶辫触锛�')
-        }
+        })
+      }
+      if (plot.barRadius) {
+        _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
+      }
+    }
+
+    chart.on('element:click', (ev) => {
+      let data = ev.data.data
+      MKEmitter.emit('resetSelectLine', config.uuid, (data ? data.$$uuid : ''), null)
+    })
+
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
       })
     }
 
     chart.render()
-  }
-
-  /**
-   * @description 缁熻鍥捐〃锛岀粺璁$被鍨嬪垏鎹�
-   */
-  handleChange = (val) => {
-    this.setState({selectFields: val}, () => {
-      let _element = document.getElementById(this.state.chartId)
-      if (_element) {
-        _element.innerHTML = ''
-      }
-      this.viewrender()
-    })
   }
 
   refreshSearch = (list) => {
@@ -1396,7 +1707,7 @@
   }
 
   render() {
-    const { config, loading, plot, empty, chartFields, selectFields, BID } = this.state
+    const { config, loading, empty, BID } = this.state
 
     return (
       <div className="custom-line-chart-plot-box" style={config.style}>
@@ -1432,19 +1743,8 @@
                 )
               }
             })}
-            {plot.datatype === 'statistics' && chartFields.length > 0 ? <Select
-              mode="multiple"
-              showSearch
-              showArrow={true}
-              value={selectFields}
-              onChange={this.handleChange}
-              maxTagCount={0}
-              maxTagPlaceholder={(option) => <div className="type-label">{option.join('銆�')}</div>}
-            >
-              {chartFields.map((item, i) => <Select.Option key={i} value={item}>{item}</Select.Option>)}
-            </Select> : null}
           </div>
-          <div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div>
+          <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 25}} id={this.state.chartId}></div>
         </div>
         {empty ? <Empty description={false}/> : null}
       </div>
@@ -1452,17 +1752,4 @@
   }
 }
 
-const mapStateToProps = (state) => {
-  return {
-    tabviews: state.tabviews,
-    permMenus: state.permMenus,
-  }
-}
-
-const mapDispatchToProps = (dispatch) => {
-  return {
-    modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews))
-  }
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(LineChart)
\ No newline at end of file
+export default LineChart
\ No newline at end of file
diff --git a/src/tabviews/custom/components/chart/antv-bar-line/index.scss b/src/tabviews/custom/components/chart/antv-bar-line/index.scss
index cd9f4ce..714a088 100644
--- a/src/tabviews/custom/components/chart/antv-bar-line/index.scss
+++ b/src/tabviews/custom/components/chart/antv-bar-line/index.scss
@@ -9,6 +9,7 @@
   .canvas-wrap {
     margin: 0 0px;
     position: relative;
+    min-height: calc(100% - 45px);
     .chart-action {
       position: absolute;
       top: 0px;
@@ -22,7 +23,7 @@
 
   .canvas {
     margin: 0;
-    padding: 20px 15px 15px;
+    padding: 15px 10px 10px;
     letter-spacing: 0px;
   }
   .canvas.empty {
@@ -45,6 +46,10 @@
     top: 0;
     right: 0px;
     bottom: 0px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: justify;
     z-index: 1;
 
     .ant-spin-blur {
@@ -53,47 +58,6 @@
       height: 100%;
       opacity: 0.5;
       background: #ffffff;
-    }
-  }
-  > .ant-select {
-    width: 150px;
-    float: right;
-    position: relative;
-    z-index: 1;
-    .ant-select-selection {
-      min-height: 24px;
-      height: 28px;
-      li {
-        background: unset;
-        border: 0;
-        width: 99%;
-        padding: 0;
-        margin-right: 0;
-        cursor: pointer;
-
-        .type-label {
-          overflow: hidden;
-          word-break: break-word;
-          white-space: nowrap;
-          text-overflow: ellipsis;
-        }
-      }
-      li + li {
-        margin-top: 0;
-        width: 1%;
-        opacity: 0;
-      }
-    }
-  }
-  > .ant-select.ant-select-focused {
-    .ant-select-selection {
-      li {
-        width: 50%;
-      }
-      li + li {
-        width: 49%;
-        opacity: 1;
-      }
     }
   }
   .g2-tooltip-list{
diff --git a/src/tabviews/custom/components/chart/antv-dashboard/index.jsx b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
new file mode 100644
index 0000000..041e41d
--- /dev/null
+++ b/src/tabviews/custom/components/chart/antv-dashboard/index.jsx
@@ -0,0 +1,618 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Chart, registerShape } from '@antv/g2'
+import { Spin, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import asyncComponent from '@/utils/asyncComponent'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+
+registerShape('point', 'pointer', {
+  draw(cfg, container) {
+    const group = container.addGroup({});
+    // 鑾峰彇鏋佸潗鏍囩郴涓嬬敾甯冧腑蹇冪偣
+    const center = this.parsePoint({ x: 0, y: 0 });
+    // 缁樺埗鎸囬拡
+    group.addShape('line', {
+      attrs: {
+        x1: center.x,
+        y1: center.y,
+        x2: cfg.x,
+        y2: cfg.y,
+        stroke: cfg.color,
+        lineWidth: 5,
+        lineCap: 'round',
+      },
+    });
+    group.addShape('circle', {
+      attrs: {
+        x: center.x,
+        y: center.y,
+        r: 9.75,
+        stroke: cfg.color,
+        lineWidth: 4.5,
+        fill: '#fff',
+      },
+    });
+    return group;
+  },
+})
+
+registerShape('point', 'hidden', {
+  draw(cfg, container) {
+    return container.addGroup({})
+  }
+})
+
+class DashboardChart extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+  }
+
+  state = {
+    BID: '',                   // 涓婄骇ID
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
+    chartId: Utils.getuuid(),  // 鍥捐〃Id
+    title: '',                 // 缁勪欢鏍囬
+    sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
+    plot: null,                // 鍥捐〃璁剧疆
+    data: {},                  // 鏁版嵁
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config, data, initdata, BID } = this.props
+    let _config = fromJS(config).toJS()
+
+    let _data = null
+    let _sync = _config.setting.sync === 'true'
+
+    if (_sync && data) {
+      _data = data[config.dataName] || []
+      _sync = false
+    } else if (_sync && initdata) {
+      _data = initdata || []
+      _sync = false
+    }
+
+    if (_config.subtype === 'ratioboard') {
+      _data = _data || []
+    } else {
+      if (_data && Array.isArray(_data)) {
+        _data = _data[0] || {}
+      } else {
+        _data = {}
+      }
+    }
+
+    let height = config.plot.height || 400
+    if (config.plot.title) {
+      _config.plot.height = height - 75
+    } else {
+      _config.plot.height = height - 30
+    }
+    _config.style.height = height
+
+    this.setState({
+      config: _config,
+      data: _data,
+      BID: BID || '',
+      arr_field: _config.columns.map(col => col.field).join(','),
+      plot: _config.plot,
+      sync: _sync,
+      title: config.plot.title
+    }, () => {
+      if (config.setting.sync !== 'true' && config.setting.onload === 'true') {
+        this.loadData()
+      } else if (config.setting.sync === 'true') {
+        this.handleData()
+      }
+    })
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { sync, config } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = null
+
+      if (config.subtype === 'ratioboard') {
+        _data = []
+        if (nextProps.data && nextProps.data[config.dataName]) {
+          _data = nextProps.data[config.dataName] || []
+        }
+      } else {
+        _data = {}
+        if (nextProps.data && nextProps.data[config.dataName]) {
+          _data = nextProps.data[config.dataName] || {}
+        }
+        if (_data.hasOwnProperty(config.plot.valueField)) {
+          _data.value = _data[config.plot.valueField]
+        }
+      }
+
+      this.setState({sync: false, data: _data}, () => {
+        this.handleData()
+      })
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    this.handleTimer()
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    clearTimeout(this.timer)
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+  }
+
+  handleTimer = () => {
+    const { config } = this.state
+
+    if (!config.timer) return
+
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
+
+    let timer = _change[config.timer]
+
+    if (!timer) return
+
+    let _param = {
+      func: 's_get_timers_role',
+      LText: `select '${window.GLOB.appkey || ''}','${config.uuid}'`,
+      timer_type: config.timer,
+      component_id: config.uuid
+    }
+    
+    _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) {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return
+      } else if (result.run_type) {
+        this.setState({timer})
+        this.timer = setTimeout(() => {
+          this.timerTask()
+        }, timer)
+      }
+    })
+  }
+
+  timerTask = () => {
+    const { timer } = this.state
+    if (!timer) return
+    
+    this.loadData(true)
+    
+    this.timer = setTimeout(() => {
+      this.timerTask()
+    }, timer)
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData()
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.state
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID) {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  handleData = () => {
+    let _element = document.getElementById(this.state.chartId)
+    if (_element) {
+      _element.innerHTML = ''
+    }
+    this.viewrender()
+  }
+
+  async loadData (hastimer) {
+    const { mainSearch, menuType } = this.props
+    const { config, arr_field, BID } = this.state
+
+    if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: {}
+      }, () => {
+        this.handleData()
+      })
+      return
+    }
+
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    if (!hastimer) {
+      this.setState({
+        loading: true
+      })
+    }
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      let data = null
+      if (config.subtype === 'ratioboard') {
+        data = result.data || []
+      } else {
+        data = {}
+        if (result.data && result.data[0] && result.data[0].hasOwnProperty(config.plot.valueField)) {
+          data.value = result.data[0][config.plot.valueField]
+        }
+      }
+
+      this.setState({
+        data,
+        loading: false
+      }, () => {
+        this.handleData()
+      })
+    } else {
+      this.setState({
+        loading: false,
+        timer: null
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  viewrender = () => {
+    const { config } = this.state
+    if (config.subtype === 'ratioboard') {
+      this.ratioboardrender()
+    } else {
+      this.dashboardrender()
+    }
+  }
+
+  getratiodata = () => {
+    const { data, plot } = this.state
+
+    let colors = {}
+    if (plot.colors && plot.colors.length > 0) {
+      plot.colors.forEach(item => {
+        colors[item.tick] = item.color
+      })
+    }
+
+    return data.map(item => {
+      let val = +item[plot.valueField]
+      let type = item[plot.labelField] || ''
+      if (isNaN(val)) {
+        val = 0
+      }
+      return {
+        type: type,
+        value: val,
+        $percent: val / plot.maxValue,
+        $color: colors[type] || '#1890ff'
+      }
+    })
+  }
+
+  ratioboardrender = () => {
+    const { plot, chartId } = this.state
+    const data = this.getratiodata()
+
+    const chart = new Chart({
+      container: chartId,
+      autoFit: true,
+      height: plot.height,
+    })
+    
+    chart.data(data)
+    chart.coordinate('polar', {
+      startAngle: -Math.PI / 2,
+      endAngle: 3 * Math.PI / 2,
+      radius: (plot.radius || 75) / 100
+    })
+    chart.scale('$percent', {
+      min: 0,
+      max: 1,
+      tickInterval: 1,
+    })
+    chart.axis(false)
+    chart.facet('rect', {
+      fields: ['type'],
+      showTitle: false,
+      eachView: function eachView(view, facet) {
+        const data = facet.data[0]
+
+        view.point().position('').shape('hidden')
+
+        view.annotation().arc({
+          top: false,
+          start: [0, 1],
+          end: [0.9999, 1],
+          style: {
+            stroke: plot.backColor,
+            lineWidth: 10
+          }
+        })
+
+        let _tick = data.$percent
+        if (_tick >= 1) {
+          _tick = 0.9999
+        }
+
+        view.annotation().arc({
+          start: [0, 1],
+          end: [_tick, 1],
+          style: {
+            stroke: data.$color,
+            lineWidth: 10,
+          }
+        })
+        // 浠〃鐩樹俊鎭�
+        let text = ''
+        if (plot.percent === 'true') {
+          text = +(data.$percent * 100).toFixed(2) + '%'
+        } else {
+          text = data.value
+        }
+    
+        view.annotation().text({
+          position: ['50%', '45%'],
+          content: data.type,
+          style: {
+            fontSize: plot.fontSize * 0.8,
+            fill: plot.labelColor,
+            fontWeight: 300,
+            textAlign: 'center'
+          },
+          offsetX: 0
+        })
+        view.annotation().text({
+          position: ['50%', '55%'],
+          content: text,
+          style: {
+            fontSize: plot.fontSize,
+            fill: plot.labelColor,
+            fontWeight: 500,
+            textAlign: 'center'
+          },
+          offsetX: 0,
+          offsetY: 10
+        })
+      }
+    })
+    chart.render()
+  }
+
+  /**
+   * @description 浠〃鐩樻覆鏌�
+   */
+  dashboardrender = () => {
+    const { plot, chartId, data } = this.state
+
+    let _data = fromJS(data).toJS()
+
+    if (_data.hasOwnProperty('value')) {
+      if (_data.value === '' || _data.value === null) {
+        delete _data.value
+      } else {
+        _data.value = +_data.value
+
+        if (isNaN(_data.value)) {
+          delete _data.value
+        } else if (_data.value > plot.maxValue) {
+          _data.value = plot.maxValue
+        }
+      }
+    }
+
+    const chart = new Chart({
+      container: chartId,
+      autoFit: true,
+      height: plot.height,
+      padding: [0, 0, 0, 0],
+    })
+    chart.data([_data])
+    chart.scale('value', {
+      min: 0,
+      max: plot.maxValue,
+      tickInterval: plot.tickInterval,
+    })
+    chart.coordinate('polar', {
+      startAngle: (-9 / 8) * Math.PI,
+      endAngle: (1 / 8) * Math.PI,
+      radius: 0.75,
+    })
+
+    chart.axis('1', false)
+    chart.axis('value', {
+      line: null,
+      label: {
+        offset: -36,
+        style: {
+          fontSize: 18,
+          fill: plot.tickColor,
+          textAlign: 'center',
+          textBaseline: 'middle',
+        },
+      },
+      tickLine: {
+        length: -24,
+        style: {
+          stroke: plot.tickColor
+        }
+      },
+      grid: null,
+    })
+    chart.legend(false)
+    chart.tooltip(false)
+    chart
+      .point()
+      .position('value*1')
+      .shape('pointer')
+      .color('value', (val) => {
+        if (!val && val !== 0) return 'transparent'
+        let _color = '#1890FF'
+        if (plot.colors && plot.colors.length > 0) {
+          _color = plot.colors[plot.colors.length - 1].color || '#1890FF'
+          plot.colors.some(item => {
+            if (item.tick > val) {
+              _color = item.color
+              return true
+            }
+            return false
+          })
+        }
+        return _color
+      })
+      .animate({
+        appear: {
+          animation: 'fade-in'
+        }
+      })
+
+    // 缁樺埗浠〃鐩樿儗鏅�
+    chart.annotation().arc({
+      top: false,
+      start: [0, 1],
+      end: [plot.maxValue, 1],
+      style: {
+        stroke: '#CBCBCB',
+        lineWidth: 18,
+        lineDash: null,
+      },
+    })
+
+    if (!plot.colors || plot.colors.length === 0) {
+      chart.annotation().arc({
+        start: [0, 1],
+        end: [plot.maxValue, 1],
+        style: {
+          stroke: '#1890FF',
+          lineWidth: 18,
+          lineDash: null,
+        },
+      })
+    } else {
+      let start = 0
+      plot.colors.forEach(item => {
+        chart.annotation().arc({
+          start: [start, 1],
+          end: [item.tick, 1],
+          style: {
+            stroke: item.color,
+            lineWidth: 18,
+            lineDash: null,
+          },
+        })
+        start = item.tick
+      })
+    }
+
+    if (plot.label) {
+      chart.annotation().text({
+        position: ['50%', '85%'],
+        content: plot.label,
+        style: {
+          fontSize: 20,
+          fill: plot.labelColor,
+          textAlign: 'center',
+        },
+      })
+    }
+
+    if (data.hasOwnProperty('value')) {
+      let val = data.value
+      if (plot.percent !== 'false' && plot.maxValue) {
+        val = +(val / plot.maxValue * 100).toFixed(2) + ' %'
+      }
+  
+      chart.annotation().text({
+        position: ['50%', '90%'],
+        content: val,
+        style: {
+          fontSize: 36,
+          fill: plot.labelColor,
+          textAlign: 'center',
+        },
+        offsetY: 15,
+      })
+    }
+
+    chart.render()
+  }
+
+  render() {
+    const { config, loading, empty } = this.state
+
+    return (
+      <div className="custom-dashboard-plot-box" style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        <NormalHeader config={config} />
+        <div className="canvas-wrap">
+          <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 30}} id={this.state.chartId}></div>
+        </div>
+      </div>
+    )
+  }
+}
+
+export default DashboardChart
\ No newline at end of file
diff --git a/src/tabviews/custom/components/chart/antv-dashboard/index.scss b/src/tabviews/custom/components/chart/antv-dashboard/index.scss
new file mode 100644
index 0000000..d9f3566
--- /dev/null
+++ b/src/tabviews/custom/components/chart/antv-dashboard/index.scss
@@ -0,0 +1,110 @@
+.custom-dashboard-plot-box {
+  position: relative;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+  
+  .canvas-wrap {
+    margin: 0 0px;
+    position: relative;
+    min-height: calc(100% - 45px);
+    .chart-action {
+      position: absolute;
+      top: 2px;
+      right: 5px;
+      z-index: 1;
+    }
+    .chart-action.with-title {
+      top: 35px;
+    }
+  }
+
+  .canvas {
+    margin: 0;
+    padding: 15px;
+    letter-spacing: 0px;
+  }
+  .canvas.empty {
+    div {
+      opacity: 0;
+    }
+  }
+  .ant-empty {
+    position: absolute;
+    top: calc(50% - 34px);
+    left: calc(50% - 92px);
+
+    .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-select {
+    width: 150px;
+    float: right;
+    position: relative;
+    z-index: 1;
+    .ant-select-selection {
+      min-height: 24px;
+      height: 28px;
+      li {
+        background: unset;
+        border: 0;
+        width: 99%;
+        padding: 0;
+        margin-right: 0;
+        cursor: pointer;
+
+        .type-label {
+          overflow: hidden;
+          word-break: break-word;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+        }
+      }
+      li + li {
+        margin-top: 0;
+        width: 1%;
+        opacity: 0;
+      }
+    }
+  }
+  > .ant-select.ant-select-focused {
+    .ant-select-selection {
+      li {
+        width: 50%;
+      }
+      li + li {
+        width: 49%;
+        opacity: 1;
+      }
+    }
+  }
+  .g2-tooltip-list{
+    display: none;
+  }
+  .g2-tooltip-title + .g2-tooltip-list{
+    display: block;
+  }
+}
diff --git a/src/tabviews/custom/components/chart/antv-pie/index.jsx b/src/tabviews/custom/components/chart/antv-pie/index.jsx
index c7fbd33..002b51b 100644
--- a/src/tabviews/custom/components/chart/antv-pie/index.jsx
+++ b/src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -3,7 +3,7 @@
 import { is, fromJS } from 'immutable'
 import { Chart } from '@antv/g2'
 import { connect } from 'react-redux'
-import DataSet from '@antv/data-set'
+import DataSet, { DataView } from '@antv/data-set'
 import { Spin, Empty, notification } from 'antd'
 import moment from 'moment'
 
@@ -55,17 +55,23 @@
       _sync = false
     }
 
+    let height = config.plot.height || 400
     if (config.plot.title || config.search.length > 0) {
-      _config.plot.height = _config.plot.height - 80
+      _config.plot.height = height - 75
     } else {
-      _config.plot.height = _config.plot.height - 30
+      _config.plot.height = height - 30
     }
 
-    if (_config.style) {
-      _config.style = {..._config.style, minHeight: (config.plot.height || 400)}
-    } else {
-      _config.style = {minHeight: (config.plot.height || 400)}
-    }
+    _config.style.height = height
+
+    let decimal = 0
+    _config.columns.forEach(col => {
+      if (_config.plot.Yaxis === col.field && /Decimal/ig.test(col.datatype)) {
+        decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
+      }
+    })
+
+    _config.plot.$decimal = decimal
 
     this.setState({
       config: _config,
@@ -100,12 +106,10 @@
       this.setState({sync: false, data: _data}, () => {
         this.handleData()
       })
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -136,16 +140,7 @@
 
     if (!config.timer) return
 
-    const _change = {
-      '15s': 15000,
-      '30s': 30000,
-      '1min': 60000,
-      '5min': 300000,
-      '10min': 600000,
-      '15min': 900000,
-      '30min': 1800000,
-      '1hour': 3600000
-    }
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
 
     let timer = _change[config.timer]
 
@@ -210,11 +205,18 @@
   }
 
   handleData = () => {
-    let _element = document.getElementById(this.state.chartId)
+    const { plot, chartId } = this.state
+    
+    let _element = document.getElementById(chartId)
     if (_element) {
       _element.innerHTML = ''
     }
-    this.pierender()
+
+    if (plot.shape === 'nest') {
+      this.nestrender()
+    } else {
+      this.pierender()
+    }
   }
 
   async loadData (hastimer) {
@@ -231,13 +233,18 @@
     }
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
       let keys = searches.map(item => item.key)
       mainSearch.forEach(item => {
         if (!keys.includes(item.key)) {
           searches.push(item)
         }
       })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     if (!hastimer) {
@@ -277,19 +284,12 @@
    * 3銆佹煴鐘跺浘鏁版嵁琛ラ綈
    */
   getdata = () => {
-    const { data, plot, config } = this.state
+    const { data, plot } = this.state
 
     if (!data) {
       this.setState({empty: true})
       return []
     }
-
-    let decimal = 0
-    config.columns.forEach(col => {
-      if (plot.Yaxis === col.field && /Decimal/ig.test(col.datatype)) {
-        decimal = +col.datatype.replace(/^Decimal\(18,/ig, '').replace(/\)/ig, '')
-      }
-    })
 
     let _data = []
     let _cdata = fromJS(data).toJS()
@@ -300,14 +300,16 @@
         if (typeof(item[plot.Yaxis]) !== 'number') {
           item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
           if (isNaN(item[plot.Yaxis])) {
-            item[plot.Yaxis] = 0
+            return
           }
+        } else if (!item[plot.Xaxis]) {
+          return
         }
 
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
+        if (!_mdata.has(item[plot.Xaxis])) {
           item.$count = 1
           _mdata.set(item[plot.Xaxis], item)
-        } else if (item[plot.Xaxis]) {
+        } else {
           let _item = _mdata.get(item[plot.Xaxis])
           _item.$count++
           _item[plot.Yaxis] += item[plot.Yaxis]
@@ -318,8 +320,7 @@
       _data = [..._mdata.values()]
       _data = _data.map(item => {
         item[plot.Yaxis] = item[plot.Yaxis] / item.$count
-        item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
-        item[plot.Yaxis] = +item[plot.Yaxis]
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
 
         return item
       })
@@ -329,13 +330,15 @@
         if (typeof(item[plot.Yaxis]) !== 'number') {
           item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
           if (isNaN(item[plot.Yaxis])) {
-            item[plot.Yaxis] = 0
+            return
           }
+        } else if (!item[plot.Xaxis]) {
+          return
         }
 
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
+        if (!_mdata.has(item[plot.Xaxis])) {
           _mdata.set(item[plot.Xaxis], item)
-        } else if (item[plot.Xaxis]) {
+        } else {
           let _item = _mdata.get(item[plot.Xaxis])
           _item[plot.Yaxis] += item[plot.Yaxis]
           _mdata.set(item[plot.Xaxis], _item)
@@ -344,34 +347,390 @@
 
       _data = [..._mdata.values()]
       _data = _data.map(item => {
-        item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
-        item[plot.Yaxis] = +item[plot.Yaxis]
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
         return item
       })
     } else { // plot.repeat === 'unrepeat'
       let _mdata = new Map()
       _cdata.forEach(item => {
-        if (item[plot.Xaxis] && !_mdata.has(item[plot.Xaxis])) {
-          
-          if (typeof(item[plot.Yaxis]) !== 'number') {
-            item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
-            if (isNaN(item[plot.Yaxis])) {
-              item[plot.Yaxis] = 0
-            }
-          }
-
-          item[plot.Yaxis] = item[plot.Yaxis].toFixed(decimal)
-          item[plot.Yaxis] = +item[plot.Yaxis]
-
-          _mdata.set(item[plot.Xaxis], item)
+        if (!item[plot.Xaxis] || _mdata.has(item[plot.Xaxis])) {
+          return
         }
+        if (typeof(item[plot.Yaxis]) !== 'number') {
+          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
+          if (isNaN(item[plot.Yaxis])) {
+            return
+          }
+        }
+
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
+
+        _mdata.set(item[plot.Xaxis], item)
       })
 
       _data = [..._mdata.values()]
     }
 
     this.setState({empty: _data.length === 0})
+
     return _data
+  }
+
+  getnestdata = () => {
+    const { data, plot } = this.state
+
+    if (!data) {
+      this.setState({empty: true})
+      return []
+    }
+
+    let _data = []
+    let _cdata = fromJS(data).toJS()
+
+    if (plot.repeat === 'average') {
+      let _mdata = new Map()
+      let map = new Map()
+      let sort = 1
+      _cdata.forEach(item => {
+        if (typeof(item[plot.Yaxis]) !== 'number') {
+          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
+          if (isNaN(item[plot.Yaxis])) {
+            return
+          }
+        } else if (!item[plot.Xaxis] || !item[plot.type]) {
+          return
+        }
+
+        let sign = item[plot.type] + item[plot.Xaxis]
+
+        if (!_mdata.has(sign)) {
+          let _sort = sort
+          if (map.has(item.type)) {
+            _sort = map.get(item.type)
+          } else {
+            map.set(item.type, _sort)
+            sort++
+          }
+
+          item.$count = 1
+          item.$sort = _sort
+          _mdata.set(sign, item)
+        } else {
+          let _item = _mdata.get(sign)
+          _item.$count++
+          _item[plot.Yaxis] += item[plot.Yaxis]
+          _mdata.set(sign, _item)
+        }
+      })
+
+      _data = [..._mdata.values()]
+      _data = _data.map(item => {
+        item[plot.Yaxis] = item[plot.Yaxis] / item.$count
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
+
+        return item
+      })
+    } else if (plot.repeat === 'cumsum') {
+      let _mdata = new Map()
+      let map = new Map()
+      let sort = 1
+      _cdata.forEach(item => {
+        if (typeof(item[plot.Yaxis]) !== 'number') {
+          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
+          if (isNaN(item[plot.Yaxis])) {
+            return
+          }
+        } else if (!item[plot.Xaxis] || !item[plot.type]) {
+          return
+        }
+
+        let sign = item[plot.type] + item[plot.Xaxis]
+
+        if (!_mdata.has(sign)) {
+          let _sort = sort
+          if (map.has(item.type)) {
+            _sort = map.get(item.type)
+          } else {
+            map.set(item.type, _sort)
+            sort++
+          }
+
+          item.$sort = _sort
+          _mdata.set(sign, item)
+        } else {
+          let _item = _mdata.get(sign)
+          _item[plot.Yaxis] += item[plot.Yaxis]
+          _mdata.set(sign, _item)
+        }
+      })
+
+      _data = [..._mdata.values()]
+      _data = _data.map(item => {
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
+        return item
+      })
+    } else { // plot.repeat === 'unrepeat'
+      let _mdata = new Map()
+      let map = new Map()
+      let sort = 1
+      _cdata.forEach(item => {
+        let sign = item[plot.type] + item[plot.Xaxis]
+        if (!item[plot.Xaxis] || !item[plot.type] || _mdata.has(sign)) {
+          return
+        }
+
+        if (typeof(item[plot.Yaxis]) !== 'number') {
+          item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
+          if (isNaN(item[plot.Yaxis])) {
+            return
+          }
+        }
+
+        let _sort = sort
+        if (map.has(item.type)) {
+          _sort = map.get(item.type)
+        } else {
+          map.set(item.type, _sort)
+          sort++
+        }
+
+        item.$sort = _sort
+        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
+
+        _mdata.set(sign, item)
+      })
+
+      _data = [..._mdata.values()]
+    }
+
+    this.setState({empty: _data.length === 0})
+
+    return _data
+  }
+
+  nestrender = () => {
+    const { plot, chartId } = this.state
+
+    let X_axis = plot.Xaxis
+    let Y_axis = plot.Yaxis
+    let type = plot.type
+    let color = plot.color
+
+    let colors = new Map()
+    let colorIndex = 0
+
+    if (plot.colors && plot.colors.length > 0) {
+      plot.colors.forEach(item => {
+        if (!colors.has(item.label)) {
+          colors.set(item.label, item.color)
+        }
+      })
+    }
+
+    let _data = this.getnestdata()
+
+    const dvx = new DataView().source(_data)
+
+    dvx.transform({
+      type: 'sort-by',
+      fields: ['$sort']
+    })
+
+    let data = dvx.rows
+
+    // 閫氳繃 DataSet 璁$畻鐧惧垎姣�
+    const dv = new DataView()
+    dv.source(data).transform({
+      type: 'percent',
+      field: Y_axis,
+      dimension: type,
+      as: '$percent'
+    })
+
+    const dv1 = new DataView()
+    dv1.source(data).transform({
+      type: 'percent',
+      field: Y_axis,
+      dimension: X_axis,
+      as: '$percent',
+    })
+
+    const chart = new Chart({
+      container: chartId,
+      autoFit: true,
+      height: plot.height,
+      padding: 0,
+    })
+
+    chart.data(dv.rows)
+
+    if (plot.show !== 'value') {
+      chart.scale('percent', {
+        formatter: (val) => {
+          val = val * 100 + '%'
+          return val
+        }
+      })
+
+      Y_axis = '$percent'
+    }
+    let radius = plot.radius / 100
+    let innerRadius = plot.innerRadius / 100
+    
+    chart.coordinate('theta', {
+      innerRadius: innerRadius,
+      radius: innerRadius + (radius - innerRadius) / 2,
+    })
+    chart.tooltip({
+      showTitle: false,
+      showMarkers: false,
+    })
+    chart.legend(false)
+    let chart1 = chart
+      .interval()
+      .adjust('stack')
+      .position(Y_axis)
+      .tooltip(`${type}*${Y_axis}`, (type, percent) => {
+        if (plot.show !== 'value') {
+          percent = (percent * 100).toFixed(2) + '%'
+        }
+        return {
+          name: type,
+          value: percent,
+        }
+      })
+    if (plot.splitLine) {
+      chart1.style({
+        lineWidth: plot.splitLine,
+        stroke: plot.splitColor,
+      })
+    }
+    if (plot.colors && plot.colors.length > 0) {
+      let limit = chartColors.length
+      chart1.color(type, (_type) => {
+        if (colors.has(_type)) {
+          return colors.get(_type)
+        } else {
+          let _c = chartColors[colorIndex % limit]
+          colors.set(type, _c)
+          colorIndex++
+          return _c
+        }
+      })
+    } else {
+      chart1.color(type)
+    }
+
+    if (plot.label !== 'false') {
+      chart1.label(type, {
+        offset: -10,
+      })
+    }
+    
+    const outterView = chart.createView()
+    
+    outterView.data(dv1.rows)
+
+    if (plot.show !== 'value') {
+      outterView.scale('percent', {
+        formatter: (val) => {
+          val = val * 100 + '%'
+          return val
+        }
+      })
+    }
+    outterView.coordinate('theta', {
+      innerRadius: (innerRadius + (radius - innerRadius) / 2) / radius,
+      radius: radius
+    })
+    let chart2 = outterView
+      .interval()
+      .adjust('stack')
+      .position(Y_axis)
+      .tooltip(`${X_axis}*${Y_axis}`, (name, value) => {
+        if (plot.show !== 'value') {
+          value = (value * 100).toFixed(2) + '%'
+        }
+        return {
+          name: name,
+          value: value
+        }
+      })
+
+    if (plot.splitLine) {
+      chart2.style({
+        lineWidth: plot.splitLine,
+        stroke: plot.splitColor,
+      })
+    }
+    if (plot.colors && plot.colors.length > 0) {
+      let limit = chartColors.length
+      chart2.color(X_axis, (type) => {
+        if (colors.has(type)) {
+          return colors.get(type)
+        } else {
+          let _c = chartColors[colorIndex % limit]
+          colors.set(type, _c)
+          colorIndex++
+          return _c
+        }
+      })
+    } else {
+      chart2.color(X_axis)
+    }
+
+    if (plot.label !== 'false') {
+      if (plot.label === 'inner') {
+        chart2.label(Y_axis, {
+          offset: -30,
+          content: (data) => {
+            let _val = ''
+            if (plot.show !== 'value') {
+              _val = `${(data[Y_axis] * 100).toFixed(2)}%`
+            } else {
+              _val = `${data[Y_axis]}`
+            }
+            return _val
+          },
+          style: {
+            textAlign: 'center',
+            fontSize: 16,
+            shadowBlur: 2,
+            shadowColor: 'rgba(0, 0, 0, .45)',
+            fill: '#fff',
+          }
+        })
+      } else {
+        chart2.label(Y_axis, {
+          layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' },
+          labelHeight: 20,
+          content: (data) => {
+            let _val = ''
+            if (plot.show !== 'value') {
+              _val = `${(data[Y_axis] * 100).toFixed(2)}%`
+            } else {
+              _val = `${data[Y_axis]}`
+            }
+
+            return `${data[X_axis]}: ${_val}`
+          },
+          labelLine: {
+            style: {
+              lineWidth: 0.5,
+            },
+          },
+          style: {
+            fill: color
+          }
+        })
+      }
+    }
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
+    }
+    chart.render()
   }
 
   /**
@@ -379,12 +738,13 @@
    */
   pierender = () => {
     const { plot, chartId } = this.state
-    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
 
-    let X_axis = plot.Xaxis || 'x'
-    let Y_axis = plot.Yaxis || 'y'
+    let color = plot.color
 
-    let data = this.getdata(X_axis, Y_axis)
+    let X_axis = plot.Xaxis
+    let Y_axis = plot.Yaxis
+
+    let data = this.getdata()
 
     const ds = new DataSet()
     const dv = ds.createView().source(data)
@@ -392,7 +752,7 @@
     const chart = new Chart({
       container: chartId,
       autoFit: true,
-      height: plot.height || 400
+      height: plot.height
     })
 
     if (plot.shape !== 'nightingale' && plot.show !== 'value') {
@@ -479,14 +839,23 @@
             value: value
           }
         })
+
+      if (plot.splitLine) {
+        _chart.style({
+          lineWidth: plot.splitLine,
+          stroke: plot.splitColor,
+        })
+      }
       if (plot.colors && plot.colors.length > 0) {
         let limit = chartColors.length
         _chart.color(X_axis, (type) => {
-          if (colors.get(type)) {
+          if (colors.has(type)) {
             return colors.get(type)
           } else {
-            colors.set(type, chartColors[colorIndex % limit])
+            let _c = chartColors[colorIndex % limit]
+            colors.set(type, _c)
             colorIndex++
+            return _c
           }
         })
       } else {
@@ -515,7 +884,7 @@
           })
         } else {
           _chart.label(Y_axis, {
-            layout: { type: 'pie-spider' },
+            layout: { type: plot.label === 'outer' ? 'pie-spider' : 'fixed-overlap' },
             labelHeight: 20,
             content: (data) => {
               let _val = ''
@@ -538,10 +907,8 @@
           })
         }
       }
-      chart.interaction('element-active')
     } else {
       chart.axis(false)
-      chart.interaction('element-highlight')
       let _chart = chart
         .interval()
         .position(`${X_axis}*${Y_axis}`)
@@ -549,11 +916,13 @@
       if (plot.colors && plot.colors.length > 0) {
         let limit = chartColors.length
         _chart.color(X_axis, (type) => {
-          if (colors.get(type)) {
+          if (colors.has(type)) {
             return colors.get(type)
           } else {
-            colors.set(type, chartColors[colorIndex % limit])
+            let _c = chartColors[colorIndex % limit]
+            colors.set(type, _c)
             colorIndex++
+            return _c
           }
         })
       } else {
@@ -570,9 +939,11 @@
         }
 
         _chart.label(X_axis, _label)
-        .style({
-          lineWidth: 1,
-          stroke: '#fff',
+      }
+      if (plot.splitLine) {
+        _chart.style({
+          lineWidth: plot.splitLine,
+          stroke: plot.splitColor,
         })
       }
     }
@@ -624,7 +995,11 @@
         }
       })
     }
-
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
+    }
     chart.render()
   }
 
@@ -647,7 +1022,7 @@
         }
         <NormalHeader config={config} BID={BID} menuType={this.props.menuType} refresh={this.refreshSearch} />
         <div className="canvas-wrap">
-          <div className={'canvas' + (empty ? ' empty' : '')} id={this.state.chartId}></div>
+          <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 30}} id={this.state.chartId}></div>
         </div>
         {empty ? <Empty description={false}/> : null}
       </div>
diff --git a/src/tabviews/custom/components/chart/antv-pie/index.scss b/src/tabviews/custom/components/chart/antv-pie/index.scss
index 3839a61..3360ffe 100644
--- a/src/tabviews/custom/components/chart/antv-pie/index.scss
+++ b/src/tabviews/custom/components/chart/antv-pie/index.scss
@@ -9,6 +9,7 @@
   .canvas-wrap {
     margin: 0 0px;
     position: relative;
+    min-height: calc(100% - 45px);
     .chart-action {
       position: absolute;
       top: 2px;
@@ -45,6 +46,10 @@
     top: 0;
     right: 0px;
     bottom: 0px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    text-align: justify;
     z-index: 1;
 
     .ant-spin-blur {
diff --git a/src/tabviews/custom/components/chart/antv-scatter/asyncButtonComponent.jsx b/src/tabviews/custom/components/chart/antv-scatter/asyncButtonComponent.jsx
new file mode 100644
index 0000000..5fb9c1a
--- /dev/null
+++ b/src/tabviews/custom/components/chart/antv-scatter/asyncButtonComponent.jsx
@@ -0,0 +1,34 @@
+import React, {Component} from 'react'
+import { Button } from 'antd'
+
+/**
+ * @description 寮傛鍔犺浇妯″潡
+ * @param {*} importComponent
+ */
+export default function asyncComponent(importComponent) {
+  return class extends Component {
+    constructor(props) {
+      super(props)
+
+      this.state = {
+        component: null
+      }
+    }
+
+    async componentDidMount() {
+      const {default: component} = await importComponent()
+
+      this.setState({component})
+    }
+
+    // <Button className="loading-skeleton" disabled={true}></Button> // 楠ㄦ灦鎸夐挳
+    render() {
+      const C = this.state.component
+      const btn = this.props.btn || {}
+
+      return C ?
+        <C {...this.props} /> :
+        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/custom/components/chart/antv-scatter/index.jsx b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
new file mode 100644
index 0000000..742617f
--- /dev/null
+++ b/src/tabviews/custom/components/chart/antv-scatter/index.jsx
@@ -0,0 +1,432 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Chart } from '@antv/g2'
+import { Spin, Empty, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import asyncComponent from '@/utils/asyncComponent'
+import asyncBtnComponent from './asyncButtonComponent'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+const ExcelOutButton = asyncBtnComponent(() => import('@/tabviews/zshare/actionList/exceloutbutton'))
+const ExcelInButton = asyncBtnComponent(() => import('@/tabviews/zshare/actionList/excelInbutton'))
+
+class ScatterChart extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+  }
+
+  state = {
+    BID: '',                   // 涓昏〃ID
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    empty: true,               // 鍥捐〃鏁版嵁涓虹┖
+    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
+    chartId: Utils.getuuid(),  // 鍥捐〃Id
+    sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
+    plot: null,                // 鍥捐〃璁剧疆
+    data: null,                // 鏁版嵁
+    search: null,              // 鎼滅储鏉′欢
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config, data, initdata, BID } = this.props
+    let _config = fromJS(config).toJS()
+    let _data = null
+    let _sync = config.setting.sync === 'true'
+
+    if (config.setting.sync === 'true' && data) {
+      _data = data[config.dataName] || []
+      _sync = false
+    } else if (config.setting.sync === 'true' && initdata) {
+      _data = initdata || []
+      _sync = false
+    }
+
+    let height = config.plot.height || 400
+    if (config.plot.title || config.search.length > 0) {
+      _config.plot.height = height - 70
+    } else {
+      _config.plot.height = height - 25
+    }
+
+    _config.style.height = height
+
+    this.setState({
+      config: _config,
+      data: _data,
+      BID: BID || '',
+      empty: !_data,
+      arr_field: _config.columns.map(col => col.field).join(','),
+      plot: _config.plot,
+      sync: _sync,
+      search: Utils.initMainSearch(config.search),
+    }, () => {
+      if (config.setting.sync !== 'true' && config.setting.onload === 'true') {
+        this.loadData()
+      } else if (config.setting.sync === 'true' && _data) {
+        this.handleData()
+      }
+    })
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { sync, config } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = []
+      if (nextProps.data && nextProps.data[config.dataName]) {
+        _data = nextProps.data[config.dataName] || []
+      }
+
+      this.setState({sync: false, data: _data, empty: !_data,}, () => {
+        this.handleData()
+      })
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
+    this.handleTimer()
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    clearTimeout(this.timer)
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
+    MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
+  }
+
+  handleTimer = () => {
+    const { config } = this.state
+
+    if (!config.timer) return
+
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
+
+    let timer = _change[config.timer]
+
+    if (!timer) return
+
+    let _param = {
+      func: 's_get_timers_role',
+      LText: `select '${window.GLOB.appkey || ''}','${config.uuid}'`,
+      timer_type: config.timer,
+      component_id: config.uuid
+    }
+    
+    _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) {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return
+      } else if (result.run_type) {
+        this.setState({timer})
+        this.timer = setTimeout(() => {
+          this.timerTask()
+        }, timer)
+      }
+    })
+  }
+
+  timerTask = () => {
+    const { timer } = this.state
+    if (!timer) return
+    
+    this.loadData(true)
+    
+    this.timer = setTimeout(() => {
+      this.timerTask()
+    }, timer)
+  }
+
+  /**
+   * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂�
+   * @param {*} menuId     // 鑿滃崟Id
+   * @param {*} position   // 鍒锋柊浣嶇疆
+   * @param {*} btn        // 鎵ц鐨勬寜閽�
+   */
+  refreshByButtonResult = (menuId, position, btn) => {
+    const { config, BID } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData()                                                            // 鏁版嵁鍒锋柊
+
+    if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) {
+      MKEmitter.emit('reloadData', btn.syncComponentId)                        // 鍚岀骇鏍囩鍒锋柊
+    }
+
+    if (position === 'mainline' && config.setting.supModule) {                 // 涓昏〃琛屽埛鏂�
+      MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty'))
+    }
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData()
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.state
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID) {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  /**
+   * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
+   */
+  queryModuleParam = (menuId, btnId) => {
+    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)
+        }
+      })
+    }
+
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
+      arr_field: arr_field,
+      orderBy: config.setting.order || '',
+      search: searches,
+      menuName: config.name
+    })
+  }
+
+  /**
+   * @description 鏁版嵁鍔犺浇
+   */
+  async loadData (hastimer) {
+    const { mainSearch, menuType } = this.props
+    const { config, arr_field, BID, search } = this.state
+
+    if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: [],
+        empty: false,
+      }, () => {
+        this.handleData()
+      })
+      return
+    }
+
+    let searches = search ? fromJS(search).toJS() : []
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+      let keys = searches.map(item => item.key)
+      mainSearch.forEach(item => {
+        if (!keys.includes(item.key)) {
+          searches.push(item)
+        }
+      })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    if (!hastimer) {
+      this.setState({
+        loading: true
+      })
+    }
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      this.setState({
+        data: result.data,
+        empty: false,
+        loading: false
+      }, () => {
+        this.handleData()
+      })
+    } else {
+      this.setState({
+        loading: false,
+        timer: null
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁棰勫鐞嗭紝缁熻鏁版嵁闇�瑕侀噸缃�
+   */
+  handleData = () => {
+    let _element = document.getElementById(this.state.chartId)
+    if (_element) {
+      _element.innerHTML = ''
+    }
+    this.scatterrender()
+  }
+
+  /**
+   * @description 鏁g偣鍥炬覆鏌�
+   */
+  scatterrender = () => {
+    const { plot, data, chartId } = this.state
+    const chart = new Chart({
+      container: chartId,
+      autoFit: true,
+      height: plot.height
+    })
+
+    chart.data(data);
+    chart.scale({
+      [plot.Xaxis]: { nice: true },
+      [plot.Yaxis]: { nice: true },
+    })
+    
+    chart.axis(plot.Xaxis, { label: { style: { fill: plot.color } } })
+    chart.axis(plot.Yaxis, { label: { style: { fill: plot.color } } })
+    chart.legend({
+      position: 'bottom',
+      itemName: { style: { fill: plot.color } }
+    })
+
+    if (plot.tooltip !== 'true') {
+      chart.tooltip(false)
+    } else {
+      chart.tooltip({
+        showTitle: false,
+        showCrosshairs: true,
+        crosshairs: {
+          type: 'xy',
+        }
+      })
+    }
+
+    chart
+      .point()
+      .position(`${plot.Xaxis}*${plot.Yaxis}`)
+      .color(plot.gender)
+      .shape(plot.shape)
+      .tooltip(`${plot.gender}*${plot.Xaxis}*${plot.Yaxis}`, (gender, height, weight) => {
+        return {
+          name: gender,
+          value: height + (plot.Xunit ? `(${plot.Xunit}), ` : ', ') + weight + (plot.Yunit ? `(${plot.Yunit})` : '')
+        };
+      })
+      .style({
+        fillOpacity: 0.85
+      })
+    if (plot.interaction && plot.interaction.length) {
+      plot.interaction.forEach(t => {
+        chart.interaction(t)
+      })
+    }
+    chart.render()
+  }
+
+  refreshSearch = (list) => {
+    this.setState({search: list}, () => {
+      this.loadData()
+    })
+  }
+
+  render() {
+    const { config, loading, empty, BID } = this.state
+
+    return (
+      <div className="custom-scatter-plot-box" style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        <NormalHeader config={config} BID={BID} menuType={this.props.menuType} refresh={this.refreshSearch} />
+        <div className="canvas-wrap">
+          <div className="chart-action">
+            {config.action.map(item => {
+              if (item.OpenType === 'excelOut') {
+                return (
+                  <ExcelOutButton
+                    key={item.uuid}
+                    BID={BID}
+                    btn={item}
+                    show="icon"
+                    setting={config.setting}
+                  />
+                )
+              } else {
+                return (
+                  <ExcelInButton
+                    key={item.uuid}
+                    BID={BID}
+                    btn={item}
+                    show="icon"
+                    setting={config.setting}
+                  />
+                )
+              }
+            })}
+          </div>
+          <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 25}} id={this.state.chartId}></div>
+        </div>
+        {empty ? <Empty description={false}/> : null}
+      </div>
+    )
+  }
+}
+
+export default ScatterChart
\ No newline at end of file
diff --git a/src/tabviews/custom/components/chart/antv-scatter/index.scss b/src/tabviews/custom/components/chart/antv-scatter/index.scss
new file mode 100644
index 0000000..c9ad16c
--- /dev/null
+++ b/src/tabviews/custom/components/chart/antv-scatter/index.scss
@@ -0,0 +1,70 @@
+.custom-scatter-plot-box {
+  position: relative;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+
+  .canvas-wrap {
+    margin: 0 0px;
+    position: relative;
+    min-height: calc(100% - 45px);
+    .chart-action {
+      position: absolute;
+      top: 0px;
+      right: 5px;
+      z-index: 1;
+      .ant-btn {
+        float: right;
+      }
+    }
+  }
+
+  .canvas {
+    margin: 0;
+    padding: 15px 10px 10px;
+    letter-spacing: 0px;
+  }
+  .canvas.empty {
+    div {
+      opacity: 0;
+    }
+  }
+  .ant-empty {
+    position: absolute;
+    top: calc(50% - 34px);
+    left: calc(50% - 92px);
+
+    .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;
+    }
+  }
+  
+  .g2-tooltip-list{
+    display: none;
+  }
+  .g2-tooltip-title + .g2-tooltip-list{
+    display: block;
+  }
+}
diff --git a/src/tabviews/custom/components/code/sand-box/index.jsx b/src/tabviews/custom/components/code/sand-box/index.jsx
index 204c9f7..1fd9fa9 100644
--- a/src/tabviews/custom/components/code/sand-box/index.jsx
+++ b/src/tabviews/custom/components/code/sand-box/index.jsx
@@ -106,12 +106,10 @@
       this.setState({sync: false, data: _data}, () => {
         this.renderView()
       })
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -141,9 +139,11 @@
       return
     }
 
-    let searches = []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
-      searches = mainSearch
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
diff --git a/src/tabviews/custom/components/editor/braft-editor/index.jsx b/src/tabviews/custom/components/editor/braft-editor/index.jsx
index 5691f35..8b7c537 100644
--- a/src/tabviews/custom/components/editor/braft-editor/index.jsx
+++ b/src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -100,12 +100,10 @@
       }
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
   }
 
@@ -135,9 +133,11 @@
       return
     }
 
-    let searches = []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
-      searches = mainSearch
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
diff --git a/src/tabviews/custom/components/form/normal-form/index.jsx b/src/tabviews/custom/components/form/normal-form/index.jsx
index 8d3fc08..f8bb190 100644
--- a/src/tabviews/custom/components/form/normal-form/index.jsx
+++ b/src/tabviews/custom/components/form/normal-form/index.jsx
@@ -3,7 +3,6 @@
 import { is, fromJS } from 'immutable'
 import { connect } from 'react-redux'
 import { Spin, notification, Button } from 'antd'
-// import moment from 'moment'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -33,7 +32,6 @@
     BID: '',                   // 涓婄骇ID
     config: null,              // 鍥捐〃閰嶇疆淇℃伅
     loading: false,            // 鏁版嵁鍔犺浇鐘舵��
-    activeKey: '',             // 閫変腑鏁版嵁
     sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
     data: null,                  // 鏁版嵁
     group: null,
@@ -41,7 +39,8 @@
   }
 
   UNSAFE_componentWillMount () {
-    const { data, BID, config } = this.props
+    const { data, BID } = this.props
+    let config = fromJS(this.props.config).toJS()
 
     let _data = null
     let _sync = false
@@ -60,15 +59,31 @@
       _data = {}
     }
 
+    if (!config.wrap.groupLabel) {
+      if (config.subcards.length > 1) {
+        config.wrap.groupLabel = 'show'
+      } else {
+        config.wrap.groupLabel = 'hidden'
+      }
+    }
+
     let roleId = sessionStorage.getItem('role_id') || ''
 
     config.subcards = config.subcards.map(group => {
       group.subButton.uuid = group.uuid
       group.subButton.$menuId = group.uuid
       group.subButton.Ot = 'requiredSgl'
-      group.subButton.btnstyle = group.subButton.style
+      group.subButton.$forbid = true
       group.subButton.OpenType = 'formSubmit'
       group.subButton.execError = 'never'
+
+      if (group.subButton.enable === 'false') {
+        group.subButton.style.display = 'none'
+      }
+
+      if (group.prevButton.enable === 'false' && group.subButton.enable === 'false' && group.nextButton.enable === 'false') {
+        group.$button = 'no-button'
+      }
 
       group.fields = group.fields.map(cell => {
         // 鏁版嵁婧恠ql璇彞锛岄澶勭悊锛屾潈闄愰粦鍚嶅崟瀛楁璁剧疆涓洪殣钘忚〃鍗�
@@ -117,6 +132,7 @@
   }
 
   componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
     MKEmitter.addListener('mkFormSubmit', this.mkFormSubmit)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
@@ -130,6 +146,7 @@
     this.setState = () => {
       return
     }
+    MKEmitter.removeListener('reloadData', this.reloadData)
     MKEmitter.removeListener('mkFormSubmit', this.mkFormSubmit)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
@@ -157,13 +174,19 @@
       }
 
       this.setState({sync: false, data: _data, group: _group, step: _group.sort - 1,})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.loadData()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
     }
+  }
+
+  reloadData = (menuId, id) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData(null, 'refresh')
   }
 
   /**
@@ -180,6 +203,26 @@
     if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) {
       MKEmitter.emit('reloadData', btn.syncComponentId)                        // 鍚岀骇鏍囩鍒锋柊
     }
+
+    if (config.wrap.datatype !== 'static' && config.setting) {
+      this.loadData(btn)
+    } else {
+      this.execSuccess(btn)
+    }
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.state
+    if (config.wrap.datatype === 'static' || !config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID) {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  execSuccess = (btn) => {
+    const { config, group } = this.state
 
     if (config.subcards.length > group.sort) {
       let _group = config.subcards.filter(item => item.sort === (group.sort + 1))[0]
@@ -218,36 +261,24 @@
     }
   }
 
-  resetParentParam = (MenuID, id) => {
-    const { config } = this.state
-    if (config.wrap.datatype === 'static' || !config.setting.supModule || config.setting.supModule !== MenuID) return
-    if (id !== this.state.BID) {
-      this.setState({ BID: id }, () => {
-        this.loadData()
-      })
-    }
-  }
-
-  async loadData () {
+  async loadData (btn, type) {
     const { mainSearch, menuType } = this.props
     const { config, arr_field, BID, group } = this.state
 
     if (config.wrap.datatype === 'static' || (config.setting.supModule && !BID)) {
       this.setState({
-        data: {},
-        loading: false
+        data: {}
       })
+      btn && this.execSuccess(btn)
       return
     }
 
-    let searches = []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
-      let keys = searches.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searches.push(item)
-        }
-      })
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      btn && this.execSuccess(btn)
+      return
     }
 
     this.setState({
@@ -260,20 +291,34 @@
     let result = await Api.genericInterface(param)
     if (result.status) {
       let _data = result.data && result.data[0] ? result.data[0] : {}
-      let _group = group
-      if (config.wrap.statusControl && _data[config.wrap.statusControl]) {
-        let _status = _data[config.wrap.statusControl]
-        let _groups = config.subcards.filter(item => item.setting.status === _status)[0]
-        _group = _groups || _group
-      }
 
-      this.setState({
-        group: _group,
-        step: _group.sort - 1,
-        activeKey: '',
-        data: _data || {},
-        loading: false
-      })
+      if (btn) {
+        this.setState({
+          data: _data || {},
+          loading: false
+        })
+        this.execSuccess(btn)
+      } else {
+        let _group = group
+
+        if (type === 'refresh') {
+          _group = config.subcards[0]
+        }
+
+        if (config.wrap.statusControl && _data[config.wrap.statusControl]) {
+          let _status = _data[config.wrap.statusControl]
+          let _groups = config.subcards.filter(item => item.setting.status === _status)[0]
+          _group = _groups || _group
+        }
+        this.setState({
+          group: null,
+          step: _group.sort - 1,
+          data: _data || {},
+          loading: false
+        }, () => {
+          this.setState({group: _group})
+        })
+      }
     } else {
       this.setState({
         loading: false,
@@ -283,6 +328,7 @@
         message: result.message,
         duration: 10
       })
+      btn && this.execSuccess(btn)
     }
   }
 
@@ -327,7 +373,7 @@
             <Spin />
           </div> : null
         }
-        {config.subcards.length > 1 ? <div className="mk-normal-form-title">
+        {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>
@@ -345,8 +391,8 @@
           inputSubmit={this.handleOk}
           wrappedComponentRef={(inst) => this.formRef = inst}
         /> : null}
-        {group && data ? <div className="mk-form-action">
-          {group.sort !== 1 ? <Button type="link" className="prev" onClick={this.prevStep} style={group.prevButton.style}>{group.prevButton.label}</Button> : null}
+        {group && data ? <div className={'mk-form-action ' + (group.$button || '')}>
+          {group.sort !== 1 && group.prevButton.enable !== 'false' ? <Button type="link" className="prev" onClick={this.prevStep} style={group.prevButton.style}>{group.prevButton.label}</Button> : null}
           <NormalButton
             BID={BID}
             position="form"
diff --git a/src/tabviews/custom/components/form/normal-form/index.scss b/src/tabviews/custom/components/form/normal-form/index.scss
index 285b505..7547391 100644
--- a/src/tabviews/custom/components/form/normal-form/index.scss
+++ b/src/tabviews/custom/components/form/normal-form/index.scss
@@ -78,6 +78,10 @@
       right: 5px;
     }
   }
+  .mk-form-action.no-button {
+    padding: 0;
+    height: 0;
+  }
   
   .loading-mask {
     position: absolute;
diff --git a/src/tabviews/custom/components/group/normal-group/index.jsx b/src/tabviews/custom/components/group/normal-group/index.jsx
index d814a27..0ffbce3 100644
--- a/src/tabviews/custom/components/group/normal-group/index.jsx
+++ b/src/tabviews/custom/components/group/normal-group/index.jsx
@@ -2,24 +2,32 @@
 import PropTypes from 'prop-types'
 import { connect } from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { Col, Empty, notification, Button } from 'antd'
-import moment from 'moment'
-import md5 from 'md5'
+import { Col, Empty, notification, Button, Row } from 'antd'
 
 import Api from '@/api'
-import options from '@/store/options.js'
 import asyncComponent from '@/utils/asyncComponent'
+import {
+  getStructuredParams,
+  getStructDefaultParam
+} from '@/utils/utils-datamanage.js'
 import Utils from '@/utils/utils.js'
 import './index.scss'
 
 // 閫氱敤缁勪欢
 const AntvBarAndLine = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-bar-line'))
 const AntvPie = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-dashboard'))
+const AntvScatter = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-scatter'))
 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 PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 const SandBox = asyncComponent(() => import('@/tabviews/custom/components/code/sand-box'))
+const NormalForm = asyncComponent(() => import('@/tabviews/custom/components/form/normal-form'))
+const NormalTree = asyncComponent(() => import('@/tabviews/custom/components/tree/antd-tree'))
+const CarouselDataCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/data-card'))
+const CarouselPropCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/prop-card'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -41,7 +49,6 @@
 
     // 鑾峰彇涓绘悳绱㈡潯浠�
     let _mainSearch = mainSearch ? fromJS(mainSearch).toJS() : []
-
     let params = []
     config.components.forEach(item => {
       if (item.type === 'tabs') return
@@ -50,8 +57,25 @@
       if (!item.format) return
 
       if (item.dataName && (!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true' && item.setting.sync === 'true') {
-        let param = this.getDefaultParam(item, _mainSearch)
-        params.push(param)
+        let searchlist = []
+        if (item.search && item.search.length > 0) {
+          searchlist = Utils.initMainSearch(item.search)
+        }
+        if (item.setting.useMSearch) {
+          let keys = searchlist.map(item => item.key)
+          _mainSearch.forEach(item => {
+            if (!keys.includes(item.key)) {
+              searchlist.push(item)
+            }
+          })
+        }
+
+        if (searchlist.filter(cell => cell.required && cell.value === '').length > 0) {
+          item.setting.sync = 'false'
+          item.setting.onload = 'false'
+        } else {
+          params.push(getStructDefaultParam(item, searchlist))
+        }
       } else {
         item.setting.sync = 'false'
       }
@@ -71,137 +95,10 @@
   }
 
   /**
-   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
-   */
-  getDefaultParam = (component, mainSearch) => {
-    const { columns, search, setting, dataName, format } = component
-    
-    let searchlist = []
-    if (search && search.length > 0) {
-      searchlist = Utils.initMainSearch(search)
-    }
-
-    if (setting.useMSearch === 'true') {
-      let keys = searchlist.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searchlist.push(item)
-        }
-      })
-    }
-
-    let arr_field = columns.map(col => col.field)
-    let _dataresource = setting.dataresource
-    let _customScript = setting.customScript
-
-    if (setting.queryType === 'statistics' || _customScript) {
-      let allSearch = Utils.getAllSearchOptions(searchlist)
-      let regoptions = allSearch.map(item => {
-        return {
-          reg: new RegExp('@' + item.key + '@', 'ig'),
-          value: `'${item.value}'`
-        }
-      })
-
-      regoptions.forEach(item => {
-        if (_dataresource && setting.queryType === 'statistics') {
-          _dataresource = _dataresource.replace(item.reg, item.value)
-        }
-        if (_customScript) {
-          _customScript = _customScript.replace(item.reg, item.value)
-        }
-      })
-    }
-
-    let _search = ''
-    if (setting.queryType !== 'statistics' && _dataresource) {
-      _search = Utils.joinMainSearchkey(searchlist)
-      _search = _search ? 'where ' + _search : ''
-    }
-
-    if (setting.order && _dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from (select ${arr_field.join(',')} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
-    } else if (_dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from ${_dataresource} ${_search} `
-    }
-
-    // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
-    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
-      _customScript &&  console.info(`${_dataresource ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
-      _dataresource &&  console.info(_dataresource)
-    }
-
-    return {
-      name: dataName,
-      columns: columns,
-      par_tablename: '',
-      type: format === 'array' ? format : '',
-      primaryKey: setting.primaryKey || '',
-      foreign_key: '',
-      sql: _dataresource,
-      script: _customScript
-    }
-  }
-
-  /**
    * @description 涓昏〃鏁版嵁鍔犺浇
    */ 
   loadmaindata = (params) => {
-    const { config } = this.props
-    let LText_field = []
-    let diffUser = false
-    let userName = sessionStorage.getItem('User_Name') || ''
-    let fullName = sessionStorage.getItem('Full_Name') || ''
-    let city = sessionStorage.getItem('city') || ''
-
-    if (sessionStorage.getItem('isEditState') === 'true') {
-      userName = sessionStorage.getItem('CloudUserName') || ''
-      fullName = sessionStorage.getItem('CloudFullName') || ''
-    }
-    
-    let _LText = params.map((item, index) => {
-      let _script = item.script
-
-      if (index === 0) {
-        _script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50)
-          select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @login_city='${city}'
-          ${_script}
-        `
-      }
-      if (!diffUser && (/@userid@/ig.test(item.sql) || /@userid@/ig.test(_script))) {
-        diffUser = true
-      }
-
-      item.columns.forEach(cell => {
-        LText_field.push(`Select '${item.name}' as tablename,'${cell.field}' as fieldname,'${cell.datatype}' as field_type`)
-      })
-      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(item.sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
-    })
-
-    let param = {
-      func: 'sPC_Get_structured_data',
-      LText: _LText.join(' union all '),
-      LText_field: LText_field.join(' union all ')
-    }
-
-    let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
-
-    param.LText1 = LText1
-    param.LText = LText
-    param.LText2 = LText2
-    param.LText_field = Utils.formatOptions(param.LText_field)
-
-    if (config.cacheUseful === 'true') {
-      param.time_type = config.timeUnit
-      param.time_limit = config.cacheTime
-      if (diffUser) {
-        param.userid = sessionStorage.getItem('UserID')
-      }
-      param.data_md5 = md5(JSON.stringify(param))
-    }
-
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+    let param = getStructuredParams(params, this.props.config)
 
     Api.getLocalConfig(param).then(result => {
       if (result.status) {
@@ -252,6 +149,36 @@
             <AntvPie data={data} config={item} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'dashboard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvDashboard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'form') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalForm config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'scatter') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvScatter config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'carousel' && item.subtype === 'datacard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <CarouselDataCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'carousel' && item.subtype === 'propcard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <CarouselPropCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'card' && item.subtype === 'datacard') {
         return (
           <Col span={item.width} key={item.uuid}>
@@ -268,6 +195,18 @@
         return (
           <Col span={item.width} key={item.uuid}>
             <TableCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'table' && item.subtype === 'normaltable') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalTable config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'tree') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalTree config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
       } else if (item.type === 'editor') {
@@ -366,7 +305,7 @@
     return (
       <div className="normal-group-wrap" id={config.uuid} style={config.style}>
         {config.setting && config.setting.print === 'true' ? <Button className="print-button" icon="printer" loading={printing} onClick={this.print}></Button> : null}
-        {this.getComponents()}
+        <Row>{this.getComponents()}</Row>
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/share/normalTable/index.jsx b/src/tabviews/custom/components/share/normalTable/index.jsx
index f471844..2d53f40 100644
--- a/src/tabviews/custom/components/share/normalTable/index.jsx
+++ b/src/tabviews/custom/components/share/normalTable/index.jsx
@@ -15,7 +15,11 @@
 
 const { Paragraph } = Typography
 const CardCellComponent = asyncComponent(() => import('@/tabviews/custom/components/card/cardcellList'))
-
+const PicRadio = {
+  '4:3': '75%', '3:2': '66.67%', '16:9': '56.25%', '2:1': '50%', '3:1': '33.33%', '4:1': '25%',
+  '5:1': '20%', '6:1': '16.67%', '7:1': '14.29%', '8:1': '12.5%', '9:1': '11.11%',
+  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
+}
 class BodyRow extends React.Component {
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.props.data), fromJS(nextProps.data)) || !is(fromJS(this.props.className), fromJS(nextProps.className))
@@ -187,7 +191,7 @@
           content = `${content.substr(0, 4)}-${content.substr(5, 2)}-${content.substr(8, 2)} ${content.substr(11, 2)}:${content.substr(14, 2)}:${content.substr(17, 2)}`
         }
   
-        content = col.prefix + content + col.postfix
+        content = (col.prefix || '') + content + (col.postfix || '')
       }
 
       if (col.marks) {
@@ -272,12 +276,8 @@
       let cols = 24 / (col.picSort || 1)
       let paddingTop = '100%'
 
-      if (col.lenWidRadio === '16:9') {
-        paddingTop = '56.25%'
-      } else if (col.lenWidRadio === '3:2') {
-        paddingTop = '66.67%'
-      } else if (col.lenWidRadio === '4:3') {
-        paddingTop = '75%'
+      if (PicRadio[col.lenWidRadio]) {
+        paddingTop = PicRadio[col.lenWidRadio]
       }
 
       resProps.children = (
@@ -350,6 +350,10 @@
       )
     } else if (col.type === 'custom') {
       style.padding = '0px'
+      if (col.style) {
+        style = {...style, ...col.style}
+      }
+
       resProps.children = (
         <CardCellComponent data={record} cards={config} elements={col.elements}/>
       )
@@ -423,7 +427,10 @@
           if (item.rowspan === 'true') {
             rowspans.push(item.field)
           }
-          if (_format && !Math.floor(Math.random() * radio)) {
+          if (item.type === 'index') {
+            item.field = '$Index'
+            item.type = 'text'
+          } else if (_format && !Math.floor(Math.random() * radio)) {
             item.blur = true
           }
   
@@ -803,12 +810,13 @@
     }
 
     return (
-      <div className={'normal-custom-table ' + setting.tableHeader} id={tableId}>
+      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.mode || ''}`} id={tableId}>
         {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
-          <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={pickup} onChange={this.pickupChange} /> : null
+          <Switch title="鏀惰捣" className="main-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} /> : null
         }
         <Table
           components={components}
+          style={setting.style}
           size={setting.size || 'middle'}
           bordered={setting.bordered !== 'false'}
           rowSelection={rowSelection}
diff --git a/src/tabviews/custom/components/share/normalTable/index.scss b/src/tabviews/custom/components/share/normalTable/index.scss
index 19301ac..489c533 100644
--- a/src/tabviews/custom/components/share/normalTable/index.scss
+++ b/src/tabviews/custom/components/share/normalTable/index.scss
@@ -8,11 +8,15 @@
   }
   .normal-table-footer.pagination {
     position: absolute;
-    bottom: 40px;
+    bottom: 10px;
   }
   >.ant-table-wrapper {
     position: relative;
     z-index: 1;
+  }
+  .ant-table {
+    color: inherit;
+    font-size: inherit;
   }
 
   table {
@@ -163,6 +167,34 @@
     display: none;
   }
 }
+.normal-custom-table.ghost {
+  .main-pickup {
+    display: none;
+  }
+  .ant-table-thead > tr {
+    > th {
+      color: inherit;
+      background: transparent;
+      .ant-table-column-sorter .ant-table-column-sorter-inner {
+        color: inherit;
+      }
+    }
+    > th:hover {
+      background: transparent;
+    }
+  }
+  .ant-table-body {
+    overflow-x: auto;
+    tr {
+      td {
+        background: transparent!important;
+      }
+    }
+    tr:hover td {
+      background: transparent!important;
+    }
+  }
+}
 .image-scale-modal {
   width: 70vw;
   min-height: 80vh;
diff --git a/src/tabviews/custom/components/share/normalheader/index.jsx b/src/tabviews/custom/components/share/normalheader/index.jsx
index 9643142..570a190 100644
--- a/src/tabviews/custom/components/share/normalheader/index.jsx
+++ b/src/tabviews/custom/components/share/normalheader/index.jsx
@@ -46,7 +46,7 @@
     if (!title && !show) return null
 
     return (
-      <div className="normal-header" style={config.headerStyle}>
+      <div className={'normal-header' + (show ? ' header-search' : '')} style={config.headerStyle}>
         <span className="title">{title}</span>
         {show ? <SearchComponent config={config} BID={BID} menuType={menuType} refreshdata={this.props.refresh}/> : null}
       </div>
diff --git a/src/tabviews/custom/components/share/normalheader/index.scss b/src/tabviews/custom/components/share/normalheader/index.scss
index c58253d..3939c9a 100644
--- a/src/tabviews/custom/components/share/normalheader/index.scss
+++ b/src/tabviews/custom/components/share/normalheader/index.scss
@@ -5,13 +5,14 @@
   border-bottom: 1px solid #e8e8e8;
   overflow: hidden;
   letter-spacing: 0px;
+  line-height: 45px;
 
   .title {
     text-decoration: inherit;
     font-weight: inherit;
     font-style: inherit;
     float: left;
-    line-height: 45px;
+    line-height: inherit;
     margin-left: 10px;
     position: relative;
     z-index: 1;
@@ -22,6 +23,7 @@
     font-weight: normal;
     font-style: normal;
     letter-spacing: 0px;
+    flex: 1;
     >.ant-row {
       >.ant-col {
         height: 45px;
@@ -36,6 +38,9 @@
     }
   }
 }
+.header-search.normal-header {
+  display: flex;
+}
 .normal-header.hidden {
   display: none;
 }
\ No newline at end of file
diff --git a/src/tabviews/custom/components/share/tabtransfer/index.jsx b/src/tabviews/custom/components/share/tabtransfer/index.jsx
index 03cbe65..62512b7 100644
--- a/src/tabviews/custom/components/share/tabtransfer/index.jsx
+++ b/src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -3,12 +3,13 @@
 import { connect } from 'react-redux'
 import { is, fromJS } from 'immutable'
 import { Row, Col, Empty, notification } from 'antd'
-import moment from 'moment'
-import md5 from 'md5'
 
 import Api from '@/api'
-import options from '@/store/options.js'
 import asyncComponent from '@/utils/asyncComponent'
+import {
+  getStructuredParams,
+  getStructDefaultParam
+} from '@/utils/utils-datamanage.js'
 import Utils from '@/utils/utils.js'
 import './index.scss'
 
@@ -16,13 +17,20 @@
 const AntvBarAndLine = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-bar-line'))
 const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch'))
 const AntvPie = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-pie'))
+const AntvDashboard = asyncComponent(() => import('@/tabviews/custom/components/chart/antv-dashboard'))
 const AntvTabs = asyncComponent(() => import('@/tabviews/custom/components/tabs/antv-tabs'))
 const DataCard = asyncComponent(() => import('@/tabviews/custom/components/card/data-card'))
+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 PropCard = asyncComponent(() => import('@/tabviews/custom/components/card/prop-card'))
 const NormalGroup = asyncComponent(() => import('@/tabviews/custom/components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('@/tabviews/custom/components/editor/braft-editor'))
 const SandBox = asyncComponent(() => import('@/tabviews/custom/components/code/sand-box'))
+const NormalForm = asyncComponent(() => import('@/tabviews/custom/components/form/normal-form'))
+const NormalTree = asyncComponent(() => import('@/tabviews/custom/components/tree/antd-tree'))
+const CarouselDataCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/data-card'))
+const CarouselPropCard = asyncComponent(() => import('@/tabviews/custom/components/carousel/prop-card'))
 
 class TabTransfer extends Component {
   static propTpyes = {
@@ -63,8 +71,25 @@
       if (!item.format) return
 
       if (item.dataName && (!item.pageable || (item.pageable && !item.setting.laypage)) && item.setting.onload === 'true' && item.setting.sync === 'true') {
-        let param = this.getDefaultParam(item, _mainSearch)
-        params.push(param)
+        let searchlist = []
+        if (item.search && item.search.length > 0) {
+          searchlist = Utils.initMainSearch(item.search)
+        }
+        if (item.setting.useMSearch) {
+          let keys = searchlist.map(item => item.key)
+          _mainSearch.forEach(item => {
+            if (!keys.includes(item.key)) {
+              searchlist.push(item)
+            }
+          })
+        }
+
+        if (searchlist.filter(cell => cell.required && cell.value === '').length > 0) {
+          item.setting.sync = 'false'
+          item.setting.onload = 'false'
+        } else {
+          params.push(getStructDefaultParam(item, searchlist))
+        }
       } else {
         item.setting.sync = 'false'
       }
@@ -86,137 +111,10 @@
   }
 
   /**
-   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
-   */
-  getDefaultParam = (component, mainSearch) => {
-    const { columns, search, setting, dataName, format } = component
-    
-    let searchlist = []
-    if (search && search.length > 0) {
-      searchlist = Utils.initMainSearch(search)
-    }
-
-    if (setting.useMSearch === 'true') {
-      let keys = searchlist.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searchlist.push(item)
-        }
-      })
-    }
-
-    let arr_field = columns.map(col => col.field)
-    let _dataresource = setting.dataresource
-    let _customScript = setting.customScript
-
-    if (setting.queryType === 'statistics' || _customScript) {
-      let allSearch = Utils.getAllSearchOptions(searchlist)
-      let regoptions = allSearch.map(item => {
-        return {
-          reg: new RegExp('@' + item.key + '@', 'ig'),
-          value: `'${item.value}'`
-        }
-      })
-
-      regoptions.forEach(item => {
-        if (_dataresource && setting.queryType === 'statistics') {
-          _dataresource = _dataresource.replace(item.reg, item.value)
-        }
-        if (_customScript) {
-          _customScript = _customScript.replace(item.reg, item.value)
-        }
-      })
-    }
-
-    let _search = ''
-    if (setting.queryType !== 'statistics' && _dataresource) {
-      _search = Utils.joinMainSearchkey(searchlist)
-      _search = _search ? 'where ' + _search : ''
-    }
-
-    if (setting.order && _dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from (select ${arr_field.join(',')} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
-    } else if (_dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from ${_dataresource} ${_search} `
-    }
-
-    // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
-    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
-      _customScript &&  console.info(`${_dataresource ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
-      _dataresource &&  console.info(_dataresource)
-    }
-
-    return {
-      name: dataName,
-      columns: columns,
-      par_tablename: '',
-      type: format === 'array' ? format : '',
-      primaryKey: setting.primaryKey || '',
-      foreign_key: '',
-      sql: _dataresource,
-      script: _customScript
-    }
-  }
-
-  /**
    * @description 涓昏〃鏁版嵁鍔犺浇
    */ 
   loadmaindata = (params) => {
-    const { config } = this.props
-    let LText_field = []
-    let diffUser = false
-    let userName = sessionStorage.getItem('User_Name') || ''
-    let fullName = sessionStorage.getItem('Full_Name') || ''
-    let city = sessionStorage.getItem('city') || ''
-
-    if (sessionStorage.getItem('isEditState') === 'true') {
-      userName = sessionStorage.getItem('CloudUserName') || ''
-      fullName = sessionStorage.getItem('CloudFullName') || ''
-    }
-    
-    let _LText = params.map((item, index) => {
-      let _script = item.script
-
-      if (index === 0) {
-        _script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50)
-          select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @login_city='${city}'
-          ${_script}
-        `
-      }
-      if (!diffUser && (/@userid@/ig.test(item.sql) || /@userid@/ig.test(_script))) {
-        diffUser = true
-      }
-
-      item.columns.forEach(cell => {
-        LText_field.push(`Select '${item.name}' as tablename,'${cell.field}' as fieldname,'${cell.datatype}' as field_type`)
-      })
-      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(item.sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
-    })
-
-    let param = {
-      func: 'sPC_Get_structured_data',
-      LText: _LText.join(' union all '),
-      LText_field: LText_field.join(' union all ')
-    }
-
-    let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
-
-    param.LText1 = LText1
-    param.LText = LText
-    param.LText2 = LText2
-    param.LText_field = Utils.formatOptions(param.LText_field)
-
-    if (config.cacheUseful === 'true') {
-      param.time_type = config.timeUnit
-      param.time_limit = config.cacheTime
-      if (diffUser) {
-        param.userid = sessionStorage.getItem('UserID')
-      }
-      param.data_md5 = md5(JSON.stringify(param))
-    }
-
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+    let param = getStructuredParams(params, this.props.config)
 
     Api.getLocalConfig(param).then(result => {
       if (result.status) {
@@ -271,10 +169,22 @@
             <AntvPie data={data} config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'dashboard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvDashboard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'scatter') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvScatter config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'search') {
         return (
           <Col span={item.width} key={item.uuid}>
-            <MainSearch config={item} mainSearch={mainSearch} menuType={menuType} refreshdata={this.resetSearch} />
+            <MainSearch config={item} menuType={menuType} refreshdata={this.resetSearch} />
           </Col>
         )
       } else if (item.type === 'tabs') {
@@ -295,18 +205,48 @@
             <PropCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'carousel' && item.subtype === 'datacard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <CarouselDataCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'carousel' && item.subtype === 'propcard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <CarouselPropCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'table' && item.subtype === 'tablecard') {
         return (
           <Col span={item.width} key={item.uuid}>
             <TableCard config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'table' && item.subtype === 'normaltable') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalTable config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'group' && item.subtype === 'normalgroup') {
         return (
           <Col span={item.width} key={item.uuid}>
             <NormalGroup config={item} bids={bids} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'form') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalForm config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'tree') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalTree config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'editor') {
         return (
           <Col span={item.width} key={item.uuid}>
diff --git a/src/tabviews/custom/components/table/normal-table/index.jsx b/src/tabviews/custom/components/table/normal-table/index.jsx
index 86035b3..2c432a8 100644
--- a/src/tabviews/custom/components/table/normal-table/index.jsx
+++ b/src/tabviews/custom/components/table/normal-table/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { notification } from 'antd'
+import { notification, Collapse } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -18,6 +18,8 @@
 const MainAction = asyncComponent(() => import('@/tabviews/zshare/actionList'))
 const MainTable = asyncComponent(() => import('@/tabviews/custom/components/share/normalTable'))
 const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader'))
+
+const { Panel } = Collapse
 
 class NormalTable extends Component {
   static propTpyes = {
@@ -46,7 +48,6 @@
     pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     orderBy: '',          // 鎺掑簭
     search: '',           // 鎼滅储鏉′欢鏁扮粍锛屼娇鐢ㄦ椂闇�鍒嗗満鏅鐞�
-    statFields: [],       // 鍚堣瀛楁
     statFValue: []        // 鍚堣鍊�
   }
 
@@ -74,6 +75,7 @@
         item.key = index
         item.$$uuid = item[_config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
     }
@@ -95,13 +97,25 @@
       }
     })
 
+    let setting = {..._config.setting, ..._config.wrap, style: {}}
+    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 || ' '
+    }
+
     this.setState({
       BID: BID || '',
       title: _config.wrap.title,
       sync: _sync,
       data: _data,
       config: _config,
-      setting: {..._config.setting, ..._config.wrap},
+      setting: setting,
       searchlist: _config.search,
       actions: _config.action,
       columns: _config.cols,
@@ -110,6 +124,8 @@
     }, () => {
       if (_config.setting.sync !== 'true' && _config.setting.onload === 'true') {
         this.loadmaindata()
+        this.getStatFieldsValue()
+      } else if (_config.setting.onload === 'true') {
         this.getStatFieldsValue()
       }
     })
@@ -123,7 +139,6 @@
   async loadmaindata (reset, repage) {
     const { mainSearch } = this.props
     const { setting, config, arr_field, search, orderBy, BID, pageIndex, pageSize } = this.state
-    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
 
     if (setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
@@ -135,26 +150,20 @@
       reset && MKEmitter.emit('resetTable', config.uuid, repage) // 鍒楄〃閲嶇疆
       return
     }
-    if (requireFields.length > 0) {
-      let labels = requireFields.map(item => item.label)
-      labels = Array.from(new Set(labels))
-
-      notification.warning({
-        top: 92,
-        message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
-        duration: 3
-      })
-      return
-    }
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    if (config.setting.useMSearch && mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
       let keys = searches.map(item => item.key.toLowerCase())
       mainSearch.forEach(item => {
         if (!keys.includes(item.key.toLowerCase())) {
           searches.push(item)
         }
       })
+    }
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
     }
 
     this.setState({
@@ -173,11 +182,17 @@
       MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 骞挎挱鏁版嵁鍒囨崲
       reset && MKEmitter.emit('resetTable', config.uuid, repage) // 鍒楄〃閲嶇疆
 
+      let start = 1
+      if (setting.laypage) {
+        start = pageSize * (pageIndex - 1) + 1
+      }
+
       this.setState({
         data: result.data.map((item, index) => {
           item.key = index
           item.$$uuid = item[setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = start + index + ''
           return item
         }),
         selectedData: [],
@@ -204,7 +219,7 @@
     const { setting, config, arr_field, search, orderBy, BID, pageIndex, pageSize } = this.state
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -236,6 +251,7 @@
           data = data.map(item => {
             if (item.$$uuid === _data.$$uuid) {
               _data.key = item.key
+              _data.$Index = item.$Index
               return _data
             } else {
               return item
@@ -274,7 +290,7 @@
    */
   getStatFieldsValue = () => {
     const { mainSearch } = this.props
-    const { setting, config, search, BID, orderBy, statFields } = this.state
+    const { setting, config, search, BID, orderBy } = this.state
 
     if (setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
       this.setState({
@@ -283,15 +299,10 @@
       return
     }
 
-    if (statFields.length === 0 || setting.interType !== 'system' || !setting.dataresource) return
-
-    let requireFields = search.filter(item => item.required && (!item.value || item.value.length === 0))
-    if (requireFields.length > 0) {
-      return
-    }
+    if (config.statFields.length === 0 || setting.interType !== 'system' || !setting.dataresource) return
 
     let searches = fromJS(search).toJS()
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -299,9 +310,13 @@
         }
       })
     }
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
 
     let _orderBy = orderBy || setting.order
-    let param = UtilsDM.getStatQueryDataParams(setting, statFields, searches, _orderBy, BID, this.props.menuType)
+    let param = UtilsDM.getStatQueryDataParams(setting, config.statFields, searches, _orderBy, BID, this.props.menuType)
 
     if (param.func === 'sPC_Get_TableData') {
       param.menuname = config.name || ''
@@ -313,7 +328,7 @@
         let values = []
 
         if (_data) {
-          statFields.forEach(item => {
+          config.statFields.forEach(item => {
             if (_data[item.field] || _data[item.field] === 0) {
               let val = +_data[item.field]
               if (isNaN(val)) {
@@ -408,14 +423,14 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { mainSearch } = this.props
     const { arr_field, config, orderBy, search, setting} = this.state
 
     if (config.uuid !== menuId) return
 
     let searches = search ? fromJS(search).toJS() : []
-    if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢
+    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())) {
@@ -424,7 +439,7 @@
       })
     }
 
-    MKEmitter.emit('execExcelout', config.uuid, btnId, {
+    MKEmitter.emit('returnModuleParam', config.uuid, btnId, {
       arr_field: arr_field,
       orderBy: orderBy || setting.order,
       search: searches,
@@ -486,6 +501,14 @@
     }
   }
 
+  getSyncData = (syncModule, btnId) => {
+    const { config, selectedData } = this.state
+
+    if (config.uuid !== syncModule) return
+
+    MKEmitter.emit('triggerBtnId', btnId, (selectedData || []))
+  }
+
   UNSAFE_componentWillReceiveProps(nextProps) {
     const { sync, config, BID } = this.state
 
@@ -498,16 +521,15 @@
         item.key = index
         item.$$uuid = item[config.setting.primaryKey] || ''
         item.$$BID = BID || ''
+        item.$Index = index + 1 + ''
         return item
       })
 
       this.setState({sync: false, data: _data})
-    } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
-      if (config.setting.syncRefresh === 'true') {
-        this.setState({}, () => {
-          this.reloadtable()
-        })
-      }
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({pageIndex: 1}, () => {
+        this.reloadtable()
+      })
     }
   }
 
@@ -517,8 +539,9 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('getSyncData', this.getSyncData)
     MKEmitter.addListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -530,8 +553,9 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('getSyncData', this.getSyncData)
     MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -540,33 +564,64 @@
 
     return (
       <div className="custom-normal-table" style={config.style}>
-        <NormalHeader config={config}/>
-        {searchlist && searchlist.length ?
-          <MainSearch BID={BID} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
-        }
-        <MainAction
-          BID={BID}
-          setting={setting}
-          actions={actions}
-          BData={this.state.BData}
-          columns={config.columns}
-          selectedData={selectedData}
-        />
-        <div className={'main-table-box ' + (!actions || actions.length === 0 ? 'no-action' : '')}>
-          <MainTable
+        {config.wrap.collapse === 'true' ? <Collapse bordered={false} defaultActiveKey="1" expandIconPosition="right">
+          <Panel forceRender={true} header={<NormalHeader config={config}/>} key="1">
+            {searchlist && searchlist.length ?
+              <MainSearch BID={BID} setting={config.wrap} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+            }
+            <MainAction
+              BID={BID}
+              setting={setting}
+              actions={actions}
+              BData={this.state.BData}
+              columns={config.columns}
+              selectedData={selectedData}
+            />
+            <div className={'main-table-box ' + (!actions || actions.length === 0 ? 'no-action' : '')}>
+              <MainTable
+                setting={setting}
+                columns={columns}
+                MenuID={config.uuid}
+                data={this.state.data}
+                fields={config.columns}
+                total={this.state.total}
+                lineMarks={config.lineMarks}
+                loading={this.state.loading}
+                refreshdata={this.refreshbytable}
+                statFValue={this.state.statFValue}
+                chgSelectData={(selects) => this.setState({selectedData: selects})}
+              />
+            </div>
+          </Panel>
+        </Collapse> : <>
+          <NormalHeader config={config}/>
+          {searchlist && searchlist.length ?
+            <MainSearch BID={BID} setting={config.wrap} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+          }
+          <MainAction
+            BID={BID}
             setting={setting}
-            columns={columns}
-            MenuID={config.uuid}
-            data={this.state.data}
-            fields={config.columns}
-            total={this.state.total}
-            lineMarks={config.lineMarks}
-            loading={this.state.loading}
-            refreshdata={this.refreshbytable}
-            statFValue={this.state.statFValue}
-            chgSelectData={(selects) => this.setState({selectedData: selects})}
+            actions={actions}
+            BData={this.state.BData}
+            columns={config.columns}
+            selectedData={selectedData}
           />
-        </div>
+          <div className={'main-table-box ' + (!actions || actions.length === 0 ? 'no-action' : '')}>
+            <MainTable
+              setting={setting}
+              columns={columns}
+              MenuID={config.uuid}
+              data={this.state.data}
+              fields={config.columns}
+              total={this.state.total}
+              lineMarks={config.lineMarks}
+              loading={this.state.loading}
+              refreshdata={this.refreshbytable}
+              statFValue={this.state.statFValue}
+              chgSelectData={(selects) => this.setState({selectedData: selects})}
+            />
+          </div>
+        </>}
       </div>
     )
   }
diff --git a/src/tabviews/custom/components/table/normal-table/index.scss b/src/tabviews/custom/components/table/normal-table/index.scss
index 05a3b2e..1207f33 100644
--- a/src/tabviews/custom/components/table/normal-table/index.scss
+++ b/src/tabviews/custom/components/table/normal-table/index.scss
@@ -60,4 +60,32 @@
       float: right;
     }
   }
+  .ant-collapse {
+    background-color: transparent;
+    border-radius: 0px;
+    > .ant-collapse-item {
+      border: 0;
+      >.ant-collapse-header {
+        padding: 0;
+        .normal-header {
+          padding-right: 40px;
+        }
+      }
+    }
+    .ant-collapse-item:last-child > .ant-collapse-content {
+      border-radius: 0;
+      .ant-collapse-content-box {
+        padding: 0;
+        >.button-list.toolbar-button {
+          padding: 0;
+          line-height: 55px;
+          padding-right: 60px;
+          button {
+            margin-right: 0px;
+            margin-bottom: 0px;
+          }
+        }
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/tabviews/custom/components/tabs/antv-tabs/index.jsx b/src/tabviews/custom/components/tabs/antv-tabs/index.jsx
index 1e004a5..5cff8f8 100644
--- a/src/tabviews/custom/components/tabs/antv-tabs/index.jsx
+++ b/src/tabviews/custom/components/tabs/antv-tabs/index.jsx
@@ -10,7 +10,7 @@
 const TabTransfer = asyncComponent(() => import('../../share/tabtransfer'))
 const { TabPane } = Tabs
 
-class antvBarLineChart extends Component {
+class antvTabs extends Component {
   static propTpyes = {
     bids: PropTypes.any,             // 鐖剁骇Id闆�
     config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
@@ -79,4 +79,4 @@
   }
 }
 
-export default antvBarLineChart
\ No newline at end of file
+export default antvTabs
\ No newline at end of file
diff --git a/src/tabviews/custom/components/tree/antd-tree/index.jsx b/src/tabviews/custom/components/tree/antd-tree/index.jsx
new file mode 100644
index 0000000..7cfd7c8
--- /dev/null
+++ b/src/tabviews/custom/components/tree/antd-tree/index.jsx
@@ -0,0 +1,452 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Spin, Empty, notification, Input, Tree, Icon } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import UtilsDM from '@/utils/utils-datamanage.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { TreeNode } = Tree
+const { Search } = Input
+
+class NormalTree extends Component {
+  static propTpyes = {
+    BID: PropTypes.any,              // 鐖剁骇Id
+    data: PropTypes.array,           // 缁熶竴鏌ヨ鏁版嵁
+    config: PropTypes.object,        // 缁勪欢閰嶇疆淇℃伅
+    mainSearch: PropTypes.any,       // 澶栧眰鎼滅储鏉′欢
+    menuType: PropTypes.any,         // 鑿滃崟绫诲瀷
+  }
+
+  state = {
+    BID: '',                   // 涓昏〃ID
+    config: null,              // 鍥捐〃閰嶇疆淇℃伅
+    loading: false,            // 鏁版嵁鍔犺浇鐘舵��
+    sync: false,               // 鏄惁缁熶竴璇锋眰鏁版嵁
+    data: null,                // 鏁版嵁
+    searchkey: null,           // 杩囨护鏉′欢
+    treedata: null,            // 鍒楄〃鏁版嵁闆�
+    treeNodes: null,           // 鍒楄〃鏁版嵁闆�
+    expandedKeys: [],          // 灞曞紑鐨勬爲鑺傜偣
+    selectedKeys: [],          // 閫変腑鐨勬爲鑺傜偣
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config, data, initdata, BID } = this.props
+    let _config = fromJS(config).toJS()
+    let _data = null
+    let _sync = config.setting.sync === 'true'
+
+    if (config.setting.sync === 'true' && data) {
+      _data = data[config.dataName] || []
+      _sync = false
+    } else if (config.setting.sync === 'true' && initdata) {
+      _data = initdata || []
+      _sync = false
+    }
+
+    this.setState({
+      config: _config,
+      data: _data,
+      BID: BID || '',
+      arr_field: _config.columns.map(col => col.field).join(','),
+      sync: _sync
+    }, () => {
+      if (config.setting.sync !== 'true' && config.setting.onload === 'true') {
+        this.loadData()
+      } else if (config.setting.sync === 'true' && _data) {
+        this.handleData()
+      }
+    })
+  }
+
+  /**
+   * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹�
+   */
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { sync, config } = this.state
+
+    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
+      let _data = []
+      if (nextProps.data && nextProps.data[config.dataName]) {
+        _data = nextProps.data[config.dataName] || []
+      }
+
+      this.setState({sync: false, data: _data}, () => {
+        this.handleData()
+      })
+    } else if (config.setting.syncRefresh && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
+      this.setState({}, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('reloadData', this.reloadData)
+    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
+    this.handleTimer()
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    clearTimeout(this.timer)
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('reloadData', this.reloadData)
+    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
+  }
+
+  handleTimer = () => {
+    const { config } = this.state
+
+    if (!config.timer) return
+
+    const _change = { '15s': 15000, '30s': 30000, '1min': 60000, '5min': 300000, '10min': 600000, '15min': 900000, '30min': 1800000, '1hour': 3600000 }
+
+    let timer = _change[config.timer]
+
+    if (!timer) return
+
+    let _param = {
+      func: 's_get_timers_role',
+      LText: `select '${window.GLOB.appkey || ''}','${config.uuid}'`,
+      timer_type: config.timer,
+      component_id: config.uuid
+    }
+    
+    _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) {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+        return
+      } else if (result.run_type) {
+        this.setState({timer})
+        this.timer = setTimeout(() => {
+          this.timerTask()
+        }, timer)
+      }
+    })
+  }
+
+  timerTask = () => {
+    const { timer } = this.state
+    if (!timer) return
+    
+    this.loadData(true)
+    
+    this.timer = setTimeout(() => {
+      this.timerTask()
+    }, timer)
+  }
+
+  reloadData = (menuId) => {
+    const { config } = this.state
+
+    if (config.uuid !== menuId) return
+
+    this.loadData()
+  }
+
+  resetParentParam = (MenuID, id) => {
+    const { config } = this.state
+
+    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
+    if (id !== this.state.BID) {
+      this.setState({ BID: id }, () => {
+        this.loadData()
+      })
+    }
+  }
+
+  /**
+   * @description 鏁版嵁鍔犺浇
+   */
+  async loadData (hastimer) {
+    const { mainSearch, menuType } = this.props
+    const { config, arr_field, BID } = this.state
+
+    if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇�
+      this.setState({
+        data: []
+      }, () => {
+        this.handleData()
+      })
+      return
+    }
+
+    let searches = config.setting.useMSearch && mainSearch ? mainSearch : []
+
+    let requireFields = searches.filter(item => item.required && item.value === '')
+    if (requireFields.length > 0) {
+      return
+    }
+
+    if (!hastimer) {
+      this.setState({
+        loading: true
+      })
+    }
+
+    let _orderBy = config.setting.order || ''
+    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType)
+
+    let result = await Api.genericInterface(param)
+    if (result.status) {
+      this.setState({
+        data: result.data,
+        loading: false
+      }, () => {
+        this.handleData()
+      })
+    } else {
+      this.setState({
+        loading: false,
+        timer: null
+      })
+      notification.error({
+        top: 92,
+        message: result.message,
+        duration: 10
+      })
+    }
+  }
+
+  handleData = () => {
+    const { data, searchkey, config } = this.state
+    if (!data || data.length === 0) {
+      this.setState({
+        treedata: [],
+        treeNodes: [],
+      })
+      return
+    }
+    let parentNodes = []
+    let _options = []
+    let logMap = new Map()
+
+    data.forEach(item => {
+      let pval = item[config.wrap.parentField]
+      let val = item[config.wrap.valueField]
+
+      if (!val || logMap.has(val)) return
+
+      logMap.set(val, true)
+      if (pval === config.wrap.mark) {
+        parentNodes.push({
+          // ...item,
+          $title: item[config.wrap.labelField] || '',
+          $key: val,
+          $parentId: ''
+        })
+      } else if (pval) {
+        _options.push({
+          // ...item,
+          $title: item[config.wrap.labelField] || '',
+          $key: val,
+          $parentId: pval
+        })
+      }
+    })
+    let _treedata = this.getTree(parentNodes, _options)
+    
+    let _treeNodes = []
+
+    if (!searchkey) {
+      _treeNodes = fromJS(_treedata).toJS()
+    } else {
+      _treeNodes = this.getFilterTree(fromJS(_treedata).toJS(), searchkey.toLowerCase())
+    }
+
+    this.setState({
+      treedata: _treedata,
+      treeNodes: _treeNodes,
+    })
+  }
+
+  treeFilter = (value) => {
+    const { treedata } = this.state
+
+    let _treeNodes = []
+
+    if (!value) {
+      _treeNodes = fromJS(treedata).toJS()
+    } else {
+      _treeNodes = this.getFilterTree(fromJS(treedata).toJS(), value.toLowerCase())
+    }
+
+    this.setState({
+      searchkey: value,
+      treeNodes: _treeNodes
+    })
+  }
+
+  /**
+   * @description 鑾峰彇缁撴瀯鏍戜俊鎭�
+   */
+  getFilterTree = (parents, searchkey) => {
+    return parents.filter(node => {
+      if (!node.children) {
+        return (node.$title.toLowerCase().indexOf(searchkey) >= 0 || node.$key.toLowerCase().indexOf(searchkey) >= 0)
+      } else {
+        if (node.$title.toLowerCase().indexOf(searchkey) >= 0 || node.$key.toLowerCase().indexOf(searchkey) >= 0) {
+          return true
+        }
+        
+        node.children = this.getFilterTree(node.children, searchkey)
+        if (node.children.length === 0) {
+          return false
+        } else {
+          return true
+        }
+      }
+    })
+  }
+
+  /**
+   * @description 鑾峰彇缁撴瀯鏍戜俊鎭�
+   */
+  getTree = (parents, options) => {
+    parents.forEach(parent => {
+      parent.children = []
+      // 娣诲姞鑿滃崟鐨勫瓙鍏冪礌
+      options = options.filter(option => {
+        if (option.$parentId === parent.$key) {
+          parent.children.push(option)
+          return false
+        }
+        return true
+      })
+
+      if (parent.children.length === 0) {
+        parent.children = null
+      } else {
+        parent.children = this.getTree(parent.children, options)
+      }
+    })
+    return parents
+  }
+
+  /**
+   * @description 鑾峰彇鏍戣妭鐐�
+   */
+  renderTreeNodes = (nodes) => {
+    return nodes.map(item => {
+      if (item.children) {
+        return (
+          <TreeNode icon={<span><Icon type="folder-open" /><Icon type="folder" /></span>} title={item.$title} key={item.$key} dataRef={item}>
+            {this.renderTreeNodes(item.children)}
+          </TreeNode>
+        )
+      }
+      return <TreeNode icon={<Icon type="file" />} key={item.$key} title={item.$title} dataRef={item} isLeaf />
+    })
+  }
+
+  changeExpandedKeys = (expandedKeys) => {
+    this.setState({
+      expandedKeys: expandedKeys
+    })
+  }
+
+  // 鍙抽敭灞曞紑鑺傜偣涓嬬殑鍏ㄩ儴鍒嗘敮
+  changeExpandedAllKeys = ({event, node}) => {
+    const { expandedKeys } = this.state
+    let _node = node.props.dataRef
+    event.stopPropagation()
+
+    let keys = []
+    this.getExpandKeys(_node, keys)
+
+    this.setState({
+      expandedKeys: Array.from(new Set([...keys, ...expandedKeys])),
+    })
+  }
+
+  getExpandKeys = (node, keys) => {
+    if (node.children) {
+      keys.push(node.$key)
+      node.children.forEach(_node => {
+        this.getExpandKeys(_node, keys)
+      })
+    }
+  }
+
+  selectTreeNode = (selectedKeys, {selected, node}) => {
+    const { config } = this.state
+    let _expandedKeys = fromJS(this.state.expandedKeys).toJS()
+    let _data = fromJS(node.props.dataRef).toJS()
+
+    if (_expandedKeys.indexOf(_data.$key) >= 0) {
+      _expandedKeys = _expandedKeys.filter(key => key !== _data.$key)
+    } else {
+      if (_data.children) {
+        _expandedKeys.push(_data.$key)
+        _expandedKeys = Array.from(new Set(_expandedKeys))
+      }
+    }
+
+    if (selected) {
+      MKEmitter.emit('resetSelectLine', config.uuid, (_data ? _data.$key : ''), _data)
+    }
+
+    this.setState({
+      expandedKeys: _expandedKeys,
+      selectedKeys: [_data.$key]
+    })
+  }
+
+  render() {
+    const { config, loading, treeNodes, expandedKeys, selectedKeys } = this.state
+
+    return (
+      <div className="custom-tree-box" style={config.style}>
+        {loading ?
+          <div className="loading-mask">
+            <div className="ant-spin-blur"></div>
+            <Spin />
+          </div> : null
+        }
+        {config.wrap.title || config.wrap.searchable === 'true' ? <div className="tree-header" style={config.headerStyle}>
+          <span className="title">{config.wrap.title}</span>
+          {config.wrap.searchable === 'true' ? <Search allowClear onSearch={this.treeFilter} /> : null}
+        </div> : null}
+        {treeNodes && treeNodes.length > 0 ? <div className="tree-box">
+          <Tree
+            blockNode
+            onSelect={this.selectTreeNode}
+            expandedKeys={expandedKeys}
+            selectedKeys={selectedKeys}
+            onRightClick={this.changeExpandedAllKeys}
+            onExpand={this.changeExpandedKeys}
+            showIcon={config.wrap.showIcon === 'true'}
+            showLine={config.wrap.showLine === 'true'}
+          >
+            {this.renderTreeNodes(treeNodes)}
+          </Tree>
+        </div> : null}
+        {treeNodes && treeNodes.length === 0 ? <Empty description={false}/> : null}
+      </div>
+    )
+  }
+}
+
+export default NormalTree
\ No newline at end of file
diff --git a/src/tabviews/custom/components/tree/antd-tree/index.scss b/src/tabviews/custom/components/tree/antd-tree/index.scss
new file mode 100644
index 0000000..13f499c
--- /dev/null
+++ b/src/tabviews/custom/components/tree/antd-tree/index.scss
@@ -0,0 +1,97 @@
+.custom-tree-box {
+  position: relative;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 100px;
+
+  .tree-header {
+    position: relative;
+    height: 45px;
+    padding-right: 8px;
+    border-bottom: 1px solid #e8e8e8;
+    overflow: hidden;
+    letter-spacing: 0px;
+  
+    .title {
+      text-decoration: inherit;
+      font-weight: inherit;
+      font-style: inherit;
+      float: left;
+      line-height: 45px;
+      margin-left: 10px;
+      position: relative;
+      z-index: 1;
+    }
+    .ant-input-search.ant-input-affix-wrapper {
+      width: calc(100% - 140px);
+      max-width: 130px;
+      margin-top: 6px;
+      float: right;
+      height: 30px;
+      border-radius: 20px;
+      border: 1px solid #d9d9d9;
+      opacity: 0.6;
+      input {
+        border: none;
+        border-radius: 20px;
+        height: 28px;
+      }
+    }
+  }
+  .tree-box {
+    overflow-x: auto;
+    padding-bottom: 10px;
+
+    .ant-tree-node-content-wrapper-close > span > span > .anticon-folder-open {
+      display: none;
+    }
+    .ant-tree-node-content-wrapper-open > span > span > .anticon-folder {
+      display: none;
+    }
+  }
+  .tree-box::-webkit-scrollbar {
+    height: 10px;
+  }
+  .tree-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);
+  }
+  .tree-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);
+  }
+  .ant-empty {
+    position: absolute;
+    top: calc(50% - 34px);
+    left: calc(50% - 92px);
+
+    .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;
+    }
+  }
+}
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 97b6365..8cf4cc6 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -3,15 +3,13 @@
 import { connect } from 'react-redux'
 import { is, fromJS } from 'immutable'
 import { notification, Spin, Row, Col } from 'antd'
-import moment from 'moment'
-import md5 from 'md5'
 
 import Api from '@/api'
 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 UtilsDM from '@/utils/utils-datamanage.js'
+import UtilsDM, { getStructuredParams, getStructDefaultParam } from '@/utils/utils-datamanage.js'
 import asyncComponent from '@/utils/asyncComponent'
 import MKEmitter from '@/utils/events.js'
 import NotFount from '@/components/404'
@@ -21,6 +19,8 @@
 const AntvBarAndLine = asyncComponent(() => import('./components/chart/antv-bar-line'))
 const AntvPie = asyncComponent(() => import('./components/chart/antv-pie'))
 const AntvTabs = asyncComponent(() => import('./components/tabs/antv-tabs'))
+const AntvDashboard = asyncComponent(() => import('./components/chart/antv-dashboard'))
+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 NormalForm = asyncComponent(() => import('./components/form/normal-form'))
@@ -32,6 +32,8 @@
 const NormalGroup = asyncComponent(() => import('./components/group/normal-group'))
 const BraftEditor = asyncComponent(() => import('./components/editor/braft-editor'))
 const SandBox = asyncComponent(() => import('./components/code/sand-box'))
+const NormalTree = asyncComponent(() => import('./components/tree/antd-tree'))
+const Balcony = asyncComponent(() => import('./components/card/balcony'))
 const SettingComponent = asyncComponent(() => import('@/tabviews/zshare/settingcomponent'))
 const PagemsgComponent = asyncComponent(() => import('@/tabviews/zshare/pageMessage'))
 
@@ -167,9 +169,9 @@
       }
 
       let regs = [
-        { reg: /@userName@/ig, value: userName },
-        { reg: /@fullName@/ig, value: fullName },
-        { reg: /@login_city@/ig, value: city }
+        { reg: /@userName@/ig, value: `'${userName}'` },
+        { reg: /@fullName@/ig, value: `'${fullName}'` },
+        { reg: /@login_city@/ig, value: `'${city}'` }
       ]
       
       if (window.GLOB.externalDatabase !== null) {
@@ -182,7 +184,7 @@
         config.urlFields.forEach(field => {
           let val = `'${param ? (param[field] || '') : ''}'`
           regs.push({
-            reg: new RegExp(field, 'ig'),
+            reg: new RegExp('@' + field + '@', 'ig'),
             value: val
           })
         })
@@ -336,7 +338,7 @@
     })
 
     Api.directRequest(url, setting.method, param, setting.cross).then(res => {
-      if (typeof(res) !== 'object' || Array.isArray(res)) {
+      if (typeof(res) !== 'object') {
         let error = '鏈煡鐨勮繑鍥炵粨鏋滐紒'
 
         if (typeof(res) === 'string') {
@@ -351,6 +353,9 @@
 
         this.customCallbackRequest(_result, setting, inters)
       } else {
+        if (Array.isArray(res)) {
+          res = { data: res }
+        }
         res.mk_api_key = mkey
         this.customCallbackRequest(res, setting, inters)
       }
@@ -462,7 +467,7 @@
           tab.components.forEach(comp => {
             if (comp.type === 'tabs' && comp.parentIds) {
               supIds.push(...comp.parentIds)
-            } else if (comp.setting.supModule) {
+            } else if (comp.setting && comp.setting.supModule) {
               supIds.push(comp.setting.supModule)
             }
           })
@@ -477,14 +482,14 @@
         }
 
         item.components = this.filterComponent(item.components, roleId, permAction, permMenus)
-      } else if (item.type === 'pie' || item.type === 'bar' || item.type === 'line') {
+      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter'].includes(item.type)) {
         if (
           item.plot.blacklist && item.plot.blacklist.length > 0 &&
           item.plot.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
         ) {
           return false
         }
-      } else {
+      } else if (item.wrap) {
         if (
           item.wrap.blacklist && item.wrap.blacklist.length > 0 &&
           item.wrap.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
@@ -492,21 +497,50 @@
           return false
         }
       }
-      // 鎼滅储榛戝悕鍗曡繃婊�
+
+      // 鎼滅储鏉′欢鍒濆鍖�
       if (item.search && item.search.length > 0) {
-        item.search = item.search.map(cell => {
-          cell.oriInitval = cell.initval
-
-          if (!cell.blacklist || cell.blacklist.length === 0) return cell
-          if (cell.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-            cell.Hide = 'true'
-          }
-
-          return item
-        })
+        item.search = Utils.initSearchVal(item.search)
       }
+
       if (item.type === 'table' && item.subtype === 'normaltable') {
-        item.cols = this.getCols(item.cols, roleId, permMenus)
+        let statFields = []
+        let getCols = (cols) => {
+          return cols.filter(col => {
+            if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
+              return false
+            } else if (col.Hide === 'true') {
+              return false
+            }
+            if (col.type === 'number' && col.sum === 'true' && !statFields.includes(col.field)) {
+              statFields.push(col)
+            } else if (col.type === 'colspan') {
+              col.subcols = getCols(col.subcols || [])
+              if (col.subcols.length === 0) {
+                return false
+              }
+            } else if (col.type === 'custom') {
+              col.elements = col.elements.map(cell => {
+                if (['text', 'number', 'link'].includes(cell.eleType) && !cell.height) {
+                  cell.innerHeight = 'auto'
+                }
+                return cell
+              })
+            }
+      
+            if (col.linkmenu && col.linkmenu.length > 0) {
+              let menu_id = col.linkmenu.pop()
+              col.linkThdMenu = permMenus.filter(m => m.MenuID === menu_id)[0] || ''
+            } else {
+              col.linkThdMenu = ''
+            }
+
+            return true
+          })
+        }
+        
+        item.cols = getCols(item.cols)
+        item.statFields = statFields
       }
 
       // 鏉冮檺杩囨护
@@ -516,20 +550,26 @@
         item.action = item.action.filter(cell => {
           cell.logLabel = item.name + '-' + cell.label
           cell.ContainerId = this.state.ContainerId
-          cell.syncComponentId = cell.syncComponent ? cell.syncComponent.pop() : ''
+          cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
           cell.$menuId = item.uuid
           cell.$tabId = tabId
-          cell.$type = 'CustomPage'
+          cell.$view = 'CustomPage'
 
           if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
             cell = this.getPrinter(cell, item.uuid)
           }
 
+          if (cell.btnstyle) { // 鍏煎
+            cell.style = cell.style || {}
+            cell.style = {...cell.style, ...cell.btnstyle}
+          }
+
           return isHS || permAction[cell.uuid]
         })
       }
+
       if (item.type === 'card') {
-        item.subcards.forEach(card => {
+        item.subcards && item.subcards.forEach(card => {
           let _hasheight = card.style.height && card.style.height !== 'auto'
 
           if (card.style.shadow) { // 鍗$墖闃村奖
@@ -542,13 +582,17 @@
               cell.logLabel = item.name + '-' + cell.label
               cell.Ot = 'requiredSgl'
               cell.ContainerId = this.state.ContainerId
-              cell.syncComponentId = cell.syncComponent ? cell.syncComponent.pop() : ''
+              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
               cell.$menuId = item.uuid
               cell.$tabId = tabId
-              cell.$type = 'CustomPage'
+              cell.$view = 'CustomPage'
 
               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}
               }
             } else if (['text', 'number', 'link'].includes(cell.eleType) && !cell.height && _hasheight) {
               cell.innerHeight = 'auto'
@@ -561,13 +605,17 @@
               cell.logLabel = item.name + '-' + cell.label
               cell.Ot = 'requiredSgl'
               cell.ContainerId = this.state.ContainerId
-              cell.syncComponentId = cell.syncComponent ? cell.syncComponent.pop() : ''
+              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
               cell.$menuId = item.uuid
               cell.$tabId = tabId
-              cell.$type = 'CustomPage'
+              cell.$view = 'CustomPage'
 
               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}
               }
             } else if (['text', 'number', 'link'].includes(cell.eleType) && !cell.height && _hasheight) {
               cell.innerHeight = 'auto'
@@ -575,21 +623,45 @@
             return cell.eleType !== 'button' || isHS || permAction[cell.uuid]
           })
         })
+      } else if (item.type === 'balcony') {
+        item.elements = item.elements.filter(cell => {
+          if (cell.eleType === 'button') {
+            cell.logLabel = item.name + '-' + cell.label
+            cell.ContainerId = this.state.ContainerId
+            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
+            cell.$menuId = item.uuid
+            cell.$tabId = tabId
+            cell.$view = 'CustomPage'
+
+            if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
+              cell = this.getPrinter(cell, item.uuid)
+            }
+          } else if (['text', 'number', 'link'].includes(cell.eleType) && !cell.height) {
+            cell.innerHeight = 'auto'
+          }
+
+          return cell.eleType !== 'button' || isHS || permAction[cell.uuid]
+        })
       } else if ((item.type === 'table' && item.subtype === 'tablecard') || item.type === 'carousel') {
-        item.subcards.forEach(card => {
+        item.subcards && item.subcards.forEach(card => {
           let _hasheight = card.style.height && card.style.height !== 'auto'
           card.elements = card.elements.filter(cell => {
             if (cell.eleType === 'button') {
               cell.logLabel = item.name + '-' + cell.label
               cell.Ot = 'requiredSgl'
               cell.ContainerId = this.state.ContainerId
-              cell.syncComponentId = cell.syncComponent ? cell.syncComponent.pop() : ''
+              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
               cell.$menuId = item.uuid
               cell.$tabId = tabId
-              cell.$type = 'CustomPage'
+              cell.$view = 'CustomPage'
 
               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}
               }
             } else if (['text', 'number', 'link'].includes(cell.eleType) && !cell.height && _hasheight) {
               cell.innerHeight = 'auto'
@@ -604,13 +676,18 @@
             cell.logLabel = item.name + '-' + cell.label
             cell.Ot = 'requiredSgl'
             cell.ContainerId = this.state.ContainerId
-            cell.syncComponentId = cell.syncComponent ? cell.syncComponent.pop() : ''
+            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
             cell.$menuId = item.uuid
             cell.$tabId = tabId
-            cell.$type = 'CustomPage'
+            cell.$view = 'CustomPage'
 
             if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) { // 鎵撳嵃鏈鸿缃�
               cell = this.getPrinter(cell, item.uuid)
+            }
+
+            if (cell.btnstyle) { // 鍏煎
+              cell.style = cell.style || {}
+              cell.style = {...cell.style, ...cell.btnstyle}
             }
 
             return isHS || permAction[cell.uuid]
@@ -656,31 +733,6 @@
     return item
   }
 
-  getCols = (cols, roleId, permMenus) => {
-    return cols.filter(col => {
-      if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-        return false
-      } else if (col.Hide === 'true') {
-        return false
-      }
-      if (col.type === 'colspan') {
-        col.subcols = this.getCols(col.subcols || [], roleId, permMenus)
-        if (col.subcols.length === 0) {
-          return false
-        }
-      }
-
-      if (col.linkmenu && col.linkmenu.length > 0) {
-        let menu_id = col.linkmenu.pop()
-        col.linkThdMenu = permMenus.filter(m => m.MenuID === menu_id)[0] || ''
-      } else {
-        col.linkThdMenu = ''
-      }
-
-      return true
-    })
-  }
-
   // 鏍煎紡鍖栭粯璁よ缃�
   formatSetting = (components, params, mainSearch, inherit, regs) => {
     return components.map(component => {
@@ -697,12 +749,19 @@
         return component
       }
 
-      if (['propcard', 'brafteditor', 'sandbox', 'stepform'].includes(component.subtype) && component.wrap.datatype === 'static') {
-        component.format = ''
+      if (component.setting) {
+        component.setting.useMSearch = component.setting.useMSearch === 'true'
+        component.setting.syncRefresh = (component.setting.useMSearch && component.setting.syncRefresh === 'true')
       }
 
-      if (!component.setting) return component // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
-      if (!component.format) return component  // 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
+      if (component.wrap && component.wrap.datatype === 'static') {
+        component.format = ''
+        component.setting = component.setting || {}
+        component.setting.useMSearch = false
+        component.setting.syncRefresh = false
+      }
+
+      if (!component.setting || !component.format) return component  // 1銆佷笉浣跨敤绯荤粺鍑芥暟鏃讹紱2銆� 娌℃湁鍔ㄦ�佹暟鎹�  鏁版嵁鏍煎紡 array 鎴� object
       if (component.setting.interType !== 'system') { // 涓嶄娇鐢ㄧ郴缁熷嚱鏁版椂
         component.setting.sync = 'false'
         component.setting.laypage = component.setting.laypage === 'true'
@@ -718,7 +777,7 @@
         }
       })
       delete component.scripts
-
+      component.setting.$name = component.name || ''
       component.setting.execute = component.setting.execute !== 'false'  // 榛樿sql鏄惁鎵ц锛岃浆涓篵oolean 缁熶竴鏍煎紡
       component.setting.laypage = component.setting.laypage === 'true'   // 鏄惁鍒嗛〉锛岃浆涓篵oolean 缁熶竴鏍煎紡
 
@@ -750,8 +809,25 @@
       // dataName 绯荤粺鐢熸垚鐨勬暟鎹簮鍚嶇О
       // pageable 鏄惁鍒嗛〉锛岀粍浠跺睘鎬э紝涓嶅垎椤电殑缁勪欢鎵嶅彲浠ョ粺涓�鏌ヨ
       if (component.floor === 1 && component.dataName && (!component.pageable || (component.pageable && !component.setting.laypage)) && component.setting.onload === 'true' && component.setting.sync === 'true') {
-        let param = this.getDefaultParam(component, mainSearch)
-        params.push(param)
+        let searchlist = []
+        if (component.search && component.search.length > 0) {
+          searchlist = Utils.initMainSearch(component.search)
+        }
+        if (component.setting.useMSearch) {
+          let keys = searchlist.map(item => item.key)
+          mainSearch.forEach(item => {
+            if (!keys.includes(item.key)) {
+              searchlist.push(item)
+            }
+          })
+        }
+
+        if (searchlist.filter(item => item.required && item.value === '').length > 0) {
+          component.setting.sync = 'false'
+          component.setting.onload = 'false'
+        } else {
+          params.push(getStructDefaultParam(component, searchlist))
+        }
       } else if (component.floor === 1) {
         component.setting.sync = 'false'
       }
@@ -761,138 +837,10 @@
   }
 
   /**
-   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
-   */
-  getDefaultParam = (component, mainSearch) => {
-    const { columns, search, setting, dataName, format } = component
-    
-    let searchlist = []
-    if (search && search.length > 0) {
-      searchlist = Utils.initMainSearch(search)
-    }
-
-    if (setting.useMSearch === 'true') {
-      let keys = searchlist.map(item => item.key)
-      mainSearch.forEach(item => {
-        if (!keys.includes(item.key)) {
-          searchlist.push(item)
-        }
-      })
-    }
-
-    let arr_field = columns.map(col => col.field)
-    let _dataresource = setting.dataresource
-    let _customScript = setting.customScript
-
-    
-    if (setting.queryType === 'statistics' || _customScript) {
-      let allSearch = Utils.getAllSearchOptions(searchlist)
-      let regoptions = allSearch.map(item => {
-        return {
-          reg: new RegExp('@' + item.key + '@', 'ig'),
-          value: `'${item.value}'`
-        }
-      })
-
-      regoptions.forEach(item => {
-        if (_dataresource && setting.queryType === 'statistics') {
-          _dataresource = _dataresource.replace(item.reg, item.value)
-        }
-        _customScript = _customScript.replace(item.reg, item.value)
-      })
-    }
-
-    let _search = ''
-    if (setting.queryType !== 'statistics' && _dataresource) {
-      _search = Utils.joinMainSearchkey(searchlist)
-      _search = _search ? 'where ' + _search : ''
-    }
-
-    if (setting.order && _dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from (select ${arr_field.join(',')} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
-    } else if (_dataresource) {
-      _dataresource = `select top 1000 ${arr_field.join(',')} from ${_dataresource} ${_search} `
-    }
-
-    // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
-    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
-      _customScript &&  console.info(`${_dataresource ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
-      _dataresource &&  console.info(_dataresource)
-    }
-
-    return {
-      name: dataName,
-      columns: columns,
-      par_tablename: '',
-      type: format === 'array' ? format : '',
-      primaryKey: setting.primaryKey || '',
-      foreign_key: '',
-      sql: _dataresource,
-      script: _customScript
-    }
-  }
-
-  /**
    * @description 涓昏〃鏁版嵁鍔犺浇
    */ 
   loadmaindata = (params) => {
-    const { config } = this.state
-    let LText_field = []
-    let diffUser = false
-    let userName = sessionStorage.getItem('User_Name') || ''
-    let fullName = sessionStorage.getItem('Full_Name') || ''
-    let city = sessionStorage.getItem('city') || ''
-
-    if (sessionStorage.getItem('isEditState') === 'true') {
-      userName = sessionStorage.getItem('CloudUserName') || ''
-      fullName = sessionStorage.getItem('CloudFullName') || ''
-    }
-    
-    let _LText = params.map((item, index) => {
-      let _script = item.script
-
-      if (index === 0) {
-        _script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50)
-          select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @login_city='${city}'
-          ${_script}
-        `
-      }
-      if (!diffUser && (/@userid@/ig.test(item.sql) || /@userid@/ig.test(_script))) {
-        diffUser = true
-      }
-
-      item.columns.forEach(cell => {
-        LText_field.push(`Select '${item.name}' as tablename,'${cell.field}' as fieldname,'${cell.datatype}' as field_type`)
-      })
-      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(item.sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
-    })
-
-    // 鎶婂ぇ鎺ュ彛sPC_Get_structured_data鐨刲text鎷嗘垚涓変唤锛岀涓�娈碉細@LText1锛岀浜屾@LText锛岀涓夋@LText2
-    let param = {
-      func: 'sPC_Get_structured_data',
-      LText: _LText.join(' union all '),
-      LText_field: LText_field.join(' union all '),
-      BID: this.state.BID || ''
-    }
-
-    let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
-
-    param.LText1 = LText1
-    param.LText = LText
-    param.LText2 = LText2
-    param.LText_field = Utils.formatOptions(param.LText_field)
-
-    if (config.cacheUseful === 'true') {
-      param.time_type = config.timeUnit
-      param.time_limit = config.cacheTime
-      if (diffUser) {
-        param.userid = sessionStorage.getItem('UserID')
-      }
-      param.data_md5 = md5(JSON.stringify(param))
-    }
-
-    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+    let param = getStructuredParams(params, this.state.config, this.state.BID)
 
     this.setState({loading: true, loadingview: false})
 
@@ -1005,6 +953,18 @@
             <AntvPie config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'scatter') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvScatter config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'dashboard') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <AntvDashboard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'form') {
         return (
           <Col span={item.width} key={item.uuid}>
@@ -1014,7 +974,7 @@
       } else if (item.type === 'search') {
         return (
           <Col span={item.width} key={item.uuid}>
-            <MainSearch config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} refreshdata={this.resetSearch} />
+            <MainSearch config={item} BID={BID} menuType={menuType} refreshdata={this.resetSearch} />
           </Col>
         )
       } else if (item.type === 'tabs') {
@@ -1033,6 +993,12 @@
         return (
           <Col span={item.width} key={item.uuid}>
             <PropCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
+      } else if (item.type === 'balcony') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <Balcony menu={config} config={item} data={data} BID={_bid} menuType={menuType} />
           </Col>
         )
       } else if (item.type === 'carousel' && item.subtype === 'datacard') {
@@ -1071,6 +1037,12 @@
             <BraftEditor config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
           </Col>
         )
+      } else if (item.type === 'tree') {
+        return (
+          <Col span={item.width} key={item.uuid}>
+            <NormalTree config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} />
+          </Col>
+        )
       } else if (item.type === 'code') {
         return (
           <Col span={item.width} key={item.uuid}>
diff --git a/src/tabviews/custom/index.scss b/src/tabviews/custom/index.scss
index 4e7b7e6..a0314f1 100644
--- a/src/tabviews/custom/index.scss
+++ b/src/tabviews/custom/index.scss
@@ -43,6 +43,12 @@
   .ant-btn-link:hover {
     opacity: 0.8;
   }
+  .button-list.toolbar-button {
+    button {
+      height: auto;
+      min-height: 32px;
+    }
+  }
 }
 .custom-page-wrap.loading {
   .ant-spin-spinning:not(.view-spin) {
diff --git a/src/tabviews/formtab/formgroup/index.jsx b/src/tabviews/formtab/formgroup/index.jsx
index aed3d1a..e03fbc1 100644
--- a/src/tabviews/formtab/formgroup/index.jsx
+++ b/src/tabviews/formtab/formgroup/index.jsx
@@ -4,7 +4,6 @@
 import { Form, Row, Col, Input, InputNumber, Select, DatePicker, notification, Collapse } from 'antd'
 import moment from 'moment'
 import { formRule } from '@/utils/option.js'
-import Utils from '@/utils/utils.js'
 import FileUpload from '@/tabviews/zshare/fileupload'
 import './index.scss'
 
@@ -71,24 +70,6 @@
             _fieldsvalue[key] = _val
           } else if (datatype[key] === 'fileupload') {
             let _val = nextProps.data[key] ? nextProps.data[key] : ''
-
-            if (_val) {
-              try {
-                _val = _val.split(',').map((url, index) => {
-                  return {
-                    uid: `${index}`,
-                    name: url.slice(url.lastIndexOf('/') + 1),
-                    status: 'done',
-                    url: url,
-                    origin: true
-                  }
-                })
-              } catch {
-                _val = []
-              }
-            } else {
-              _val = []
-            }
 
             _fieldsvalue[key] = _val
           } else if (datatype[key] === 'text' || datatype[key] === 'textarea') {
@@ -521,30 +502,11 @@
           </Col>
         )
       } else if (item.type === 'fileupload') {
-        let filelist = this.props.data ? this.props.data[item.field] : item.initval
-        if (filelist && this.state.readin[item.field]) {
-          try {
-            filelist = filelist.split(',').map((url, index) => {
-              return {
-                uid: `${index}`,
-                name: url.slice(url.lastIndexOf('/') + 1),
-                status: 'done',
-                url: url,
-                origin: true
-              }
-            })
-          } catch {
-            filelist = []
-          }
-        } else {
-          filelist = []
-        }
-
         fields.push(
           <Col span={24 / cols} key={index}>
             <Form.Item label={item.label}>
               {getFieldDecorator(item.field, {
-                initialValue: filelist,
+                initialValue: item.initval,
                 rules: [
                   {
                     required: item.required === 'true',
@@ -552,7 +514,7 @@
                   }
                 ]
               })(
-                <FileUpload />
+                <FileUpload config={item}/>
               )}
             </Form.Item>
           </Col>
@@ -674,19 +636,8 @@
               _value = values[key] ? values[key].join(',') : ''
 
             } else if (this.state.datatype[key] === 'fileupload') {
-              let vals = []
+              _value = values[key]
 
-              if (values[key] && values[key].length > 0) {
-                values[key].forEach(_val => {
-                  if (_val.origin && _val.url) {
-                    vals.push(_val.url)
-                  } else if (!_val.origin && _val.status === 'done' && _val.response) {
-                    vals.push(Utils.getrealurl(_val.response))
-                  }
-                })
-              }
-
-              _value = vals.join(',')
             } else if (this.state.datatype[key] === 'text' || this.state.datatype[key] === 'textarea') {
               _value = values[key].replace(/\t*|\v*/g, '') // 鍘婚櫎鍒惰〃绗�
 
diff --git a/src/tabviews/home/index.jsx b/src/tabviews/home/index.jsx
index 26fbcd0..dfb3f7d 100644
--- a/src/tabviews/home/index.jsx
+++ b/src/tabviews/home/index.jsx
@@ -1,5 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import { connect } from 'react-redux'
 import { notification, Spin } from 'antd'
 
 import Api from '@/api'
@@ -17,11 +18,25 @@
   state = {
     loading: true,
     background: sessionStorage.getItem('home_background'),
+    waiting: true,
     view: ''
   }
 
   componentDidMount () {
     this.loadHomeConfig()
+    if (this.props.permMenus.length > 0 && JSON.stringify(this.props.permAction) !== '{}') {
+      this.setState({
+        waiting: false
+      })
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    if (nextProps.permMenus.length > 0 && JSON.stringify(nextProps.permAction) !== '{}') {
+      this.setState({
+        waiting: false
+      })
+    }
   }
 
   loadHomeConfig = () => {
@@ -39,6 +54,7 @@
         } else {
           this.setState({
             loading: false,
+            waiting: false,
             view: 'default'
           })
         }
@@ -57,9 +73,9 @@
   }
 
   render() {
-    const { loading, view, background } = this.state
+    const { loading, waiting, view, background } = this.state
 
-    if (loading) {
+    if (loading || waiting) {
       return (<div className="home-loading-view" style={{background: background}}><Spin className="home-box-spin" size="large" /></div>)
     } else if (view === 'custom') {
       return (<CustomPage MenuID={this.props.MenuID}/>)
@@ -69,4 +85,15 @@
   }
 }
 
-export default Home
\ No newline at end of file
+const mapStateToProps = (state) => {
+  return {
+    permAction: state.permAction,
+    permMenus: state.permMenus
+  }
+}
+
+const mapDispatchToProps = () => {
+  return {}
+}
+
+export default connect(mapStateToProps, mapDispatchToProps)(Home)
\ No newline at end of file
diff --git a/src/tabviews/scriptmanage/config.jsx b/src/tabviews/scriptmanage/config.jsx
index e9ccbfc..493937d 100644
--- a/src/tabviews/scriptmanage/config.jsx
+++ b/src/tabviews/scriptmanage/config.jsx
@@ -15,7 +15,7 @@
   },
   tables: [{"TbName":"s_custom_script","Remark":"鑷畾涔夎剼鏈�"}],
   search: [
-    {"label":"鎻忚堪","field":"Remark","type":"text","initval":"","match":"like","required":"false","ratio":6,"blacklist":[],"uuid":"1587005744706mppigfhf206gciiivf9"}
+    {"label":"鎻忚堪","field":"Remark","type":"text","initval":"","oriInitval":"", "match":"like","required": false,"ratio":6,"blacklist":[],"uuid":"1587005744706mppigfhf206gciiivf9"}
   ],
   action:[
     {"label":"娣诲姞","OpenType":"pop","intertype":"inner","innerFunc":"s_custom_script_adduptdel","position":"toolbar","Ot":"notRequired","execSuccess":"grid","execError":"never","icon":"","class":"green","sql":"s_custom_script","sqlType":"insert","uuid":"1587006129803057fs8mb9q151ae6165"},
diff --git a/src/tabviews/scriptmanage/index.jsx b/src/tabviews/scriptmanage/index.jsx
index 68a4ce8..868fc97 100644
--- a/src/tabviews/scriptmanage/index.jsx
+++ b/src/tabviews/scriptmanage/index.jsx
@@ -135,7 +135,6 @@
     if (result.status) {
       this.setState({
         data: result.data.map((item, index) => {
-          // item.LongParam = this.UnformatOptions(item.LongParam)
           item.key = index
           item.$$uuid = item[setting.primaryKey] || ''
           return item
@@ -154,75 +153,6 @@
       })
     }
   }
-
-  // UnformatOptions = (value) => {
-  //   if (!value) return ''
-  //   let salt = 'minKe' // 鐩愬��
-  //   let _value = ''
-  //   const formatKeys = [
-  //     { key: 'select', value: ' msltk ' },
-  //     { key: 'from', value: ' mfrmk ' },
-  //     { key: 'where', value: ' mwhrk ' },
-  //     { key: 'order by', value: ' modbk ' },
-  //     { key: 'asc', value: ' modack ' },
-  //     { key: 'desc', value: ' moddesk ' },
-  //     { key: 'top', value: ' mtpk ' },
-  //     { key: 'like', value: ' mlkk ' },
-  //     { key: 'not like', value: ' mnlkk ' },
-  //     { key: 'between', value: ' mbtnk ' },
-  //     { key: 'and', value: ' madk ' },
-  //     { key: 'insert', value: ' mistk ' },
-  //     { key: 'into', value: ' mitk ' },
-  //     { key: 'update', value: ' muptk ' },
-  //     { key: 'delete', value: ' mdelk ' },
-  //     { key: 'begin', value: ' mbgink ' },
-  //     { key: 'end', value: ' medk ' },
-  //     { key: 'if', value: ' mefk ' },
-  //     { key: 'while', value: ' mwilk ' },
-  //     { key: 'create', value: ' mcrtk ' },
-  //     { key: 'alter', value: ' matek ' },
-  //     { key: 'len', value: ' mlnk ' },
-  //     { key: 'left', value: ' mlftk ' },
-  //     { key: 'right', value: ' mritk ' },
-  //     { key: 'union', value: ' munok ' },
-  //     { key: 'varchar', value: ' mvcrk ' },
-  //     { key: 'getdate', value: ' mgtdtk ' },
-  //     { key: 'TRY', value: ' mtryonek ' },
-  //     { key: 'TRAN', value: ' mtrnk ' },
-  //     { key: 'goto', value: ' mgtk ' },
-  //     { key: 'set', value: ' mstk ' },
-  //     { key: 'ROLLBACK', value: ' mrlbkk ' }
-  //   ]
-
-  //   try {
-  //     try {
-  //       _value = JSON.parse(window.decodeURIComponent(window.atob(value)))
-  //     } catch {
-  //       _value = ''
-  //     }
-
-  //     if (!_value) {
-  //       _value = window.atob(value)
-  //       _value = _value.replace(salt, '')
-  //       _value = window.decodeURIComponent(window.atob(_value))
-  
-  //       _value = _value.replace(/\smpercent\s/g, '%')
-  
-  //       formatKeys.forEach(item => {
-  //         let reg = new RegExp(item.value, 'g')
-  //         _value = _value.replace(reg, ' ' + item.key + ' ')
-  //       })
-  
-  //       _value = _value.replace(/\s\n\s/ig, '\n')
-  //       _value = _value.replace(/(^\s+|\s+$)/ig, '')
-  //     }
-  //   } catch {
-  //     console.warn('UnFormat Failure')
-  //     _value = ''
-  //   }
-
-  //   return _value
-  // }
 
   /**
    * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
diff --git a/src/tabviews/subtable/index.jsx b/src/tabviews/subtable/index.jsx
index b31d3b2..f917266 100644
--- a/src/tabviews/subtable/index.jsx
+++ b/src/tabviews/subtable/index.jsx
@@ -141,16 +141,17 @@
         config.action = config.action.filter(item => permAction[item.uuid])
       }
 
-      let roleId = sessionStorage.getItem('role_id') || '' // 瑙掕壊ID
-      // 瀛楁鏉冮檺榛戝悕鍗�
-      config.search = config.search.map(item => {
-        item.oriInitval = item.initval
-        if (!item.blacklist || item.blacklist.length === 0) return item
-        if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-          item.Hide = 'true'
+      config.search = Utils.initSearchVal(config.search)
+
+      let hasReqFields = false
+      config.search.forEach(field => {
+        if (field.required) {
+          hasReqFields = true
         }
-        return item
       })
+
+      // 瀛楁鏉冮檺榛戝悕鍗�
+      let roleId = sessionStorage.getItem('role_id') || '' // 瑙掕壊ID
 
       config.columns = config.columns.map(col => {
         if (!col.blacklist || col.blacklist.length === 0) return col
@@ -260,16 +261,6 @@
         _columns.push(config.gridBtn)
       }
 
-      let valid = true // 鎼滅储鏉′欢蹇呭~楠岃瘉
-      let hasReqFields = false
-      config.search.forEach(field => {
-        if (field.required !== 'true') return
-        hasReqFields = true
-        if (!field.initval) {
-          valid = false
-        }
-      })
-
       config.setting.tabType = 'sub'
       // 鏁版嵁婧愪俊鎭澶勭悊
       config.setting.laypage = config.setting.laypage !== 'false'     // 鏄惁鍒嗛〉锛岃浆涓篵oolean 缁熶竴鏍煎紡
@@ -306,6 +297,26 @@
           config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
           config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
         }
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+
+        regs.forEach(cell => {
+          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
+          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
+        })
       }
 
       this.setState({
@@ -319,10 +330,10 @@
         actions: _actions,
         columns: _columns,
         arr_field: _arrField.join(','),
-        search: Utils.initMainSearch(config.search), // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
+        search: Utils.initMainSearch(config.search),
         hasReqFields
       }, () => {
-        if (config.setting.onload !== 'false' && (!Tab.supMenu || BID || Tab.isTreeNode) && valid) { // 鍒濆鍖栧彲鍔犺浇
+        if (config.setting.onload !== 'false' && (!Tab.supMenu || BID || Tab.isTreeNode)) { // 鍒濆鍖栧彲鍔犺浇
           this.loadData()
         }
       })
@@ -350,23 +361,17 @@
       searches = [...mainSearch, ...searches]
     }
 
-    let requireFields = []
     if (hasReqFields) {
-      requireFields = searches.filter(item => item.required && (!item.value || item.value.length === 0))
+      let requireFields = searches.filter(item => item.required && item.value === '')
+      if (requireFields.length > 0) {
+        this.setState({
+          loading: false
+        })
+        return
+      }
     }
     
-    if (requireFields.length > 0) {
-      let prex = this.props.Tab && this.props.Tab.label ? this.props.Tab.label + '-' : ''
-      let labels = requireFields.map(item => item.label)
-      labels = Array.from(new Set(labels))
-
-      notification.warning({
-        top: 92,
-        message: prex + this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
-        duration: 3
-      })
-      return
-    } else if (this.props.Tab.supMenu && !BID) { // 涓昏〃ID涓嶅瓨鍦ㄦ椂锛屼笉鏌ヨ瀛愯〃
+    if (this.props.Tab.supMenu && !BID) { // 涓昏〃ID涓嶅瓨鍦ㄦ椂锛屼笉鏌ヨ瀛愯〃
       this.setState({
         data: [],
         selectedData: [],
@@ -466,7 +471,7 @@
     })
 
     Api.directRequest(url, setting.method, param, setting.cross).then(res => {
-      if (typeof(res) !== 'object' || Array.isArray(res)) {
+      if (typeof(res) !== 'object') {
         let error = '鏈煡鐨勮繑鍥炵粨鏋滐紒'
 
         if (typeof(res) === 'string') {
@@ -481,6 +486,9 @@
 
         this.customCallbackRequest(_result)
       } else {
+        if (Array.isArray(res)) {
+          res = { data: res }
+        }
         res.mk_api_key = mkey
         this.customCallbackRequest(res)
       }
@@ -596,6 +604,11 @@
     this.getStatFieldsValue(searches)
 
     if (result.status) {
+      let start = 1
+      if (setting.laypage) {
+        start = pageSize * (pageIndex - 1) + 1
+      }
+
       this.setState({
         data: result.data.map((item, index) => {
           if (absFields.length) {
@@ -609,6 +622,7 @@
           item.key = index
           item.$$uuid = item[setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = start + index + ''
 
           return item
         }),
@@ -676,6 +690,7 @@
           data = data.map(item => {
             if (item.$$uuid === _data.$$uuid) {
               _data.key = item.key
+              _data.$Index = item.$Index
               return _data
             } else {
               return item
@@ -813,7 +828,7 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { Tab, mainSearch, MenuID } = this.props
     const { arr_field, orderBy, search, setting} = this.state
 
@@ -824,7 +839,7 @@
       searches = [...mainSearch, ...search]
     }
 
-    MKEmitter.emit('execExcelout', MenuID, btnId, {
+    MKEmitter.emit('returnModuleParam', MenuID, btnId, {
       arr_field: arr_field,
       orderBy: orderBy || setting.order,
       search: searches,
@@ -920,7 +935,7 @@
 
   componentDidMount () {
     MKEmitter.addListener('reloadData', this.reloadData)
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -932,7 +947,7 @@
       return
     }
     MKEmitter.removeListener('reloadData', this.reloadData)
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -943,7 +958,7 @@
       <div className="subtable" id={'subtable' + this.props.MenuID}>
         {loadingview && <Spin />}
         {searchlist && searchlist.length ?
-          <SubSearch BID={this.props.BID} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+          <SubSearch BID={this.props.BID} setting={setting} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
         }
         {config ? <Row className="chart-view" gutter={16}>
           {/* 瑙嗗浘缁� */}
@@ -973,7 +988,7 @@
                   </div>
                   <div className="subtable-box">
                     {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && this.state.data && this.state.data.length > 0 ?
-                      <Switch title="鏀惰捣" className="subtable-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" defaultChecked={pickup} onChange={this.pickupChange} /> : null
+                      <Switch title="鏀惰捣" className="subtable-pickup" checkedChildren="寮�" unCheckedChildren="鍏�" checked={pickup} onChange={this.pickupChange} /> : null
                     }
                     <SubTable
                       tableId={this.props.Tab.uuid}
diff --git a/src/tabviews/subtabtable/index.jsx b/src/tabviews/subtabtable/index.jsx
index 7cda524..fdc900d 100644
--- a/src/tabviews/subtabtable/index.jsx
+++ b/src/tabviews/subtabtable/index.jsx
@@ -136,17 +136,17 @@
         config.action = config.action.filter(item => permAction[item.uuid])
       }
 
-      let roleId = sessionStorage.getItem('role_id') || '' // 瑙掕壊ID
-      // 瀛楁鏉冮檺榛戝悕鍗�
-      config.search = config.search.filter(item => {
-        item.oriInitval = item.initval
-        if (!item.blacklist || item.blacklist.length === 0) return item
-        if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
-          item.Hide = 'true'
-        }
+      config.search = Utils.initSearchVal(config.search)
 
-        return item
+      let hasReqFields = false
+      config.search.forEach(field => {
+        if (field.required) {
+          hasReqFields = true
+        }
       })
+
+      // 瀛楁鏉冮檺榛戝悕鍗�
+      let roleId = sessionStorage.getItem('role_id') || '' // 瑙掕壊ID
 
       config.columns = config.columns.map(col => {
         if (!col.blacklist || col.blacklist.length === 0) return col
@@ -235,16 +235,6 @@
         _columns.push(config.gridBtn)
       }
 
-      let valid = true // 鎼滅储鏉′欢蹇呭~楠岃瘉
-      let hasReqFields = false
-      config.search.forEach(field => {
-        if (field.required !== 'true') return
-        hasReqFields = true
-        if (!field.initval) {
-          valid = false
-        }
-      })
-
       config.setting.tabType = 'subtab'
       // 鏁版嵁婧愪俊鎭澶勭悊
       config.setting.laypage = config.setting.laypage !== 'false'     // 鏄惁鍒嗛〉锛岃浆涓篵oolean 缁熶竴鏍煎紡
@@ -281,6 +271,26 @@
           config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
           config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
         }
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+
+        regs.forEach(cell => {
+          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
+          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
+        })
       }
 
       this.setState({
@@ -297,7 +307,7 @@
         search: Utils.initMainSearch(config.search), // 鎼滅储鏉′欢鍒濆鍖栵紙鍚湁鏃堕棿鏍煎紡锛岄渶瑕佽浆鍖栵級
         hasReqFields
       }, () => {
-        if (config.setting.onload !== 'false' && valid) { // 鍒濆鍖栧彲鍔犺浇
+        if (config.setting.onload !== 'false') { // 鍒濆鍖栧彲鍔犺浇
           this.loadData()
         }
       })
@@ -323,23 +333,17 @@
       searches = [...mainSearch, ...searches]
     }
 
-    let requireFields = []
-
     if (hasReqFields) {
-      requireFields = searches.filter(item => item.required && (!item.value || item.value.length === 0))
+      let requireFields = searches.filter(item => item.required && item.value === '')
+      if (requireFields.length > 0) {
+        this.setState({
+          loading: false
+        })
+        return
+      }
     }
 
-    if (requireFields.length > 0) {
-      let labels = requireFields.map(item => item.label)
-      labels = Array.from(new Set(labels))
-
-      notification.warning({
-        top: 92,
-        message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
-        duration: 3
-      })
-      return
-    } else if (window.GLOB.systemType === 'production' && setting.interType === 'custom' && !setting.proInterface) {
+    if (window.GLOB.systemType === 'production' && setting.interType === 'custom' && !setting.proInterface) {
       notification.warning({
         top: 92,
         message: '鏈缃寮忕郴缁熷湴鍧�!',
@@ -428,7 +432,7 @@
     })
 
     Api.directRequest(url, setting.method, param, setting.cross).then(res => {
-      if (typeof(res) !== 'object' || Array.isArray(res)) {
+      if (typeof(res) !== 'object') {
         let error = '鏈煡鐨勮繑鍥炵粨鏋滐紒'
 
         if (typeof(res) === 'string') {
@@ -443,6 +447,9 @@
 
         this.customCallbackRequest(_result)
       } else {
+        if (Array.isArray(res)) {
+          res = { data: res }
+        }
         res.mk_api_key = mkey
         this.customCallbackRequest(res)
       }
@@ -559,6 +566,11 @@
     this.getStatFieldsValue(searches)
 
     if (result.status) {
+      let start = 1
+      if (setting.laypage) {
+        start = pageSize * (pageIndex - 1) + 1
+      }
+
       this.setState({
         data: result.data.map((item, index) => {
           if (absFields.length) {
@@ -572,6 +584,7 @@
           item.key = index
           item.$$uuid = item[setting.primaryKey] || ''
           item.$$BID = BID || ''
+          item.$Index = start + index + ''
 
           return item
         }),
@@ -702,7 +715,7 @@
   /**
    * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁�
    */
-  getexceloutparam = (menuId, btnId) => {
+  queryModuleParam = (menuId, btnId) => {
     const { Tab, mainSearch, MenuID } = this.props
     const { arr_field, orderBy, search, setting} = this.state
 
@@ -713,7 +726,7 @@
       searches = [...mainSearch, ...search]
     }
 
-    MKEmitter.emit('execExcelout', MenuID, btnId, {
+    MKEmitter.emit('returnModuleParam', MenuID, btnId, {
       arr_field: arr_field,
       orderBy: orderBy || setting.order,
       search: searches,
@@ -753,7 +766,7 @@
   }
 
   componentDidMount () {
-    MKEmitter.addListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -764,7 +777,7 @@
     this.setState = () => {
       return
     }
-    MKEmitter.removeListener('getexceloutparam', this.getexceloutparam)
+    MKEmitter.removeListener('queryModuleParam', this.queryModuleParam)
     MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult)
   }
 
@@ -775,7 +788,7 @@
       <div className="subtabtable" id={'subtabtable' + this.props.MenuID}>
         {loadingview && <Spin />}
         {searchlist && searchlist.length ?
-          <SubSearch BID={this.props.BID} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
+          <SubSearch BID={this.props.BID} setting={setting} searchlist={searchlist} menuType={this.props.menuType} refreshdata={this.refreshbysearch}/> : null
         }
         {config ? <Row className="chart-view" gutter={16}>
           {/* 瑙嗗浘缁� */}
diff --git a/src/tabviews/tabmanage/index.jsx b/src/tabviews/tabmanage/index.jsx
index 7be8cb2..5d37c1d 100644
--- a/src/tabviews/tabmanage/index.jsx
+++ b/src/tabviews/tabmanage/index.jsx
@@ -49,9 +49,9 @@
             return {
               uuid: temp.MenuID,
               value: temp.MenuID,
-              MenuName: temp.MenuName,
+              MenuName: temp.MenuName || '',
               type: temp.Template,
-              MenuNo: temp.MenuNo,
+              MenuNo: temp.MenuNo || '',
               Remark: temp.Remark
             }
           })
@@ -504,7 +504,7 @@
 
     let _tabviews = []
     if (tabviews) {
-      _tabviews = tabviews.filter(tab => tab.MenuName.toLowerCase().indexOf(searchKey.toLowerCase()) >= 0)
+      _tabviews = tabviews.filter(tab => tab.MenuName.toLowerCase().indexOf(searchKey.toLowerCase()) >= 0 || tab.MenuNo.toLowerCase().indexOf(searchKey.toLowerCase()) >= 0)
     }
 
     return (
diff --git a/src/tabviews/treepage/index.jsx b/src/tabviews/treepage/index.jsx
index 5590efc..835e4a3 100644
--- a/src/tabviews/treepage/index.jsx
+++ b/src/tabviews/treepage/index.jsx
@@ -171,6 +171,26 @@
           config.setting.dataresource = config.setting.dataresource.replace(/@\$|\$@/ig, '')
           config.setting.customScript = config.setting.customScript.replace(/@\$|\$@/ig, '')
         }
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+
+        regs.forEach(cell => {
+          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
+          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
+        })
       }
 
       this.setState({
diff --git a/src/tabviews/verupmanage/config.jsx b/src/tabviews/verupmanage/config.jsx
index 37a7348..60948bb 100644
--- a/src/tabviews/verupmanage/config.jsx
+++ b/src/tabviews/verupmanage/config.jsx
@@ -13,7 +13,7 @@
     queryType: 'query',
   },
   search:[
-    {label: '浼犺緭鍙�', field:'VersionName', type: 'text', initval:'',match: 'like', uuid: '1581736007223d84ddmht4gdfb1850nh'}
+    {label: '浼犺緭鍙�', field: 'VersionName', type: 'text', initval:'', oriInitval: '', required: false, match: 'like', uuid: '1581736007223d84ddmht4gdfb1850nh'}
   ],
   action:[
     {label:'娣诲姞',OpenType:'pop',intertype:'outer',innerFunc:'',sysInterface:'true',outerFunc:'s_get_sVersiondetail_Up',interface:'http://cloud.mk9h.cn/webapi/dostars',callbackFunc:'s_sVersion_Local_add',position:'toolbar',Ot:'notRequired',execSuccess:'grid',execError:'never',icon:'',class:'green',uuid:'1583979660949vpssdb2p2lsqff9abkr'},
@@ -99,7 +99,7 @@
       onload:'true'
     },
     search:[
-      {label:'缁煎悎鏌ヨ',field:'Remark,KeyWords,TypeName',type:'text',initval:'',match:'like','ratio':6,uuid:'1583983588787acl55md59fu9kpb52db'}
+      {label:'缁煎悎鏌ヨ',field:'Remark,KeyWords,TypeName',type:'text',initval:'', oriInitval: '', required: false,match:'like','ratio':6,uuid:'1583983588787acl55md59fu9kpb52db'}
     ],
     action:[
       {label:'鎵ц',OpenType:'pop',intertype:'outer',innerFunc:'',sysInterface:'true',outerFunc:'s_get_sVersionDetail_Ltext',interface:'http://cloud.mk9h.cn/webapi/dostars',callbackFunc:'s_sDataDictb_TBBack',position:'toolbar',execSuccess:'grid',execError:'never',icon:'',class:'primary',Ot:'required',uuid:'1583983849299g1qfd28g3c9n9e0e57a',verify:null},
@@ -144,7 +144,7 @@
       onload:'true'
     },
     search:[
-      {label:'缁煎悎鏌ヨ',field:'Remark,KeyWords,TypeName',type:'text',initval:'',match:'like',uuid:'15839847143720ggaaukqtfhp3mirsuc'}
+      {label:'缁煎悎鏌ヨ',field:'Remark,KeyWords,TypeName',type:'text',initval:'', oriInitval: '', required: false,match:'like',uuid:'15839847143720ggaaukqtfhp3mirsuc'}
     ],
     action:[],
     columns:[
diff --git a/src/tabviews/zshare/actionList/asyncButtonComponent.jsx b/src/tabviews/zshare/actionList/asyncButtonComponent.jsx
index 1d48bf6..30d70ed 100644
--- a/src/tabviews/zshare/actionList/asyncButtonComponent.jsx
+++ b/src/tabviews/zshare/actionList/asyncButtonComponent.jsx
@@ -27,19 +27,11 @@
       const btn = this.props.btn || {}
       let style = {}
 
-      if (!C && btn.btnstyle) {
-        if (btn.btnstyle.marginRight) {
-          style.marginRight = btn.btnstyle.marginRight
-        }
-        if (btn.btnstyle.marginLeft) {
-          style.marginLeft = btn.btnstyle.marginLeft
-        }
-        if (btn.btnstyle.marginTop) {
-          style.marginTop = btn.btnstyle.marginTop
-        }
-        if (btn.btnstyle.marginBottom) {
-          style.marginBottom = btn.btnstyle.marginBottom
-        }
+      if (!C && btn.style) {
+        style.marginRight = btn.style.marginRight || ''
+        style.marginLeft = btn.style.marginLeft || ''
+        style.marginTop = btn.style.marginTop || ''
+        style.marginBottom = btn.style.marginBottom || ''
       }
 
       return C ?
diff --git a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
index 584b9e2..12ee0f4 100644
--- a/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -23,7 +23,23 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    disabled: false,
     loading: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -35,6 +51,24 @@
 
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -160,13 +194,14 @@
 
   render() {
     const { btn, show } = this.props
-    const { loading } = this.state
+    const { loading, disabled } = this.state
 
     if (show === 'actionList') {
       return (
         <Button
           icon={btn.icon}
           loading={loading}
+          disabled={disabled}
           className={'mk-btn mk-' + btn.class}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{btn.label}</Button>
@@ -177,7 +212,8 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle}
+          disabled={disabled}
+          style={btn.style}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/actionList/excelInbutton/index.jsx b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
index 0d53a35..2fc88ba 100644
--- a/src/tabviews/zshare/actionList/excelInbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -28,7 +28,23 @@
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
     loading: false,
+    disabled: false,
     primaryId: '',
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -40,6 +56,24 @@
 
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -74,7 +108,7 @@
 
     if ((triggerId && btn.uuid !== triggerId) || loading) return
 
-    if (Tab && Tab.supMenu && !BID) {
+    if (((Tab && Tab.supMenu) || setting.supModule) && !BID) {
       notification.warning({
         top: 92,
         message: '闇�瑕佷笂绾т富閿�硷紒',
@@ -103,7 +137,7 @@
     }
 
     let primaryId = '' // 瀵煎叆鏃惰Id
-    if (btn.Ot === 'requiredSgl') {
+    if (btn.Ot === 'requiredSgl' && setting.primaryKey) {
       primaryId = data[0][setting.primaryKey] || ''
     }
 
@@ -408,13 +442,14 @@
 
   render() {
     const { btn, show } = this.props
-    const { loading } = this.state
+    const { loading, disabled } = this.state
 
     if (show === 'actionList') {
       return <div style={{display: 'inline-block'}} onClick={(e) => e.stopPropagation()}>
         <Button
           icon={btn.icon}
           loading={loading}
+          disabled={disabled}
           className={'mk-btn mk-' + btn.class}
           onClick={() => {this.actionTrigger()}}
         >{btn.label}</Button>
@@ -426,7 +461,8 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle}
+          disabled={disabled}
+          style={btn.style}
           icon={show === 'text' ? '' : (show === 'icon' ? (btn.icon || 'upload') : (btn.icon || ''))}
           onClick={() => {this.actionTrigger()}}
         >{show === 'icon' ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
index 121fc6f..2bd9686 100644
--- a/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -42,7 +42,7 @@
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
     }
-    MKEmitter.addListener('execExcelout', this.triggerExcelout)
+    MKEmitter.addListener('returnModuleParam', this.triggerExcelout)
   }
 
   componentWillUnmount () {
@@ -50,7 +50,7 @@
       return
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
-    MKEmitter.removeListener('execExcelout', this.triggerExcelout)
+    MKEmitter.removeListener('returnModuleParam', this.triggerExcelout)
   }
 
   /**
@@ -78,7 +78,7 @@
 
     if ((triggerId && btn.uuid !== triggerId) || loading) return
 
-    if (Tab && Tab.supMenu && !BID) {
+    if (((Tab && Tab.supMenu) || setting.supModule) && !BID) {
       notification.warning({
         top: 92,
         message: '闇�瑕佷笂绾т富閿�硷紒',
@@ -110,7 +110,7 @@
       return
     }
 
-    MKEmitter.emit('getexceloutparam', btn.$menuId, btn.uuid)
+    MKEmitter.emit('queryModuleParam', btn.$menuId, btn.uuid)
     if (window.GLOB.systemType === 'production') {
       MKEmitter.emit('queryTrigger', {menuId: btn.uuid, name: '瀵煎嚭Excel'})
     }
@@ -130,9 +130,7 @@
     if (btn.search === 'true' && viewParam.search && viewParam.search.length > 0) {
       let valid = false
       viewParam.search.forEach(item => {
-        if (Array.isArray(item.value) && item.value.length > 0) {
-          valid = true
-        } else if (item.value || item.value === 0) {
+        if (item.value || item.value === 0) {
           valid = true
         }
       })
@@ -430,31 +428,77 @@
     const { btn } = this.props
     
     try {
-      let _header = []
-      let _topRow = {}
-      let colwidth = []
-      let abses = []
+      let imgCol = btn.verify.columns.filter(col => col.type === 'image')[0]
 
-      btn.verify.columns.forEach(col => {
-        if (_topRow[col.Column]) return
+      if (imgCol) {
+        const column = btn.verify.columns.map(item => {
+          let col = {
+            title: item.Text, 
+            key: item.Column,
+            type: 'text',
+            width: (item.Width || 20) * 10
+          }
+          if (item.type === 'image') {
+            col.type = 'image'
+            col.height = col.width
+          }
+          return col
+        })
 
-        _header.push(col.Column)
-        _topRow[col.Column] = col.Text
+        let table = []
 
-        if (col.abs === 'true') {
-          abses.push(col.Column)
+        data && data.forEach((item, index) => {
+          let _row = {}
+  
+          item.$Index = index + 1 + ''
+  
+          btn.verify.columns.forEach((col, i) => {
+            if (item[col.Column] && col.abs === 'true') {
+              _row[col.Column] = Math.abs(item[col.Column])
+            } else {
+              _row[col.Column] = item[col.Column]
+            }
+          })
+  
+          table.push(_row)
+        })
+
+        this.table2excel(column, table, this.state.excelName.replace(/\.xlsx/ig, '.xls'))
+
+        if (btn.verify && btn.verify.enable === 'true' && btn.verify.script) {
+          this.execCustomScript()
+        } else {
+          this.execSuccess({ErrCode: 'S', ErrMesg: '瀵煎嚭鎴愬姛锛�'})
         }
 
-        colwidth.push({width: col.Width || 20})
-      })
-
-      let table = []
-
-      table.push(_topRow)
-
-      if (data && abses.length > 0) {
-        data.forEach(item => {
+      } else {
+        let _header = []
+        let _topRow = {}
+        let colwidth = []
+        let abses = []
+  
+        btn.verify.columns.forEach(col => {
+          if (_topRow[col.Column]) return
+  
+          _header.push(col.Column)
+          _topRow[col.Column] = col.Text
+  
+          if (col.abs === 'true') {
+            abses.push(col.Column)
+          }
+  
+          colwidth.push({width: col.Width || 20})
+        })
+  
+        let table = []
+  
+        table.push(_topRow)
+  
+        data && data.forEach((item, index) => {
           let _row = {}
+  
+          item.$Index = index + 1 + ''
+  
           _header.forEach(field => {
             if (item[field] && abses.includes(field)) {
               _row[field] = Math.abs(item[field])
@@ -465,35 +509,67 @@
   
           table.push(_row)
         })
-      } else if (data) {
-        data.forEach(item => {
-          let _row = {}
-          _header.forEach(field => {
-            _row[field] = item[field]
-          })
   
-          table.push(_row)
-        })
-      }
-
-      const ws = XLSX.utils.json_to_sheet(table, {header: _header, skipHeader: true})
-
-      ws['!cols'] = colwidth
-
-      const wb = XLSX.utils.book_new()
-      XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
-
-      XLSX.writeFile(wb, this.state.excelName)
-
-      if (btn.verify && btn.verify.enable === 'true' && btn.verify.script) {
-        this.execCustomScript()
-      } else {
-        this.execSuccess({ErrCode: 'S', ErrMesg: '瀵煎嚭鎴愬姛锛�'})
+        const ws = XLSX.utils.json_to_sheet(table, {header: _header, skipHeader: true})
+  
+        ws['!cols'] = colwidth
+  
+        const wb = XLSX.utils.book_new()
+        XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
+  
+        XLSX.writeFile(wb, this.state.excelName)
+  
+        if (btn.verify && btn.verify.enable === 'true' && btn.verify.script) {
+          this.execCustomScript()
+        } else {
+          this.execSuccess({ErrCode: 'S', ErrMesg: '瀵煎嚭鎴愬姛锛�'})
+        }
       }
     } catch {
       this.execError({ErrCode: 'N', message: 'Excel鐢熸垚澶辫触锛�'})
     }
   }
+
+  table2excel = (column, data, excelName) => {
+    let thead = column.reduce((result, item) => {
+      return result + `<th>${item.title}</th>`
+    }, '')
+  
+    thead = `<thead><tr>${thead}</tr></thead>`
+  
+    let tbody = data.reduce((result, row) => {
+      const temp = column.reduce((tds, col) => {
+        let cell = '<td></td>'
+        if (col.type !== 'image' || !row[col.key]) {
+          cell = `<td style="width: ${col.width}px;">${row[col.key]}</td>`
+        } else if (col.type === 'image') {
+          cell = `<td style="width: ${col.width}px;height: ${col.height}px;"><img src="${row[col.key]}" width="${col.width * 0.75}"></td>`
+        }
+        return tds + cell
+      }, '')
+      return result + `<tr>${temp}</tr>`
+    }, '')
+  
+    tbody = `<tbody>${tbody}</tbody>`
+  
+    const table = thead + tbody
+
+    let html = "<html xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:x='urn:schemas-microsoft-com:office:excel' xmlns='http://www.w3.org/TR/REC-html40'>"
+    html += '<head><meta http-equiv="content-type" content="application/vnd.ms-excel; charset=UTF-8">'
+    html += '<xml><x:ExcelWorkbook><x:ExcelWorksheets><x:ExcelWorksheet><x:Name>Sheet1</x:Name><x:WorksheetOptions><x:Print><x:ValidPrinterInfo/></x:Print></x:WorksheetOptions></x:ExcelWorksheet></x:ExcelWorksheets></x:ExcelWorkbook></xml></head>'
+    html += `<body><table>${table}</table></body>`
+    html += '</html>'
+
+    let url = 'data:application/vnd.ms-excel;charset=utf-8,' + encodeURIComponent(html)
+    // let url = 'data:application/vnd.ms-excel;base64,' + window.btoa(unescape(encodeURIComponent(html)))
+    let link = document.createElement('a')
+    link.href = url
+    link.download = excelName
+    document.body.appendChild(link)
+    link.click()
+    document.body.removeChild(link)
+  }
+  
 
   /**
    * @description 鎵ц鑷畾涔夎剼鏈�
@@ -606,20 +682,21 @@
     if (this.props.BID) {
       param.BID = this.props.BID
     }
+
+    let userName = sessionStorage.getItem('User_Name') || ''
+    let fullName = sessionStorage.getItem('Full_Name') || ''
+    let city = sessionStorage.getItem('city') || ''
+
+    if (sessionStorage.getItem('isEditState') === 'true') {
+      userName = sessionStorage.getItem('CloudUserName') || ''
+      fullName = sessionStorage.getItem('CloudFullName') || ''
+    }
     
     let _dataresource = setting.dataresource
 
     let regoptions = null
     if (setting.queryType === 'statistics' || param.custom_script) {
       let allSearch = Utils.getAllSearchOptions(search)
-      let userName = sessionStorage.getItem('User_Name') || ''
-      let fullName = sessionStorage.getItem('Full_Name') || ''
-      let city = sessionStorage.getItem('city') || ''
-
-      if (sessionStorage.getItem('isEditState') === 'true') {
-        userName = sessionStorage.getItem('CloudUserName') || ''
-        fullName = sessionStorage.getItem('CloudFullName') || ''
-      }
 
       regoptions = allSearch.map(item => {
         return {
@@ -665,7 +742,7 @@
     }
 
     if (param.custom_script) {
-      param.custom_script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000) select @ErrorCode='',@retmsg =''
+      param.custom_script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50) select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @login_city='${city}'
         ${param.custom_script}
       `
       regoptions.forEach(item => {
@@ -798,7 +875,7 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle}
+          style={btn.style}
           icon={show === 'text' ? '' : (show === 'icon' ? (btn.icon || 'download') : (btn.icon || ''))}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{show === 'icon' ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/actionList/newpagebutton/index.jsx b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
index dcf07e8..2ff034c 100644
--- a/src/tabviews/zshare/actionList/newpagebutton/index.jsx
+++ b/src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -21,7 +21,23 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    disabled: false,
     visible: false
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -33,6 +49,24 @@
 
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -69,14 +103,6 @@
         duration: 5
       })
       return
-    } else if (btn.Ot !== 'notRequired' && !setting.primaryKey) {
-      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾槸鍚﹁缃富閿�
-      notification.warning({
-        top: 92,
-        message: '鏈缃富閿紒',
-        duration: 5
-      })
-      return
     } else if (!btn.pageTemplate) {
       notification.warning({
         top: 92,
@@ -91,7 +117,7 @@
     let MenuNo = ''
     let Remark = ''
     if (btn.Ot === 'requiredSgl' && data[0]) {
-      Id = data[0][setting.primaryKey] || ''
+      Id = setting.primaryKey ? (data[0][setting.primaryKey] || '') : ''
       name = data[0].PrintTempName || ''
       MenuNo = data[0].PrintTempNO || ''
       Remark = data[0].Remark || ''
@@ -103,7 +129,7 @@
       _name = '鍗曟嵁鎵撳嵃'
       if (btn.Ot === 'required' && data && data.length > 0) {
         data.forEach((item, i) => {
-          let _id = item[setting.primaryKey] || ''
+          let _id = setting.primaryKey ? (item[setting.primaryKey] || '') : ''
           let url = '#/billprint/' + window.btoa(window.encodeURIComponent(JSON.stringify({ id: _id, tempId: btn.printTemp, dataM: sessionStorage.getItem('dataM') })))
           window.open(url)
         })
@@ -164,12 +190,14 @@
 
   render() {
     const { btn, show } = this.props
+    const { disabled } = this.state
 
     if (show === 'actionList') {
       return (
         <Button
           className={'mk-btn mk-' + btn.class}
           icon={btn.icon}
+          disabled={disabled}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{btn.label}</Button>
       )
@@ -178,7 +206,8 @@
         <Button
           type="link"
           title={show === 'icon' ? btn.label : ''}
-          style={btn.btnstyle}
+          style={btn.style}
+          disabled={disabled}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/actionList/normalbutton/index.jsx b/src/tabviews/zshare/actionList/normalbutton/index.jsx
index 076f844..952fd74 100644
--- a/src/tabviews/zshare/actionList/normalbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -3,7 +3,7 @@
 import moment from 'moment'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { Button, Modal, notification, message } from 'antd'
+import { Button, Modal, notification, message, Drawer } from 'antd'
 
 import Api from '@/api'
 import Utils, { getSysDefaultSql } from '@/utils/utils.js'
@@ -42,7 +42,25 @@
     btnconfig: null,
     loading: false,
     loadingNumber: '',
+    disabled: false,
     checkParam: null
+  }
+
+  moduleParams = null
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -52,10 +70,28 @@
   componentDidMount () {
     const { position } = this.props
 
-    if (position === 'toolbar') {
-      MKEmitter.addListener('triggerBtnId', this.actionTrigger)
-    } else if (position === 'form') {
+    MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    if (position === 'form') {
       MKEmitter.addListener('triggerFormSubmit', this.actionSubmit)
+    }
+    MKEmitter.addListener('returnModuleParam', this.resetModuleParam)
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -65,6 +101,7 @@
     }
     MKEmitter.removeListener('triggerBtnId', this.actionTrigger)
     MKEmitter.removeListener('triggerFormSubmit', this.actionSubmit)
+    MKEmitter.removeListener('returnModuleParam', this.resetModuleParam)
   }
 
   actionSubmit = (res) => {
@@ -77,6 +114,14 @@
     })
 
     this.execSubmit(this.state.tabledata, () => {}, res.form)
+  }
+
+  resetModuleParam = (menuId, btnId, param) => {
+    const { btn } = this.props
+    
+    if (btn.$menuId !== menuId || btn.uuid !== btnId || !param) return
+
+    this.moduleParams = param
   }
 
   /**
@@ -99,17 +144,22 @@
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
    */
   actionTrigger = (triggerId, record) => {
-    const { setting, Tab, BID, btn, selectedData } = this.props
+    const { Tab, BID, btn, selectedData, setting } = this.props
     const { loading } = this.state
 
     if ((triggerId && btn.uuid !== triggerId) || loading) return
 
-    if (Tab && Tab.supMenu && !BID) {
+    if (((Tab && Tab.supMenu) || setting.supModule) && !BID) {
       notification.warning({
         top: 92,
         message: '闇�瑕佷笂绾т富閿�硷紒',
         duration: 5
       })
+      return
+    }
+
+    if (btn.$syncModule && !triggerId) {
+      MKEmitter.emit('getSyncData', btn.$syncModule, btn.uuid)
       return
     }
 
@@ -129,14 +179,6 @@
       notification.warning({
         top: 92,
         message: this.state.dict['main.action.confirm.selectSingleLine'],
-        duration: 5
-      })
-      return
-    } else if (btn.OpenType !== 'formSubmit' && !setting.primaryKey) {
-      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾槸鍚﹁缃富閿�
-      notification.warning({
-        top: 92,
-        message: '鏈缃富閿紒',
         duration: 5
       })
       return
@@ -258,7 +300,7 @@
       
       let primaryId = ''
 
-      if (btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce') {
+      if ((btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce') && setting.primaryKey) {
         let ids = data.map(d => { return d[setting.primaryKey] || ''})
         ids = ids.filter(Boolean)
         primaryId = ids.join(',')
@@ -268,11 +310,11 @@
         param.ID = primaryId
 
         if (retmsg) {
-          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
           param.LText = sql
           param.$callbacksql = callbacksql
         } else {
-          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, this.props.Tab) // 鏁版嵁婧�
+          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
         }
 
         if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -310,11 +352,11 @@
           param.ID = primaryId || Utils.getguid()
 
           if (retmsg) {
-            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
             param.LText = sql
             param.$callbacksql = callbacksql
           } else {
-            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab) // 鏁版嵁婧�
+            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
           }
           
           if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -342,11 +384,11 @@
           param.ID = primaryId
 
           if (retmsg) {
-            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
             param.LText = sql
             param.$callbacksql = callbacksql
           } else {
-            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab) // 鏁版嵁婧�
+            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
           }
           
           if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -404,11 +446,11 @@
           param.ID = primaryId
 
           if (retmsg) {
-            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
             param.LText = sql
             param.$callbacksql = callbacksql
           } else {
-            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, this.props.Tab) // 鏁版嵁婧�
+            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions, Utils.getAllSearchOptions) // 鏁版嵁婧�
           }
           
           if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -437,11 +479,11 @@
             param.ID = Utils.getguid()
 
             if (retmsg) {
-              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
               param.LText = sql
               param.$callbacksql = callbacksql
             } else {
-              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab) // 鏁版嵁婧�
+              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
             }
             
             if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -460,11 +502,11 @@
             param.ID = primaryId
 
             if (retmsg) {
-              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, retmsg) // 鏁版嵁婧�
+              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
               param.LText = sql
               param.$callbacksql = callbacksql
             } else {
-              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab) // 鏁版嵁婧�
+              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, this.props.Tab, false, this.moduleParams, Utils.getAllSearchOptions) // 鏁版嵁婧�
             }
             
             if (sessionStorage.getItem('dataM') === 'true') { // 鏁版嵁鏉冮檺
@@ -512,13 +554,15 @@
       
       let primaryId = ''
 
-      if (btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce') {
+      if ((btn.Ot === 'requiredSgl' || btn.Ot === 'requiredOnce') && setting.primaryKey) {
         let ids = data.map(d => { return d[setting.primaryKey] || ''})
         ids = ids.filter(Boolean)
         primaryId = ids.join(',')
       }
 
-      param[setting.primaryKey] = primaryId // 璁剧疆涓婚敭鍙傛暟
+      if (setting.primaryKey) {
+        param[setting.primaryKey] = primaryId // 璁剧疆涓婚敭鍙傛暟
+      }
 
       if (btn.OpenType === 'pop' || btn.OpenType === 'formSubmit') { // 琛ㄥ崟
         formdata.forEach(_data => {
@@ -559,7 +603,9 @@
             param[_data.key] = _data.value
           })
         }
-        param[setting.primaryKey] = primaryId
+        if (setting.primaryKey) {
+          param[setting.primaryKey] = primaryId
+        }
 
         if (this.props.menuType === 'HS' && param.func === 's_sDataDictb_TBBack' && param.LTextOut) { // 鍑芥暟 s_sDataDictb_TBBack 浜戠楠岃瘉
           param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -578,6 +624,30 @@
    * @description 鎸夐挳鎻愪氦鎵ц
    */
   execSubmit = (data, _resolve, formdata) => {
+    const { setting, btn } = this.props
+    this.moduleParams = null
+
+    if (
+      (btn.intertype === 'system' || (btn.intertype === 'custom' && btn.procMode === 'system')) && 
+      btn.sqlType !== 'insert' && btn.Ot !== 'notRequired' && btn.verify && btn.verify.invalid === 'true' &&
+      setting.dataresource
+    ) {
+      MKEmitter.emit('queryModuleParam', btn.$menuId, btn.uuid)
+      setTimeout(() => {
+        if (this.moduleParams) {
+          this.execRealSubmit(data, _resolve, formdata)
+        } else {
+          setTimeout(() => {
+            this.execRealSubmit(data, _resolve, formdata)
+          }, 100)
+        }
+      }, 50)
+    } else {
+      this.execRealSubmit(data, _resolve, formdata)
+    }
+  }
+
+  execRealSubmit = (data, _resolve, formdata) => {
     const { setting, btn } = this.props
     if (btn.intertype === 'system' || btn.intertype === 'inner') { // 绯荤粺鎺ュ彛
       let params = []
@@ -800,7 +870,7 @@
     })
 
     Api.directRequest(url, btn.method, param, btn.cross).then(res => {
-      if (typeof(res) !== 'object' || Array.isArray(res)) {
+      if (typeof(res) !== 'object') {
         let error = '鏈煡鐨勮繑鍥炵粨鏋滐紒'
 
         if (typeof(res) === 'string') {
@@ -815,6 +885,9 @@
 
         this.customCallbackRequest(params, result, record, _resolve)
       } else {
+        if (Array.isArray(res)) {
+          res = { data: res }
+        }
         res.mk_api_key = mkey
         this.customCallbackRequest(params, res, record, _resolve)
       }
@@ -872,6 +945,9 @@
             subObjs.push(val)
           }
         } else {
+          if (typeof(val) === 'string') {
+            val = val.replace(/'/ig, '"')
+          }
           keys.push(key)
           vals.push(`'${val}'`)
         }
@@ -1252,6 +1328,7 @@
       let _param = {
         templatecode: verify.noteCode, // 妯℃澘缂栫爜
         TypeCharOne: verify.noteTemp,  // N涓嶅悓鍐呭锛孻鐩稿悓鍐呭
+        ID: verify.noteId || ''        // 妯℃澘Id锛屾殏鏃舵湭浣跨敤
       }
 
       _param.submitdate = res.submitdate
@@ -1316,10 +1393,12 @@
       _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
       _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
 
-      _param.rduri = 'http://sso.mk9h.cn/webapi/dostar'
-      _param.appkey = window.GLOB.appkey || ''
+      _param.rduri = 'http://sso.mk9h.cn/webapi/dostars'
 
-      Api.dostarInterface(_param).then(result => {
+      _param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+      _param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+
+      Api.getLocalConfig(_param).then(result => {
         if (!result.status) {
           notification.warning({
             top: 92,
@@ -1578,13 +1657,19 @@
         _initval = ''
       }
 
+      let _type = item.type
+
+      if (['date', 'datemonth', 'datetime'].includes(_type) && item.declareType === 'nvarchar(50)') {
+        _type = 'text'
+      }
+
       result.push({
         key: item.field,
         readonly: item.readonly === 'true',
         readin: _readin,
         fieldlen: _fieldlen,
         writein: item.writein !== 'false',
-        type: item.type,
+        type: _type,
         value: _initval
       })
     })
@@ -1613,51 +1698,87 @@
 
     let title = btnconfig.setting.title
     let width = btnconfig.setting.width + 'vw'
-    let clickouter = false
-    let container = document.body
+    let clickouter = btnconfig.setting.clickouter === 'close'
 
-    if (
-      (setting.tabType === 'main' && btnconfig.setting.container === 'tab' && this.props.ContainerId) ||
-      (btnconfig.setting.container === 'tab' && btn.ContainerId)
-    ) {
-      width = btnconfig.setting.width + '%'
-      container = () => document.getElementById(this.props.ContainerId || btn.ContainerId)
+    if (btnconfig.setting.display === 'drawer') {
+      let height = '100vh'
+      if (btnconfig.setting.placement === 'top' || btnconfig.setting.placement === 'bottom') {
+        width = '100vw'
+        height = btnconfig.setting.width + 'vh'
+      }
+      return (
+        <Drawer
+          title={title}
+          width={width}
+          height={height}
+          maskClosable={clickouter}
+          onClose={this.handleCancel}
+          visible={visible}
+          placement={btnconfig.setting.placement || 'right'}
+          bodyStyle={{ paddingBottom: 80 }}
+          destroyOnClose
+        >
+          <MutilForm
+            BID={BID}
+            dict={this.state.dict}
+            menuType={this.props.menuType}
+            action={btnconfig}
+            inputSubmit={this.handleOk}
+            data={this.state.tabledata[0]}
+            BData={this.props.BData}
+            wrappedComponentRef={(inst) => this.formRef = inst}
+          />
+          <div style={{ position: 'absolute', zIndex: 1, right: 0, bottom: 0, width: '100%', borderTop: '1px solid #e9e9e9', padding: '10px 16px', background: '#fff', textAlign: 'right'}}>
+            <Button onClick={this.handleCancel} style={{ marginRight: 8 }}>
+              鍙栨秷
+            </Button>
+            <Button onClick={this.handleOk} loading={this.state.confirmLoading} type="primary">
+              纭畾
+            </Button>
+          </div>
+        </Drawer>
+      )
+    } else {
+      let container = document.body
+
+      if (
+        (setting.tabType === 'main' && btnconfig.setting.container === 'tab' && this.props.ContainerId) ||
+        (btnconfig.setting.container === 'tab' && btn.ContainerId)
+      ) {
+        width = btnconfig.setting.width + '%'
+        container = () => document.getElementById(this.props.ContainerId || btn.ContainerId)
+      }
+      return (
+        <Modal
+          title={title}
+          maskClosable={clickouter}
+          getContainer={container}
+          wrapClassName='action-modal'
+          visible={visible}
+          width={width}
+          onOk={this.handleOk}
+          confirmLoading={this.state.confirmLoading}
+          onCancel={this.handleCancel}
+          destroyOnClose
+        >
+          <MutilForm
+            BID={BID}
+            dict={this.state.dict}
+            menuType={this.props.menuType}
+            action={btnconfig}
+            inputSubmit={this.handleOk}
+            data={this.state.tabledata[0]}
+            BData={this.props.BData}
+            wrappedComponentRef={(inst) => this.formRef = inst}
+          />
+        </Modal>
+      )
     }
-
-    if (btnconfig.setting.clickouter === 'close') {
-      clickouter = true
-    }
-
-    return (
-      <Modal
-        title={title}
-        maskClosable={clickouter}
-        getContainer={container}
-        wrapClassName='action-modal'
-        visible={visible}
-        width={width}
-        onOk={this.handleOk}
-        confirmLoading={this.state.confirmLoading}
-        onCancel={this.handleCancel}
-        destroyOnClose
-      >
-        <MutilForm
-          BID={BID}
-          dict={this.state.dict}
-          menuType={this.props.menuType}
-          action={btnconfig}
-          inputSubmit={this.handleOk}
-          data={this.state.tabledata[0]}
-          BData={this.props.BData}
-          wrappedComponentRef={(inst) => this.formRef = inst}
-        />
-      </Modal>
-    )
   }
 
   render() {
     const { btn, show, style } = this.props
-    const { loadingNumber, loading, visible } = this.state
+    const { loadingNumber, loading, disabled } = this.state
 
     if (show === 'actionList') {
       return <div style={{display: 'inline-block'}} onClick={(e) => e.stopPropagation()}>
@@ -1665,10 +1786,11 @@
           style={style}
           icon={btn.icon}
           loading={loading}
+          disabled={disabled}
           className={'mk-btn mk-' + btn.class}
           onClick={() => {this.actionTrigger()}}
         >{(loadingNumber ? `(${loadingNumber})` : '') + btn.label}</Button>
-        {visible ? this.getModels() : null}
+        {this.getModels()}
       </div>
     } else if (show && show.indexOf('plus') > -1) {
       return <div className="mk-btn-wrap">
@@ -1679,7 +1801,7 @@
           style={{fontSize: show.substring(4) + 'px'}}
           onClick={() => {this.actionTrigger()}}
         ></Button>
-        {visible ? this.getModels() : null}
+        {this.getModels()}
       </div>
     } else { // icon銆乼ext銆� all 鍗$墖
       return <div style={{display: 'inline-block'}} onClick={(e) => e.stopPropagation()}>
@@ -1687,11 +1809,12 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle || style}
+          disabled={disabled}
+          style={btn.style || style}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={() => {this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button>
-        {visible ? this.getModels() : null}
+        {this.getModels()}
       </div>
     }
   }
diff --git a/src/tabviews/zshare/actionList/popupbutton/index.jsx b/src/tabviews/zshare/actionList/popupbutton/index.jsx
index 539e70c..c519a94 100644
--- a/src/tabviews/zshare/actionList/popupbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -31,7 +31,23 @@
     visible: false,
     popData: null,
     primaryId: '',
+    disabled: false,
     loading: false,
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -46,6 +62,24 @@
     }
     MKEmitter.addListener('openNewTab', this.openNewTab)
     MKEmitter.addListener('refreshPopButton', this.refreshPopButton)
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
+    }
   }
 
   componentWillUnmount () {
@@ -75,7 +109,7 @@
 
     if (btn.uuid !== tabId) return
 
-    if (btn.$type === 'CustomPage') {
+    if (btn.$view === 'CustomPage') {
       if (btn.popClose !== 'never') {
         MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.popClose, btn)
       }
@@ -94,7 +128,7 @@
 
     if ((triggerId && btn.uuid !== triggerId) || loading) return
 
-    if (Tab && Tab.supMenu && !BID) {
+    if (((Tab && Tab.supMenu) || setting.supModule) && !BID) {
       notification.warning({
         top: 92,
         message: '闇�瑕佷笂绾т富閿�硷紒',
@@ -113,14 +147,6 @@
         duration: 5
       })
       return
-    } else if (!setting.primaryKey) {
-      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾槸鍚﹁缃富閿�
-      notification.warning({
-        top: 92,
-        message: '鏈缃富閿紒',
-        duration: 5
-      })
-      return
     } else if (setting.tabType === 'subtab') {
       notification.warning({
         top: 92,
@@ -133,7 +159,7 @@
     let _data = null
     let primaryId = ''
 
-    if (btn.Ot === 'requiredSgl') {
+    if (btn.Ot === 'requiredSgl' && setting.primaryKey) {
       _data = data[0]
       primaryId = _data[setting.primaryKey] || ''
     }
@@ -168,13 +194,14 @@
 
   render() {
     const { btn, show } = this.props
-    const { loading, popData, primaryId } = this.state
+    const { loading, popData, primaryId, disabled } = this.state
 
     return (
       <div style={{display: 'inline-block'}} onClick={(e) => e.stopPropagation()}>
         {show === 'actionList' ? <Button
           className={'mk-btn mk-' + btn.class}
           icon={btn.icon}
+          disabled={disabled}
           onClick={() => {this.actionTrigger()}}
           loading={loading}
         >{btn.label}</Button> : null}
@@ -182,12 +209,13 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle}
+          disabled={disabled}
+          style={btn.style}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={() => {this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button> : null}
         <Modal
-          className={'popview-modal ' + (btn.$type === 'CustomPage' ? 'custom-popview' : '')}
+          className={'popview-modal ' + (btn.$view === 'CustomPage' ? 'custom-popview' : '')}
           title={btn.label}
           width={'85vw'}
           maskClosable={false}
@@ -198,14 +226,14 @@
           ]}
           destroyOnClose
         >
-          {btn.$type !== 'CustomPage' ? <SubTabTable
+          {btn.$view !== 'CustomPage' ? <SubTabTable
             Tab={btn}
             MenuID={btn.linkTab}
             SupMenuID={this.props.MenuID}
             BID={popData ? primaryId : this.props.BID}
             BData={popData || this.props.BData}
           /> : null}
-          {btn.$type === 'CustomPage' ? <CustomPage Tab={btn} MenuID={btn.uuid} param={{BID: (popData ? primaryId : this.props.BID), data: (popData || this.props.BData)}} /> : null}
+          {btn.$view === 'CustomPage' ? <CustomPage Tab={btn} MenuID={btn.uuid} param={{$BID: (popData ? primaryId : this.props.BID), ...(popData || this.props.BData || {})}} /> : null}
         </Modal>
       </div>
     )
diff --git a/src/tabviews/zshare/actionList/printbutton/index.jsx b/src/tabviews/zshare/actionList/printbutton/index.jsx
index 323d5ab..fb45054 100644
--- a/src/tabviews/zshare/actionList/printbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -40,7 +40,23 @@
     tabledata: null,
     btnconfig: null,
     loading: false,
+    disabled: false,
     loadingNumber: ''
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -52,6 +68,24 @@
 
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -81,12 +115,12 @@
    * @description 瑙﹀彂鎸夐挳鎿嶄綔
    */
   actionTrigger = (triggerId, record) => {
-    const { setting, Tab, BID, btn, selectedData } = this.props
+    const { Tab, BID, btn, selectedData, setting } = this.props
     const { loading } = this.state
 
     if ((triggerId && btn.uuid !== triggerId) || loading) return
 
-    if (Tab && Tab.supMenu && !BID) {
+    if (((Tab && Tab.supMenu) || setting.supModule) && !BID) {
       notification.warning({
         top: 92,
         message: '闇�瑕佷笂绾т富閿�硷紒',
@@ -111,14 +145,6 @@
       notification.warning({
         top: 92,
         message: this.state.dict['main.action.confirm.selectSingleLine'],
-        duration: 5
-      })
-      return
-    } else if (!setting.primaryKey) {
-      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾槸鍚﹁缃富閿�
-      notification.warning({
-        top: 92,
-        message: '鏈缃富閿紒',
         duration: 5
       })
       return
@@ -276,6 +302,7 @@
 
       let errorMsg = ''
       let _temps = {}
+      let images = []
 
       result.forEach(res => {
         if (res.status && !errorMsg) {
@@ -289,6 +316,7 @@
               status: false
             }
           } else {
+            images = [...images, ..._temp.imgs]
             _temps[res.tempId] = _temp
           }
         } else if (!errorMsg) {
@@ -297,7 +325,38 @@
       })
 
       if (!errorMsg) {
-        this.execPrint(printlist, _temps, formdata)
+        if (images.length > 0) {
+          let errorUrls = []
+          images.forEach(url => {
+            let img = new Image()
+            img.onerror = () => {
+              errorUrls.push(url)
+            }
+            img.src = url
+          })
+
+          setTimeout(() => {
+            if (errorUrls.length > 0) {
+              notification.warning({
+                top: 92,
+                message: '妯℃澘涓浘鐗� ' + errorUrls.join('锛�') + ' 宸插け鏁堬紒',
+                duration: 5
+              })
+              Object.keys(_temps).forEach(key => {
+                _temps[key].config.ReportHeader.Control = _temps[key].config.ReportHeader.Control.map(item => {
+                  if (item.Type === 'image' && errorUrls.includes(item.Value)) {
+                    item.Value = ''
+                  }
+                  return item
+                })
+              })
+            }
+
+            this.execPrint(printlist, _temps, formdata)
+          }, 500)
+        } else {
+          this.execPrint(printlist, _temps, formdata)
+        }
       } else {
         this.execError(errorMsg)
       }
@@ -358,17 +417,21 @@
         let _param = { ...param, ...formdata }
         params.push(_param)
       } else if (btn.Ot === 'requiredSgl') {
-        param[setting.primaryKey] = data[0][setting.primaryKey]
+        if (setting.primaryKey) {
+          param[setting.primaryKey] = data[0][setting.primaryKey]
+        }
 
         let _param = { ...param, ...formdata }
 
         params.push(_param)
       } else if (btn.Ot === 'requiredOnce') {
-        let ids = data.map(d => { return d[setting.primaryKey]})
-        ids = ids.filter(Boolean)
-        ids = ids.join(',')
-
-        param[setting.primaryKey] = ids
+        if (setting.primaryKey) {
+          let ids = data.map(d => { return d[setting.primaryKey]})
+          ids = ids.filter(Boolean)
+          ids = ids.join(',')
+  
+          param[setting.primaryKey] = ids
+        }
 
         let _param = { ...param, ...formdata }
 
@@ -376,7 +439,10 @@
       } else if (btn.Ot === 'required') {
         params = data.map((cell, index) => {
           let _param = { ...param }
-          _param[setting.primaryKey] = cell[setting.primaryKey]
+          
+          if (setting.primaryKey) {
+            _param[setting.primaryKey] = cell[setting.primaryKey]
+          }
 
           formlist.forEach(_data => {
             if (index !== 0 && _data.readin && cell.hasOwnProperty(_data.key)) {
@@ -568,6 +634,7 @@
     let _configparam = ''  // 鎵撳嵃閰嶇疆淇℃伅
     let fields = []        // 妯℃澘涓墍闇�瀛楁
     let nonEFields = []    // 闈炵┖瀛楁
+    let imgs = []
 
     if (!res.ConfigParam) {
       error = '鏈幏鍙栧埌鎵撳嵃妯℃澘淇℃伅锛�'
@@ -581,7 +648,6 @@
       if (!configParam) {
         error = '鎵撳嵃妯℃澘瑙f瀽閿欒锛�'
       } else {
-        
         let control = configParam.elements.map(element => {
           let _field = element.field
 
@@ -628,6 +694,12 @@
             item.ImageWidth = element.imgWidth
             item.ImageHeight = element.imgHeight
             item.Trimming = ''
+            if (element.productValue && window.GLOB.systemType === 'production') {
+              item.Value = element.productValue
+              imgs.push(item.Value)
+            } else if (item.Value) {
+              imgs.push(item.Value)
+            }
           } else if (item.Type === 'text') {
             item.FontFamily = element.fontFamily
             item.FontSize = element.fontSize
@@ -688,7 +760,8 @@
       error: error,
       config: _configparam,
       fields: fields,
-      nonEFields: nonEFields
+      nonEFields: nonEFields,
+      imgs: imgs
     }
   }
 
@@ -1251,13 +1324,14 @@
 
   render() {
     const { btn, show } = this.props
-    const { loadingNumber, loading } = this.state
+    const { loadingNumber, loading, disabled } = this.state
 
     if (show === 'actionList') {
       return <div style={{display: 'inline-block'}} onClick={(e) => e.stopPropagation()}>
         <Button
           icon={btn.icon}
           loading={loading}
+          disabled={disabled}
           className={'mk-btn mk-' + btn.class}
           onClick={() => {this.actionTrigger()}}
         >{loadingNumber ? `(${loadingNumber})` : '' + btn.label}</Button>
@@ -1269,7 +1343,8 @@
           type="link"
           title={show === 'icon' ? btn.label : ''}
           loading={loading}
-          style={btn.btnstyle}
+          disabled={disabled}
+          style={btn.style}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={() => {this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/actionList/tabbutton/index.jsx b/src/tabviews/zshare/actionList/tabbutton/index.jsx
index 28bf3f2..fdb9d78 100644
--- a/src/tabviews/zshare/actionList/tabbutton/index.jsx
+++ b/src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -22,7 +22,23 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    disabled: false,
     primaryId: ''
+  }
+
+  UNSAFE_componentWillMount () {
+    const { btn, selectedData } = this.props
+    let disabled = false
+
+    if (btn.controlField && selectedData && selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+      selectedData.forEach(item => {
+        let s = item[btn.controlField] + ''
+        if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+          disabled = true
+        }
+      })
+      this.setState({disabled})
+    }
   }
 
   shouldComponentUpdate (nextProps, nextState) {
@@ -34,6 +50,24 @@
 
     if (position === 'toolbar') {
       MKEmitter.addListener('triggerBtnId', this.actionTrigger)
+    }
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { btn, selectedData } = this.props
+
+    if (btn.controlField && !is(fromJS(nextProps.selectedData || []), fromJS(selectedData || []))) {
+      let disabled = false
+
+      if (nextProps.selectedData && nextProps.selectedData.length > 0) { // 琛ㄦ牸涓寜閽殣钘忔帶鍒�
+        nextProps.selectedData.forEach(item => {
+          let s = item[btn.controlField] + ''
+          if (s === btn.controlVal || (btn.controlVal && btn.controlVal.split(',').includes(s))) {
+            disabled = true
+          }
+        })
+      }
+      this.setState({disabled})
     }
   }
 
@@ -62,19 +96,11 @@
         duration: 5
       })
       return
-    } else if (!setting.primaryKey) {
-      // 闇�瑕侀�夋嫨琛屾椂锛屾牎楠屾槸鍚﹁缃富閿�
-      notification.warning({
-        top: 92,
-        message: '鏈缃富閿紒',
-        duration: 5
-      })
-      return
     }
 
     let primaryId = ''
 
-    if (btn.Ot === 'requiredSgl') {
+    if (btn.Ot === 'requiredSgl' && setting.primaryKey) {
       primaryId = data[0][setting.primaryKey] || ''
     }
 
@@ -156,12 +182,14 @@
 
   render() {
     const { btn, show } = this.props
+    const { disabled } = this.state
 
     if (show === 'actionList') {
       return (
         <Button
           className={'mk-btn mk-' + btn.class}
           icon={btn.icon}
+          disabled={disabled}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{btn.label}</Button>
       )
@@ -170,7 +198,8 @@
         <Button
           type="link"
           title={show === 'icon' ? btn.label : ''}
-          style={btn.btnstyle}
+          style={btn.style}
+          disabled={disabled}
           icon={show === 'text' ? '' : (btn.icon || '')}
           onClick={(e) => {e.stopPropagation(); this.actionTrigger()}}
         >{show === 'icon' && btn.icon ? '' : btn.label}</Button>
diff --git a/src/tabviews/zshare/dategroup/index.jsx b/src/tabviews/zshare/dategroup/index.jsx
deleted file mode 100644
index 64a37cf..0000000
--- a/src/tabviews/zshare/dategroup/index.jsx
+++ /dev/null
@@ -1,229 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { DatePicker, Tooltip, Icon } from 'antd'
-import moment from 'moment'
-
-import Utils from '@/utils/utils.js'
-import QuarterPicker from './quarterpicker'
-import YearPicker from './yearpicker'
-import './index.scss'
-
-const { MonthPicker, WeekPicker, RangePicker } = DatePicker
-
-class DateGroup extends Component {
-  static propTpyes = {
-    card: PropTypes.object,         // 鎼滅储鏉′欢
-    position: PropTypes.number,     // 绱㈠紩锛岀敤浜庢帶鍒跺搴﹀拰骞寸殑灞曞紑鏂瑰悜
-    onGroupChange: PropTypes.func   // 鎼滅储鍐呭鍒囨崲
-  }
-
-  state = {
-    active: '',
-    quarterId: Utils.getuuid(),
-    yearId: Utils.getuuid(),
-    dateRange: '',
-    initDateRange: '',
-    initType: '',
-    placement: this.props.position % 4 !== 3 ? 'bottomLeft' : 'bottomRight'
-  }
-
-  UNSAFE_componentWillMount() {
-    const { card } = this.props
-
-    if (card.initval && card.initval[0]) {
-      let _type = card.initval[0]
-      let _val = card.initval[1]
-      let _dateRange = null
-
-      if (_type === 'day') {
-        _dateRange = [moment().subtract(_val, 'days').format('YYYY-MM-DD'),
-          moment().subtract(_val, 'days').format('YYYY-MM-DD')]
-      } else if (_type === 'week') {
-        _dateRange = [moment().subtract(_val * 7, 'days').startOf('week').format('YYYY-MM-DD'),
-          moment().subtract(_val * 7, 'days').endOf('week').format('YYYY-MM-DD')]
-      } else if (_type === 'month') {
-        _dateRange = [moment().subtract(_val, 'month').startOf('month').format('YYYY-MM-DD'),
-          moment().subtract(_val, 'month').endOf('month').format('YYYY-MM-DD')]
-      } else if (_type === 'quarter') {
-        let _differ = parseInt(moment().format('MM')) % 3
-        let _pdiffer = 0
-        let _ndiffer = 0
-
-        // 宸�艰绠�
-        switch(_differ) {
-          case 0:
-            _pdiffer = 2
-            _ndiffer = 0
-            break
-          case 1:
-            _pdiffer = 0
-            _ndiffer = -2
-            break
-          case 2:
-            _pdiffer = 1
-            _ndiffer = -1
-            break
-          default:
-        }
-        _dateRange = [moment().subtract(_pdiffer + _val * 3, 'month').startOf('month').format('YYYY-MM-DD'),
-          moment().subtract(_ndiffer + _val * 3, 'month').endOf('month').format('YYYY-MM-DD')]
-      } else if (_type === 'year') {
-        let _year = parseInt(moment().format('YYYY')) - _val
-        _dateRange = [_year + '-01-01', _year + '-12-31']
-      } else if (_type === 'customized') {
-        try {
-          _val = JSON.parse(_val)
-        } catch {
-          _val = [0, 0]
-        }
-        _dateRange = [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
-          moment().subtract(_val[1], 'days').format('YYYY-MM-DD')]
-      }
-      this.setState({
-        active: card.initval[0],
-        dateRange: _dateRange,
-        initDateRange: _dateRange,
-        initType: card.initval[0]
-      })
-    }
-  }
-
-  onChange = (date, type) => {
-    let values = []
-    if (type === 'day') {
-      values = [moment(date).format('YYYY-MM-DD'), moment(date).format('YYYY-MM-DD')]
-    } else if (type === 'week') {
-      values = [moment(date).startOf('week').format('YYYY-MM-DD'), moment(date).endOf('week').format('YYYY-MM-DD')]
-    } else if (type === 'month') {
-      values = [moment(date).startOf('month').format('YYYY-MM-DD'), moment(date).endOf('month').format('YYYY-MM-DD')]
-    } else if (type === 'quarter') {
-      values = date
-      document.getElementById(this.state.quarterId).click()
-    } else if (type === 'year') {
-      values = date
-      document.getElementById(this.state.yearId).click()
-    } else if (type === 'customized') {
-      values = [moment(date[0]).format('YYYY-MM-DD'), moment(date[1]).format('YYYY-MM-DD')]
-    }
-
-    this.setState({
-      active: type,
-      dateRange: values
-    }, () => {
-      this.props.onGroupChange()
-    })
-  }
-
-  clearTime = () => {
-    this.setState({
-      active: '',
-      dateRange: ''
-    }, () => {
-      this.props.onGroupChange()
-    })
-  }
-
-  reset = () => {
-    const { initDateRange, initType } = this.state
-
-    this.setState({
-      active: initType,
-      dateRange: initDateRange
-    })
-  }
-
-  getSearchItems = () => {
-    const { card } = this.props
-    const { dateRange, active } = this.state
-    let items = []
-
-    items.push({
-      type: 'daterange',
-      key: card.datefield,
-      value: dateRange,
-      label: card.label,
-      match: 'between',
-      required: card.required === 'true'
-    })
-
-    if (card.transfer === 'true') {
-      items.push({
-        type: card.type,
-        key: card.field,
-        value: active,
-        label: card.label,
-        match: '=',
-        forbid: true,
-        required: card.required === 'true'
-      })
-    }
-
-    return items
-  }
-
-  render() {
-    const { card } = this.props
-    const { active, quarterId, yearId, dateRange, placement } = this.state
-    let tabs = {day: '鏃�', week: '鍛�', month: '鏈�', quarter: '瀛�', year: '骞�', customized: '鑷畾涔�'}
-
-    return (
-      <div className="table-search-date-group">
-        {card.items.map(tab => {
-          if (tab === 'day') {
-            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-              {tabs[tab]}
-              <DatePicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
-            </span>)
-          } else if (tab === 'week') {
-            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-              {tabs[tab]}
-              <WeekPicker dropdownClassName="group-week-picker" allowClear={false} onChange={(date) => this.onChange(date, tab)} />
-            </span>)
-          } else if (tab === 'month') {
-            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-              {tabs[tab]}
-              <MonthPicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
-            </span>)
-          } else if (tab === 'quarter') {
-            return (
-              <Tooltip key={tab} placement={placement} overlayClassName={'quarter-picker-tooltip ' + placement} trigger="click" title={
-                <div>
-                  <QuarterPicker card={card} onChange={(date) => this.onChange(date, tab)}/>
-                </div>
-              }>
-                <span id={quarterId} className={'ant-tag ant-tag-quarter ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-                  {tabs[tab]}
-                </span>
-              </Tooltip>
-            )
-          } else if (tab === 'year') {
-            return (
-              <Tooltip key={tab} placement={placement} overlayClassName={'year-picker-tooltip ' + placement} trigger="click" title={
-                <div>
-                  <YearPicker card={card} onChange={(date) => this.onChange(date, tab)}/>
-                </div>
-              }>
-                <span id={yearId} className={'ant-tag ant-tag-quarter ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-                  {tabs[tab]}
-                </span>
-              </Tooltip>
-            )
-          } else {
-            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
-              {tabs[tab]}
-              <RangePicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
-            </span>)
-          }
-        })}
-        
-        {dateRange ? <div className="table-search-date-group-value">
-          {dateRange.join(' ~ ')}
-          <Icon type="close-circle" onClick={this.clearTime} className="ant-calendar-picker-clear" />
-        </div> : null}
-        {!dateRange && card.required === 'true' ? <div className="ant-form-explain">璇烽�夋嫨{card.label}!</div> : null}
-      </div>
-    )
-  }
-}
-
-export default DateGroup
\ No newline at end of file
diff --git a/src/tabviews/zshare/fileupload/index.jsx b/src/tabviews/zshare/fileupload/index.jsx
index df0cf6f..32ecbc4 100644
--- a/src/tabviews/zshare/fileupload/index.jsx
+++ b/src/tabviews/zshare/fileupload/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { fromJS } from 'immutable'
+import { is, fromJS } from 'immutable'
 import moment from 'moment'
 import { Upload, Button, Icon, Progress, notification } from 'antd'
 import SparkMD5 from 'spark-md5'
@@ -16,23 +16,74 @@
 
 class FileUpload extends Component {
   static propTpyes = {
-    value: PropTypes.array,    // 鏂囦欢鏁扮粍
-    accept: PropTypes.any,     // 鏂囦欢鏍煎紡
-    maxFile: PropTypes.any,    // 鏈�澶ф枃浠舵暟
-    fileType: PropTypes.string // 鏂囦欢鏄剧ず绫诲瀷
+    config: PropTypes.object,  // 琛ㄥ崟淇℃伅
+    onChange: PropTypes.func,  // 琛ㄥ崟鍙樺寲
   }
 
   state = {
     percent: 0,
+    accept: '',
+    accepts: null,
+    maxFile: null,
+    rduri: '',
+    limit: 2,
+    compress: false,
+    fileType: 'text',
     showprogress: false,
     filelist: []
   }
 
   UNSAFE_componentWillMount () {
-    const { value } = this.props
-    if (!value) return
+    const { config } = this.props
 
-    this.setState({filelist: fromJS(value).toJS()})
+    let filelist = []
+    if (config.initval) {
+      try {
+        filelist = config.initval.split(',').map((url, index) => {
+          return {
+            uid: `${index}`,
+            name: url.slice(url.lastIndexOf('/') + 1),
+            status: 'done',
+            url: url,
+            origin: true
+          }
+        })
+      } catch {
+        filelist = []
+      }
+    }
+
+    let accept = ''
+    let accepts = null
+    let compress = false
+    if (config.compress === 'true') {
+      compress = true
+      accepts = ['.jpg', '.png', '.gif', '.jpeg']
+      accept = accepts.join(',')
+    } else if (config.suffix) {
+      accepts = config.suffix.split(',')
+      accept = config.suffix
+    }
+    let rduri = config.rduri || ''
+    
+    if (window.GLOB.systemType === 'production') {
+      rduri = config.proRduri || ''
+    }
+
+    this.setState({
+      rduri,
+      accept,
+      accepts,
+      filelist,
+      compress,
+      limit: config.limit || 2,
+      maxFile: config.maxfile && config.maxfile > 0 ? config.maxfile : null,
+      fileType: config.fileType || 'text'
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
   }
 
   onChange = ({ fileList }) => {
@@ -44,14 +95,24 @@
     })
 
     this.setState({filelist: fileList})
-    this.props.onChange(fileList)
   }
 
   onRemove = file => {
     const files = this.state.filelist.filter(v => v.uid !== file.uid)
 
     this.setState({filelist: files})
-    this.props.onChange(files)
+
+    let vals = []
+
+    files.forEach(item => {
+      if (item.origin && item.url) {
+        vals.push(item.url)
+      } else if (!item.origin && item.status === 'done' && item.response) {
+        vals.push(item.response)
+      }
+    })
+
+    this.props.onChange(vals.join(','))
   }
 
   onUpdate = (url) => {
@@ -63,19 +124,31 @@
       filelist[filelist.length -1].origin = false
     }
 
+    filelist = filelist.filter(item => !!(item.url || item.response))
+
+    let vals = []
+
+    filelist.forEach(item => {
+      if (item.origin && item.url) {
+        vals.push(item.url)
+      } else if (!item.origin && item.status === 'done' && item.response) {
+        vals.push(item.response)
+      }
+    })
+
     this.setState({filelist})
-    this.props.onChange(filelist)
+    this.props.onChange(vals.join(','))
   }
 
-  onDelete = (msg) => {
+  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})
-    this.props.onChange(filelist)
+
+    this.setState({filelist, showprogress: false, percent: 0})
 
     notification.warning({
       top: 92,
@@ -97,6 +170,7 @@
     form.append('fileExt', params.file.fileType)
     form.append('shardingCnt', param.chunks)
     form.append('shardingNo', param.chunk)
+    form.append('LoginUID', sessionStorage.getItem('LoginUID') || '')
 
     Api.getLargeFileUpload(form).then(res => {
       if (res.status) {
@@ -109,7 +183,7 @@
           if (res.urlPath) {
             this.onUpdate(res.urlPath)
           } else {
-            this.onDelete()
+            this.onFail()
           }
           this.setState({
             percent: 100
@@ -123,7 +197,7 @@
           })
         }
       } else {
-        this.onDelete(res.message)
+        this.onFail(res.message)
       }
     })
   }
@@ -139,12 +213,11 @@
   }
 
   beforeUpload = (file) => {
-    const { accept } = this.props
+    const { accepts, compress, limit, rduri } = this.state
 
-    if (accept && file.name) {
-      let types = accept.split(',')
+    if (accepts && file.name) {
       let pass = false
-      types.forEach(type => {
+      accepts.forEach(type => {
         if (new RegExp(type + '$', 'ig').test(file.name)) {
           pass = true
         }
@@ -164,6 +237,89 @@
       showprogress: true,
       percent: 0
     })
+
+    if (compress) {
+      let reader = new FileReader()
+      let fileSize = file.size / 1024 / 1024
+      let compressRate = 0.9
+
+      if (fileSize / limit > 5) {
+        compressRate = 0.4
+      } else if (fileSize / limit > 4) {
+        compressRate = 0.5
+      } else if (fileSize / limit > 3) {
+        compressRate = 0.6
+      } else if (fileSize / limit > 2) {
+        compressRate = 0.7
+      } else if (fileSize > limit) {
+        compressRate = 0.8
+      }
+
+      reader.onload = (e) => {
+        let img = new Image()
+        let maxW = 640
+ 
+        img.onload = () => {
+          let cvs = document.createElement( 'canvas')
+          let ctx = cvs.getContext( '2d')
+    
+          if (img.width > maxW) {
+            img.height *= maxW / img.width
+            img.width = maxW
+          }
+  
+          cvs.width = img.width
+          cvs.height = img.height
+  
+          ctx.clearRect(0, 0, cvs.width, cvs.height)
+          ctx.drawImage(img, 0, 0, img.width, img.height)
+
+          let param = {Base64Img: cvs.toDataURL('image/jpeg', compressRate)}
+
+          if (rduri) {
+            param.rduri = rduri
+          }
+
+          Api.fileuploadbase64(param).then(result => {
+            if (result.status && result.Images) {
+              let url = service + result.Images
+
+              if (rduri) {
+                url = rduri.replace(/webapi(.*)$/, '') + result.Images
+              }
+
+              this.onUpdate(url)
+
+              this.setState({
+                percent: 100
+              }, () => {
+                setTimeout(() => {
+                  this.setState({
+                    showprogress: false,
+                    percent: 0
+                  })
+                }, 200)
+              })
+            } else {
+              this.onFail(result.message)
+            }
+          })
+        }
+
+        img.onerror = () => {
+          this.onFail('鍥剧墖璇诲彇澶辫触锛�')
+        }
+    
+        img.src = e.target.result
+      }
+
+      reader.onerror = () => {
+        this.onFail('鏂囦欢璇诲彇澶辫触锛�')
+      }
+
+      reader.readAsDataURL(file)
+      return false
+    }
 
     // 鍏煎鎬х殑澶勭悊
     let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice
@@ -233,11 +389,10 @@
     }
 
     chunkFileReader.onerror = () => {
-      this.onDelete()
-      console.warn('File reading failed.')
+      this.onFail('鏂囦欢璇诲彇澶辫触锛�')
     }
     totalFileReader.onerror = () => {
-      this.onDelete()
+      this.onFail('鏂囦欢璇诲彇澶辫触锛�')
     }
 
     let loadNext = () => {
@@ -269,12 +424,11 @@
   }
 
   render() {
-    const { maxFile, fileType, accept } = this.props
-    const { showprogress, percent, filelist } = this.state
+    const { showprogress, percent, filelist, maxFile, fileType, accept } = this.state
 
     let uploadable = 'fileupload-form-container '
 
-    if (maxFile && maxFile > 0 && filelist.length >= maxFile) {
+    if (maxFile && filelist.length >= maxFile) {
       uploadable += 'limit-fileupload'
     }
 
@@ -284,7 +438,7 @@
       listType: fileType,
       fileList: filelist,
       action: null,
-      accept: accept || '',
+      accept: accept,
       method: 'post',
       multiple: false,
       onChange: this.onChange,
diff --git a/src/tabviews/zshare/fileupload/index.scss b/src/tabviews/zshare/fileupload/index.scss
index 5841f7b..6b612d6 100644
--- a/src/tabviews/zshare/fileupload/index.scss
+++ b/src/tabviews/zshare/fileupload/index.scss
@@ -4,6 +4,12 @@
     bottom: -20px;
     left: 0px;
   }
+
+  .ant-upload-select-picture-card {
+    .ant-progress-small.ant-progress-line {
+      bottom: 0px;
+    }
+  }
   
   .ant-upload-list-picture-card .ant-upload-list-item {
     width: 90px;
@@ -12,6 +18,12 @@
   .ant-upload.ant-upload-select-picture-card {
     width: 90px;
     height: 90px;
+  }
+  a[href^="data"] {
+    pointer-events: none;
+    .anticon-eye-o {
+      display: none;
+    }
   }
 }
 .fileupload-form-container.limit-fileupload {
@@ -26,4 +38,7 @@
       }
     }
   }
+  > .ant-upload-select-picture-card {
+    display: none;
+  }
 }
\ No newline at end of file
diff --git a/src/tabviews/zshare/imgScale/index.jsx b/src/tabviews/zshare/imgScale/index.jsx
new file mode 100644
index 0000000..dc4c542
--- /dev/null
+++ b/src/tabviews/zshare/imgScale/index.jsx
@@ -0,0 +1,65 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon } from 'antd'
+
+import './index.scss'
+
+class ImgScale extends Component {
+  static propTpyes = {
+    data: PropTypes.object
+  }
+
+  state = {
+    list: [],
+    index: 0
+  }
+
+  UNSAFE_componentWillMount() {
+    const { data } = this.props
+
+    this.setState({
+      list: data.list || [],
+      index: data.index || 0
+    })
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  reduce = () => {
+    const { index } = this.state
+
+    this.setState({index: index - 1})
+  }
+
+  plus = () => {
+    const { index } = this.state
+
+    this.setState({index: index + 1})
+  }
+
+  render() {
+    const { list, index } = this.state
+
+    return (
+      <div className="img-scale-wrap">
+        <img src={list[index]} alt="" />
+        {index > 0 ? <Icon type="left" onClick={this.reduce} /> : null}
+        {index < list.length -1 ? <Icon type="right" onClick={this.plus} /> : null}
+      </div>
+    )
+  }
+}
+
+export default ImgScale
\ No newline at end of file
diff --git a/src/tabviews/zshare/imgScale/index.scss b/src/tabviews/zshare/imgScale/index.scss
new file mode 100644
index 0000000..db4944e
--- /dev/null
+++ b/src/tabviews/zshare/imgScale/index.scss
@@ -0,0 +1,20 @@
+.img-scale-wrap {
+  position: relative;
+  img {
+    max-width: 100%;
+  }
+
+  .anticon {
+    position: absolute;
+    top: calc(50% - 25px);
+    font-size: 30px;
+    padding: 10px;
+  }
+
+  .anticon-left {
+    left: 20px;
+  }
+  .anticon-right {
+    right: 20px;
+  }
+}
diff --git a/src/tabviews/zshare/mutilform/checkCard/index.jsx b/src/tabviews/zshare/mutilform/checkCard/index.jsx
index c8ceec6..fd825fa 100644
--- a/src/tabviews/zshare/mutilform/checkCard/index.jsx
+++ b/src/tabviews/zshare/mutilform/checkCard/index.jsx
@@ -2,6 +2,7 @@
 import PropTypes from 'prop-types'
 import { Col, Row } from 'antd'
 
+import MKEmitter from '@/utils/events.js'
 import './index.scss'
 
 class CheckCard extends Component {
@@ -29,10 +30,12 @@
   }
 
   changeCard = (item) => {
-    const { multiple } = this.props.card
+    const { card } = this.props
     const { selectKeys } = this.state
 
-    if (multiple === 'true') {
+    if (card.readonly) return
+
+    if (card.multiple === 'true') {
       let keys = []
       if (selectKeys.includes(item.$value)) {
         keys = selectKeys.filter(key => key !== item.$value)
@@ -45,7 +48,13 @@
       }, () => {
         this.props.onChange && this.props.onChange(keys.join(','))
       })
-    } else if (multiple !== 'true' && selectKeys !== item.$value) {
+    } else if (selectKeys !== item.$value) {
+      card.linkFields && card.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkSP', m.uuid, item.$value, 0)
+        }, (i + 1) * 10)
+      })
+
       this.setState({
         selectKeys: item.$value
       }, () => {
@@ -55,7 +64,7 @@
   }
 
   getCards = () => {
-    const { display, width, options, fields, ratio, multiple } = this.props.card
+    const { display, width, options, fields, ratio, multiple, backgroundColor, borderColor } = this.props.card
     const { selectKeys } = this.state
 
     let paddingTop = '100%'
@@ -67,12 +76,16 @@
       paddingTop = '56.25%'
     }
 
+    let style = borderColor ? {borderColor} : {}
+    let _style = backgroundColor ? {backgroundColor} : null
+
     if (!options || options.length === 0) {
       return null
     } else if (display !== 'picture') {
       if (!fields || fields.length === 0) {
         return null
       }
+
       return options.map(item => {
         let _active = false
         if (multiple === 'true' && selectKeys.includes(item.$value)) {
@@ -82,7 +95,8 @@
         }
 
         return <Col span={width} key={item.key}>
-          <div className={'card-cell ' + (_active ? 'active' : '')} onClick={() => this.changeCard(item)}>
+          <div className={'card-cell' + (_active ? ' active' : '') + (_style ? ' bg-control' : '')} style={style} onClick={() => this.changeCard(item)}>
+            <div className="bg-mask" style={_style}></div>
             {fields.map(col => {
               return <span key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{item[col.field]}</span>
             })}
@@ -99,7 +113,7 @@
         }
 
         return <Col span={width} key={item.key}>
-          <div className={'card-pic-cell ' + (_active ? 'active' : '')} onClick={() => this.changeCard(item)} style={{paddingTop, backgroundImage: `url(${item.$url})`}}>
+          <div className={'card-pic-cell ' + (_active ? 'active' : '')} onClick={() => this.changeCard(item)} style={{...style, paddingTop, backgroundImage: `url(${item.$url})`}}>
           </div>
         </Col>
       })
@@ -107,8 +121,9 @@
   }
 
   render() {
+    const { card } = this.props
     return (
-      <div className="check-card-form-box">
+      <div className={'check-card-form-box' + (card.readonly ? ' readonly' : '')}>
         <Row gutter={12}>{this.getCards()}</Row>
       </div>
     )
diff --git a/src/tabviews/zshare/mutilform/checkCard/index.scss b/src/tabviews/zshare/mutilform/checkCard/index.scss
index 3d87dc7..ae18860 100644
--- a/src/tabviews/zshare/mutilform/checkCard/index.scss
+++ b/src/tabviews/zshare/mutilform/checkCard/index.scss
@@ -2,28 +2,48 @@
   margin-top: 10px;
   margin-bottom: -10px;
   .card-cell {
+    position: relative;
     border: 1px solid #bcbcbc;
     border-radius: 4px;
     padding: 6px;
     margin-bottom: 12px;
     line-height: 1.5;
-    transition: all 0.3s;
     cursor: pointer;
+    transition: all 0.3s;
     span {
       display: block;
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
+      position: relative;
+      z-index: 1;
+    }
+    .bg-mask {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      opacity: 0.3;
+      border-radius: 4px;
+      background-color: transparent;
+      transition: opacity 0.3s;
     }
   }
-  .card-cell:hover, .card-cell.active {
+  .card-cell:not(.bg-control).active {
     border-color: #1890ff;
     background: #1890ff;
     span {
       color: #ffffff!important;
     }
   }
+  .card-cell.bg-control.active {
+    .bg-mask {
+      opacity: 1;
+    }
+  }
   .card-pic-cell {
+    position: relative;
     border: 1px solid #bcbcbc;
     border-radius: 4px;
     background-size: cover;
@@ -31,9 +51,47 @@
     margin-bottom: 12px;
     line-height: 1.5;
     cursor: pointer;
+    transition: all 0.3s;
   }
-  .card-pic-cell:hover, .card-pic-cell.active {
+  .card-pic-cell.active {
     border-color: #1890ff;
     box-shadow: 0px 0px 4px #1890ff;
   }
+
+  .card-cell:not(.bg-control).active::after {
+    content: ' ';
+    position: absolute;
+    display: table;
+    border: 2px solid #ffffff;
+    border-top: 0;
+    border-left: 0;
+    bottom: 0;
+    right: 12px;
+    width: 6px;
+    height: 12px;
+    transform: rotate(45deg) scale(1) translate(-50%, -50%);
+  }
+}
+.check-card-form-box:not(.readonly) {
+  .card-cell:not(.bg-control):hover {
+    border-color: #1890ff;
+    background: #1890ff;
+    span {
+      color: #ffffff!important;
+    }
+  }
+  .card-cell.bg-control:not(.active):hover {
+    .bg-mask {
+      opacity: 0.7;
+    }
+  }
+  .card-pic-cell:hover {
+    border-color: #1890ff;
+    box-shadow: 0px 0px 4px #1890ff;
+  }
+}
+.check-card-form-box.readonly {
+  .card-cell, .card-pic-cell {
+    cursor: not-allowed;
+  }
 }
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.jsx b/src/tabviews/zshare/mutilform/customSwitch/index.jsx
deleted file mode 100644
index 4a3c83a..0000000
--- a/src/tabviews/zshare/mutilform/customSwitch/index.jsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Switch } from 'antd'
-
-import './index.scss'
-
-class CheckCard extends Component {
-  static propTpyes = {
-    Item: PropTypes.bool,      // 琛ㄥ崟
-    onChange: PropTypes.func   // 鏁版嵁鍒囨崲
-  }
-
-  state = {
-    defaultChecked: this.props.Item.initval === true
-  }
-
-  UNSAFE_componentWillMount () {
-    const { Item, onChange } = this.props
-    if (Item.initval === true) {
-      onChange && onChange(Item.openVal)
-    } else {
-      onChange && onChange(Item.closeVal)
-    }
-  }
-
-  onChange = (val) => {
-    const { Item, onChange } = this.props
-    if (val) {
-      onChange && onChange(Item.openVal)
-    } else {
-      onChange && onChange(Item.closeVal)
-    }
-  }
-
-  render() {
-    const { Item } = this.props
-    const { defaultChecked } = this.state
-
-    return (
-      <Switch checkedChildren={Item.openText || ''} unCheckedChildren={Item.closeText || ''} defaultChecked={defaultChecked} onChange={this.onChange}/>
-    )
-  }
-}
-
-export default CheckCard
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customTextArea/index.jsx b/src/tabviews/zshare/mutilform/customTextArea/index.jsx
deleted file mode 100644
index 457e5f2..0000000
--- a/src/tabviews/zshare/mutilform/customTextArea/index.jsx
+++ /dev/null
@@ -1,88 +0,0 @@
-import React, {Component} from 'react'
-import PropTypes from 'prop-types'
-import { Input } from 'antd'
-
-import './index.scss'
-
-const { TextArea } = Input
-
-class CustomTextArea extends Component {
-  static propTpyes = {
-    Item: PropTypes.bool,      // 琛ㄥ崟
-    onChange: PropTypes.func   // 鏁版嵁鍒囨崲
-  }
-
-  state = {
-    value: '',
-    encryption: false
-  }
-
-  UNSAFE_componentWillMount () {
-    let value = ''
-    let encryption = false
-
-    if (this.props['data-__meta']) {
-      value = this.props['data-__meta'].initialValue || ''
-    }
-
-    if (this.props.Item && this.props.Item.encryption === 'true') {
-      encryption = true
-      if (value) {
-        try {
-          value = window.decodeURIComponent(window.atob(value))
-        } catch {
-          value = this.props['data-__meta'].initialValue || ''
-        }
-      }
-    }
-    
-    this.setState({
-      value,
-      encryption
-    })
-  }
-
-  UNSAFE_componentWillReceiveProps(nextProps) {
-    const { value, encryption } = this.state
-
-    if (!encryption && value !== nextProps.value) {
-      this.setState({ value: nextProps.value || '' })
-    } else if (encryption && window.btoa(window.encodeURIComponent(value)) !== nextProps.value) {
-      let _value = nextProps.value || ''
-      try {
-        _value = window.decodeURIComponent(window.atob(_value))
-      } catch {
-        _value = nextProps.value || ''
-      }
-      this.setState({ value: _value })
-    }
-  }
-
-  onChange = (e) => {
-    const { encryption } = this.state
-    let val = e.target.value
-
-    this.setState({ value: val })
-
-    let _val = val
-    if (encryption) {
-      try {
-        _val = window.btoa(window.encodeURIComponent(_val))
-      } catch {
-        _val = val
-      }
-    }
-    this.props.onChange(_val)
-  }
-
-  render() {
-    const { Item } = this.props
-    const { value } = this.state
-
-    return (
-      <TextArea value={value} autoSize={{ minRows: 2, maxRows: Item.maxRows || 6 }} onChange={this.onChange} disabled={Item.readonly === 'true'} />
-    )
-  }
-}
-
-export default CustomTextArea
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/index.jsx b/src/tabviews/zshare/mutilform/index.jsx
index 1efef2a..28affdd 100644
--- a/src/tabviews/zshare/mutilform/index.jsx
+++ b/src/tabviews/zshare/mutilform/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Form, Row, Col, Input, InputNumber, Select, DatePicker, notification, Checkbox, Radio, Tooltip, Icon } from 'antd'
+import { Form, Row, Col, notification, Tooltip, Icon } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -9,17 +9,21 @@
 import { formRule } from '@/utils/option.js'
 import Utils from '@/utils/utils.js'
 import asyncComponent from '@/utils/asyncComponent'
-import asyncSpinComponent from '@/utils/asyncSpinComponent'
+import MKEmitter from '@/utils/events.js'
+import MKInput from './mkInput'
+import MKNumberInput from './mkNumberInput'
+import MKSelect from './mkSelect'
 import './index.scss'
 
-const { MonthPicker } = DatePicker
-
-const CheckCard = asyncComponent(() => import('./checkCard'))
-const CustomSwitch = asyncComponent(() => import('./customSwitch'))
-const CustomTextArea = asyncComponent(() => import('./customTextArea'))
-const FileUpload = asyncComponent(() => import('../fileupload'))
-const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
-const Editor = asyncSpinComponent(() => import('@/components/editor'))
+const MKCheckCard = asyncComponent(() => import('./mkCheckCard'))
+const MKSwitch = asyncComponent(() => import('./mkSwitch'))
+const MKCheckbox = asyncComponent(() => import('./mkCheckbox'))
+const MKRadio = asyncComponent(() => import('./mkRadio'))
+const MKDatePicker = asyncComponent(() => import('./mkDatePicker'))
+const MKTextArea = asyncComponent(() => import('./mkTextArea'))
+const MKFileUpload = asyncComponent(() => import('../fileupload'))
+const MKColor = asyncComponent(() => import('./mkColor'))
+const MKEditor = asyncComponent(() => import('@/components/editor'))
 
 class MainSearch extends Component {
   static propTpyes = {
@@ -33,154 +37,24 @@
   }
 
   state = {
-    datatype: null,  // 鏁版嵁绫诲瀷
-    readtype: null,  // 鏄惁鍙
-    readin: null,    // 琛屾暟鎹槸鍚﹀啓鍏�
-    writein: null,   // 鎵ц鏃舵槸鍚﹀~鍏ラ粯璁ql
-    fieldlen: null,  // 瀛楁闀垮害
     formlist: [],    // 琛ㄥ崟椤�
-    intercepts: [],  // 鎴彇瀛楁
-    record: {}       // 璁板綍涓嬫媺琛ㄥ崟鍏宠仈瀛楁锛岀敤浜庢暟鎹啓鍏�
   }
+
+  record = {}
 
   componentDidMount () {
     const { data, BData, action } = this.props
 
-    let datatype = {}
-    let readtype = {}
-    let readin = {}
-    let writein = {}
-    let fieldlen = {}
-    let intercepts = []
-    let _inputfields = []
     let linkFields = {} // 鍏宠仈鑿滃崟
-    let supItemVal = {} // 涓婄骇鑿滃崟鍒濆鍊�
+    let controlFields = {} // 鎺у埗琛ㄥ崟
     let deForms = []    // 闇�瑕佸姩鎬佽幏鍙栦笅鎷夎彍鍗曠殑琛ㄥ崟
 
+    let record = {}
     let formlist = fromJS(action.fields).toJS()
+    let fieldMap = new Map()
 
-    formlist.forEach(item => {
-      if (item.type === 'text' || item.type === 'number') {              // 鐢ㄤ簬杩囨护涓嬫媺鑿滃崟鍏宠仈琛ㄥ崟
-        _inputfields.push(item.field)
-      } else if (item.type === 'textarea') {
-        _inputfields.push(item.field)
-      } else if (item.type === 'link') {
-        linkFields[item.linkField] = linkFields[item.linkField] || []
-        linkFields[item.linkField].push(item.field)
-      }
-      if (item.interception === 'true') {                                // 瀛楃鎴彇瀛楁
-        intercepts.push(item.field)
-      }
-    })
-
-    formlist = formlist.map(item => {
-      if (item.labelwidth) {
-        item.labelCol = {style: {width: item.labelwidth + '%'}}
-        item.wrapperCol = {style: {width: (100 - item.labelwidth) + '%'}}
-      }
-      if (item.type === 'split' || item.type === 'hint') return item
-
-      // 鏁版嵁鑷姩濉厖
-      let _readin = item.readin !== 'false'
-      if (item.type === 'linkMain' || item.type === 'funcvar') {
-        _readin = false
-      }
-
-      let _fieldlen = item.fieldlength || 50
-      if (item.type === 'textarea' || item.type === 'fileupload' || item.type === 'multiselect' || item.type === 'brafteditor') {
-        _fieldlen = item.fieldlength || 512
-      } else if (item.type === 'number') {
-        _fieldlen = item.decimal ? item.decimal : 0
-        item.initval = item.initval || 0
-      }
-
-      datatype[item.field] = item.type
-      readtype[item.field] = item.readonly === 'true'
-      readin[item.field] = _readin
-      writein[item.field] = item.writein !== 'false'
-      fieldlen[item.field] = _fieldlen
-
-      if (item.setAll === 'true' && (item.type === 'select' || item.type === 'link' || item.type === 'radio')) { // 娣诲姞绌哄��
-        item.options.unshift({
-          key: Utils.getuuid(),
-          Value: '',
-          Text: item.emptyText || '绌�',
-          ParentID: ''
-        })
-      }
-
-      item.oriOptions = item.options ? fromJS(item.options).toJS() : null // 淇濆瓨鍒濆鍒楄〃锛岀敤浜庤仈鍔ㄨ彍鍗曟帶鍒�
-
-      // 涓嬬骇琛ㄥ崟鎺у埗-瀛楁鍐欏叆
-      if ((item.type === 'select' || item.type === 'radio') && item.linkSubField && item.linkSubField.length > 0) {
-        item.linkSubField = item.linkSubField.filter(_item => _inputfields.includes(_item))
-      }
-      if (item.linkSubField && item.linkSubField.length === 0) {
-        item.linkSubField = null
-      }
-
-      let newval = ''
-
-      if (item.type === 'linkMain') {
-        newval = BData && BData[item.field] ? BData[item.field] : ''
-      } else if (_readin && !/^date/.test(item.type) && data && data.hasOwnProperty(item.field)) {
-        newval = data[item.field]
-      } else if (item.type === 'date') { // 鏃堕棿鎼滅储
-        if (_readin && data && data.hasOwnProperty(item.field)) {
-          newval = data[item.field]
-        }
-        if (newval) {
-          newval = moment(newval, 'YYYY-MM-DD')
-          newval = newval.format('YYYY-MM-DD') === 'Invalid date' ? '' : newval
-        }
-        if (!newval && item.initval) {
-          newval = moment().subtract(item.initval, 'days')
-        } else if (!newval) {
-          newval = null
-        }
-      } else if (item.type === 'datemonth') {
-        if (_readin && data && data.hasOwnProperty(item.field)) {
-          newval = data[item.field]
-        }
-        if (newval) {
-          newval = moment(newval, 'YYYY-MM')
-          newval = newval.format('YYYY-MM') === 'Invalid date' ? '' : newval
-        }
-        if (!newval && item.initval) {
-          newval = moment().subtract(item.initval, 'month')
-        } else if (!newval) {
-          newval = null
-        }
-      } else if (item.type === 'datetime') {
-        if (_readin && data && data.hasOwnProperty(item.field)) {
-          newval = data[item.field]
-        }
-        if (newval) {
-          newval = moment(newval, 'YYYY-MM-DD HH:mm:ss')
-          newval = newval.format('YYYY-MM-DD HH:mm:ss') === 'Invalid date' ? '' : newval
-        }
-        if (!newval && item.initval) {
-          newval = moment(moment().subtract(item.initval, 'days').format('YYYY-MM-DD') + ' 00:00:00', 'YYYY-MM-DD HH:mm:ss')
-        } else if (!newval) {
-          newval = null
-        }
-      }
-
-      if (item.type === 'switch' && newval !== '') { // 寮�鍏冲彧鎺ユ敹鍥哄畾鍊�
-        if (newval !== item.closeVal && newval !== item.openVal) {
-          newval = ''
-        } else if (newval === item.openVal) {
-          newval = true
-        } else {
-          newval = false
-        }
-      }
-
-      // 璇诲彇琛ㄦ牸鏁版嵁鎴栬鏈夋椂闂寸殑鍒濆鍊�
-      item.initval = newval !== '' ? newval : item.initval
-
-      // 涓嬫媺琛ㄥ崟锛屽瓨鍦ㄤ笂绾ц彍鍗曟椂锛岀敓鎴愭樉绀哄�煎垪琛紝浼樺厛浠ユ暟瀛楀垽鏂�
-      if (item.supvalue) {
+    formlist = formlist.filter(item => {
+      if (item.supField && item.supvalue) { // 澶氬眰琛ㄥ崟鎺у埗
         let supvals = []
         item.supvalue.split(',').forEach(val => {
           supvals.push(val)
@@ -188,88 +62,306 @@
             supvals.push(+val)
           }
         })
-        item.supvalue = supvals
+        controlFields[item.supField] = controlFields[item.supField] || []
+        controlFields[item.supField].push({field: item.field, values: supvals})
+      }
+      if (item.type === 'link') {
+        linkFields[item.linkField] = linkFields[item.linkField] || []
+        linkFields[item.linkField].push({field: item.field, uuid: item.uuid})
+      }
+
+      if (item.type === 'split' || item.type === 'hint') return true
+
+      if (!item.field || !['text', 'number', 'switch', 'select', 'link', 'linkMain', 'funcvar', 'date', 'datemonth', 'datetime', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color'].includes(item.type)) return false
+
+      // 鏁版嵁鑷姩濉厖
+      item.readin = item.readin !== 'false'
+      item.readonly = item.readonly === 'true'
+      item.writein = item.writein !== 'false'
+      item.hidden = item.hidden === 'true'
+      item.fieldlength = item.fieldlength || 50
+
+      if (item.type === 'funcvar') {
+        item.readin = false
+        item.hidden = true
+      } else if (item.type === 'number') {
+        item.decimal = item.decimal || 0
+        item.fieldlength = item.decimal
+        item.initval = item.initval || 0
+      }
+
+      if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect'].includes(item.type)) {
+        item.options = item.options || []
+        item.options = item.options.map(cell => {
+          cell.value = cell.Value
+          cell.label = cell.Text
+          return cell
+        })
+        if (item.setAll === 'true' && ['select', 'link', 'radio'].includes(item.type)) { // 娣诲姞绌哄��
+          item.options.unshift({
+            key: Utils.getuuid(),
+            value: '',
+            label: item.emptyText || '绌�',
+            ParentID: ''
+          })
+        }
+        item.oriOptions = fromJS(item.options).toJS()
+      }
+
+      let newval = '$empty'
+
+      if (item.readin && data && data.hasOwnProperty(item.field)) {
+        newval = data[item.field]
+      }
+      if (item.type === 'linkMain') {
+        newval = BData && BData[item.field] ? BData[item.field] : '$empty'
+      } else if (item.type === 'date') { // 鏃堕棿鎼滅储
+        if (newval !== '$empty') {
+          newval = moment(newval, 'YYYY-MM-DD').format('YYYY-MM-DD')
+          newval = newval === 'Invalid date' ? '$empty' : newval
+        }
+        if (newval === '$empty' && item.initval) {
+          newval = moment().subtract(item.initval, 'days').format('YYYY-MM-DD')
+        }
+      } else if (item.type === 'datemonth') {
+        if (newval !== '$empty') {
+          newval = moment(newval, 'YYYY-MM').format('YYYY-MM')
+          newval = newval === 'Invalid date' ? '$empty' : newval
+        }
+        if (newval === '$empty' && item.initval) {
+          newval = moment().subtract(item.initval, 'month').format('YYYY-MM')
+        }
+      } else if (item.type === 'datetime') {
+        if (newval !== '$empty') {
+          newval = moment(newval, 'YYYY-MM-DD HH:mm:ss').format('YYYY-MM-DD HH:mm:ss')
+          newval = newval === 'Invalid date' ? '$empty' : newval
+        }
+        if (newval === '$empty' && item.initval) {
+          newval = moment().subtract(item.initval, 'days').format('YYYY-MM-DD') + ' 00:00:00'
+        }
+      } else if (item.type === 'switch') { // 寮�鍏冲彧鎺ユ敹鍥哄畾鍊�
+        if (newval !== '$empty' && (newval === item.closeVal || newval === item.openVal)) {
+
+        } else if (item.initval === true) {
+          newval = item.openVal
+        } else {
+          newval = item.closeVal
+        }
+      }
+
+      if (newval !== '$empty') {
+        item.initval = newval
+      } else if (item.initval === undefined) {
+        item.initval = ''
+      }
+
+      if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect'].includes(item.type) && item.resourceType === '1') {
+        deForms.push(item)
+      }
+
+      if (item.type === 'text') {
+        let _rules = [{
+          pattern: /^[^']*$/ig,
+          message: formRule.input.quotemsg
+        }, {
+          required: item.required === 'true',
+          message: item.label + '涓嶅彲涓虹┖!'
+        }, {
+          max: item.fieldlength,
+          message: formRule.input.formMessage.replace('@max', item.fieldlength)
+        }]
+
+        if (item.regular) {
+          if (item.regular === 'number') {
+            _rules.push({
+              pattern: /^[0-9.-]*$/ig,
+              message: formRule.input.numbermsg
+            })
+          } else if (item.regular === 'letter') {
+            _rules.push({
+              pattern: /^[a-zA-Z]*$/ig,
+              message: formRule.input.lettermsg
+            })
+          } else if (item.regular === 'letter&number') {
+            _rules.push({
+              pattern: /^[a-zA-Z0-9]*$/ig,
+              message: formRule.input.letternummsg
+            })
+          } else if (item.regular === 'funcname') {
+            _rules.push({
+              pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
+              message: formRule.input.funcname
+            })
+          }
+        }
+        
+        item.rules = _rules
+      } else if (item.type === 'number') {
+        item.rules = [{
+          required: true,
+          message: item.label + '涓嶅彲涓虹┖!'
+        }, {
+          validator: (rule, value, callback) => this.handleConfirmPassword(rule, value, callback, item)
+        }]
+      } else if (item.type === 'textarea') {
+        let _rules = [
+          {
+            required: item.required === 'true',
+            message: item.label + '涓嶅彲涓虹┖!'
+          },
+          {
+            max: item.fieldlength,
+            message: formRule.input.formMessage.replace('@max', item.fieldlength)
+          }
+        ]
+        if (item.encryption !== 'true') {
+          _rules.push({
+            pattern: /^[^']*$/ig,
+            message: formRule.input.quotemsg
+          })
+        }
+        item.rules = _rules
+      } else if (item.type === 'brafteditor') {
+        item.rules = [
+          {
+            required: item.required === 'true',
+            message: item.label + '涓嶅彲涓虹┖!'
+          },
+          {
+            max: item.fieldlength,
+            message: formRule.input.formMessage.replace('@max', item.fieldlength)
+          }
+        ]
+      } else if (item.type === 'linkMain') {
+        item.rules = [
+          {
+            required: item.required === 'true',
+            message: item.label + '涓嶅彲涓虹┖!'
+          }
+        ]
+      } else {
+        item.rules = [
+          {
+            required: item.required === 'true',
+            message: '璇烽�夋嫨' + item.label + '!'
+          }
+        ]
+      }
+
+      fieldMap.set(item.field, item)
+
+      return true
+    })
+
+    Object.keys(controlFields).forEach(key => {
+      if (!fieldMap.has(key)) return
+
+      let supItem = fieldMap.get(key)
+      let fields = []
+      
+      controlFields[key].forEach(item => {
+        if (!fieldMap.has(item.field)) return
+
+        let cell = fieldMap.get(item.field)
+
+        if (cell.hidden) return
+
+        if (supItem.hidden || !item.values.includes(supItem.initval)) {
+          cell.hidden = true
+          fieldMap.set(item.field, cell)
+        }
+
+        fields.push(item)
+      })
+
+      supItem.controlFields = fields
+      
+      fieldMap.set(key, supItem)
+    })
+
+    formlist = formlist.map(cell => {
+      if (cell.labelwidth) {
+        cell.labelCol = {style: {width: cell.labelwidth + '%'}}
+        cell.wrapperCol = {style: {width: (100 - cell.labelwidth) + '%'}}
+      }
+      if (!cell.field || !fieldMap.has(cell.field)) return cell
+      let item = fieldMap.get(cell.field)
+
+      if (item.type === 'link') {
+        item.supInitVal = ''
+
+        if (fieldMap.has(item.linkField)) {
+          item.supInitVal = fieldMap.get(item.linkField).initval || ''
+        } else if (data && data.hasOwnProperty(item.linkField)) {
+          item.supInitVal = data[item.linkField]
+        }
+        
+        item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.value === '')
+      }
+
+      if (['select', 'link', 'radio'].includes(item.type) && item.resourceType !== '1') { // 閫変腑绗竴椤�
+        if (typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) {
+          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
       }
 
       if (linkFields[item.field]) {
         item.linkFields = linkFields[item.field]
       }
-      supItemVal[item.field] = item.initval
 
-      if (['select', 'link', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(item.type) && item.resourceType === '1') {
-        deForms.push(item)
-      } else if (['select', 'link', 'radio'].includes(item.type) && item.resourceType !== '1') { // 閫変腑绗竴椤�
-        if (typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) {
-          item.initval = item.options[0] ? item.options[0].Value : ''
+      // 涓嬬骇琛ㄥ崟鎺у埗-瀛楁鍐欏叆
+      if ((['select', 'radio'].includes(item.type) || (item.type === 'checkcard' && item.multiple !== 'true')) && item.linkSubField) {
+        item.subFields = []
+        item.linkSubField.forEach(m => {
+          let n = fieldMap.get(m)
+          if (n && ['text', 'number', 'textarea'].includes(n.type)) {
+            item.subFields.push({
+              uuid: n.uuid,
+              field: m
+            })
+          }
+        })
+
+        if (item.subFields.length === 0) {
+          item.subFields = null
         }
+        item.linkSubField = null
       }
 
+      if (item.enter === 'tab' || item.enter === 'sub') {
+        if (fieldMap.has(item.tabField)) {
+          item.tabUuid = fieldMap.get(item.tabField).uuid
+        } else {
+          item.tabUuid = item.uuid
+        }
+      }
+      
       return item
     })
 
-    formlist = formlist.map(item => {
-      if (item.type === 'link') {
-        item.supInitVal = ''
+    this.record = record
 
-        if (supItemVal[item.linkField]) {
-          item.supInitVal = supItemVal[item.linkField]
-        } else if (data && data.hasOwnProperty(item.linkField)) {
-          item.supInitVal = data[item.linkField]
-        }
-        
-        item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-      }
-      return item
-    })
-
-    this.setState({
-      readin,
-      writein,
-      readtype,
-      datatype,
-      fieldlen,
-      intercepts,
-      formlist
-    }, () => {
-      if (action.setting && action.setting.focus) {
+    this.setState({ formlist }, () => {
+      if (action.setting && action.setting.focus && fieldMap.has(action.setting.focus)) {
         setTimeout(() => {
-          this.selectInput(action.setting.focus)
+          MKEmitter.emit('mkFC', 'focus', fieldMap.get(action.setting.focus).uuid)
         }, 500)
       }
-      // 鐢ㄦ潵鏇存柊state锛岄槻姝㈠彈鎺ц〃鍗曞垵濮嬫椂涓嶆樉绀�
-      this.setState({
-        loaded: true
-      })
-      this.improveActionForm(deForms)
-    })
-  }
 
-  selectInput = (selectId) => {
-    try {
-      let _form = document.getElementById('main-form-box')
-      let _inputs = _form.getElementsByTagName('input')
-      _inputs = [..._inputs]
-      _inputs.forEach(input => {
-        if (!input || input.id !== selectId) return
-
-        if (input.className === 'ant-select-search__field') {
-          let div = input.parentNode
-          while (div && div.parentNode) {
-            div = div.parentNode
-            if (div.id === selectId) {
-              div && div.click && div.click()
-              div = null
-            }
-          }
-        } else if (input.select) {
-          input.select()
-        } else if (input.focus) {
-          input.focus()
+      if (deForms.length > 0) {
+        if (this.props.menuType !== 'HS' && options.sysType === 'local' && window.GLOB.systemType !== 'production') {
+          this.improveSimpleActionForm(deForms)
+        } else {
+          this.improveActionForm(deForms)
         }
-      })
-    } catch {
-      console.warn('focus error锛�')
-    }
+      }
+    })
   }
 
   /**
@@ -277,14 +369,6 @@
    */
   improveActionForm = (deForms) => {
     const { BID, menuType } = this.props
-    const { formlist } = this.state
-
-    if (deForms.length === 0) {
-      return
-    } else if (menuType !== 'HS' && options.sysType === 'local' && !window.GLOB.systemType) {
-      this.improveSimpleActionForm(deForms)
-      return
-    }
 
     let deffers = []
     let mainItems = []  // 浜戠鎴栧崟鐐规暟鎹�
@@ -298,7 +382,7 @@
       }
     })
     
-    if (menuType !== 'HS' && window.GLOB.systemType !== 'production') {
+    if (menuType !== 'HS' && options.sysType !== 'local') {
       localItems = [...localItems, ...mainItems]
       mainItems = []
     }
@@ -309,11 +393,8 @@
       LText: localItems.join(' union all '),
       obj_name: '',
       arr_field: '',
-      table_type: 'Y'
-    }
-
-    if (BID) {
-      param.BID = BID
+      table_type: 'Y',
+      BID: BID || ''
     }
 
     if (param.LText) {
@@ -347,11 +428,8 @@
       LText: mainItems.join(' union all '),
       obj_name: '',
       arr_field: '',
-      table_type: 'Y'
-    }
-
-    if (BID) {
-      mainparam.BID = BID
+      table_type: 'Y',
+      BID: BID || ''
     }
 
     if (mainparam.LText) {
@@ -394,62 +472,7 @@
       delete result.message
       delete result.status
 
-      let _formlist = formlist.map(item => {
-        if (['select', 'link', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
-          let options = []
-          result[item.field].forEach(cell => {
-            let _cell = { key: Utils.getuuid() }
-
-            if (item.type !== 'checkcard') {
-              _cell.Value = cell[item.valueField]
-              _cell.Text = cell[item.valueText]
-              if ((!_cell.Value && _cell.Value !== 0) || (!_cell.Text && _cell.Text !== 0)) return
-            } else {
-              _cell.$value = cell[item.valueField]
-              _cell = {..._cell, ...cell}
-              if (!_cell.$value && _cell.$value !== 0) return
-            }
-    
-            if (item.type === 'link') {
-              _cell.ParentID = cell[item.linkField] === undefined ? '' : cell[item.linkField]
-            } else if (item.linkSubField) {
-              item.linkSubField.forEach(_field => {
-                _cell[_field] = (cell[_field] || cell[_field] === 0) ? cell[_field] : ''
-              })
-            }
-    
-            options.push(_cell)
-          })
-
-          item.oriOptions = [...item.oriOptions, ...options]
-        }
-        return item
-      })
-      let values = []
-
-      this.setState({
-        formlist: _formlist.map(item => {
-          if (item.type === 'link') {
-            item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-          } else if (['select', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(item.type)) {
-            item.options = item.oriOptions
-          }
-          if (['select', 'link', 'radio'].includes(item.type) && typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) { // 閫変腑绗竴椤�
-            item.initval = item.options[0] ? item.options[0].Value : ''
-            values.push({field: item.field, value: item.initval})
-          }
-          return item
-        })
-      }, () => {
-        if (values.length === 0) return
-        let fieldsvalue = {}
-        values.forEach(item => {
-          if (this.props.form.getFieldValue(item.field) !== undefined) {
-            fieldsvalue[item.field] = item.value
-          }
-        })
-        this.props.form.setFieldsValue(fieldsvalue)
-      })
+      this.resetFormList(result)
     })
   }
 
@@ -457,18 +480,13 @@
    * @description 娴嬭瘯绯荤粺鑾峰彇涓嬫媺琛ㄥ崟閫夐」淇℃伅
    */
   improveSimpleActionForm = (deForms) => {
-    const { formlist } = this.state
-
     let deffers = deForms.map(form => {
       let param = {
         func: 'sPC_Get_SelectedList',
         LText: form.data_sql,
         obj_name: form.field,
-        arr_field: form.arr_field
-      }
-  
-      if (this.props.BID) {
-        param.BID = this.props.BID
+        arr_field: form.arr_field,
+        BID: this.props.BID || ''
       }
   
       param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -501,152 +519,56 @@
       delete result.message
       delete result.status
 
-      let _formlist = formlist.map(item => {
-        if (['select', 'link', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
-          let options = []
-          result[item.field].forEach(cell => {
-            let _cell = { key: Utils.getuuid() }
-
-            if (item.type !== 'checkcard') {
-              _cell.Value = cell[item.valueField]
-              _cell.Text = cell[item.valueText]
-              if ((!_cell.Value && _cell.Value !== 0) || (!_cell.Text && _cell.Text !== 0)) return
-            } else {
-              _cell.$value = cell[item.valueField]
-              _cell = {..._cell, ...cell}
-              if (!_cell.$value && _cell.$value !== 0) return
-            }
-    
-            if (item.type === 'link') {
-              _cell.ParentID = cell[item.linkField] === undefined ? '' : cell[item.linkField]
-            } else if (item.linkSubField) {
-              item.linkSubField.forEach(_field => {
-                _cell[_field] = (cell[_field] || cell[_field] === 0) ? cell[_field] : ''
-              })
-            }
-    
-            options.push(_cell)
-          })
-
-          item.oriOptions = [...item.oriOptions, ...options]
-        }
-        return item
-      })
-      let values = []
-
-      this.setState({
-        formlist: _formlist.map(item => {
-          if (item.type === 'link') {
-            item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-          } else if (['select', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(item.type)) {
-            item.options = item.oriOptions
-          }
-          if (['select', 'link', 'radio'].includes(item.type) && typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) { // 閫変腑绗竴椤�
-            item.initval = item.options[0] ? item.options[0].Value : ''
-            values.push({field: item.field, value: item.initval})
-          }
-          return item
-        })
-      }, () => {
-        if (values.length === 0) return
-        let fieldsvalue = {}
-        values.forEach(item => {
-          if (this.props.form.getFieldValue(item.field) !== undefined) {
-            fieldsvalue[item.field] = item.value
-          }
-        })
-        this.props.form.setFieldsValue(fieldsvalue)
-      })
+      this.resetFormList(result)
     })
   }
 
-  resetform = (formlist, supfields, index, fieldsvalue) => {
-    index++
-    let subfields = []
+  resetFormList = (result) => {
+    let _formlist = this.state.formlist.map(item => {
+      if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
+        let options = []
+        result[item.field].forEach(cell => {
+          let _cell = { key: Utils.getuuid() }
 
-    supfields.forEach(supfield => {
-      formlist = formlist.map(item => {
-        if (item.type === 'link' && item.linkField === supfield.field) {
-          
-          item.options = item.oriOptions.filter(option => option.ParentID === supfield.initval || option.Value === '')
-          item.initval = item.options[0] ? item.options[0].Value : ''
-
-          if (this.props.form.getFieldValue(item.field) !== undefined) {
-            fieldsvalue[item.field] = item.initval
+          if (item.type !== 'checkcard') {
+            _cell.value = cell[item.valueField]
+            _cell.label = cell[item.valueText]
+            if (!_cell.label && _cell.label !== 0) return
+          } else {
+            _cell.$value = cell[item.cardValField]
+            _cell = {..._cell, ...cell}
           }
   
-          subfields.push(item)
+          if (item.type === 'link') {
+            _cell.ParentID = cell[item.linkField] === undefined ? '' : cell[item.linkField]
+          } else if (item.subFields) {
+            item.subFields.forEach(m => {
+              _cell[m.field] = (cell[m.field] || cell[m.field] === 0) ? cell[m.field] : ''
+            })
+          }
+  
+          options.push(_cell)
+        })
+
+        item.oriOptions = [...item.oriOptions, ...options]
+
+        if (item.type === 'link') {
+          item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.value === '')
+        } else if (['select', 'radio', 'checkbox', 'checkcard', 'multiselect'].includes(item.type)) {
+          item.options = item.oriOptions
         }
-        return item
-      })
-    })
-
-    if (subfields.length === 0 || index > 6) {
-      return {formlist: formlist, fieldsvalue: fieldsvalue}
-    } else {
-      return this.resetform(formlist, subfields, index, fieldsvalue)
-    }
-  }
-
-  selectChange = (_field, value) => {
-    const { record } = this.state
-    let formlist = fromJS(this.state.formlist).toJS()
-    let subfields = []
-    let fieldsvalue = {}
-    let _record = {}
-
-    formlist = formlist.map(item => {
-      if (item.type === 'link' && item.linkField === _field.field) {
-        item.options = item.oriOptions.filter(option => option.ParentID === value || option.Value === '')
-        item.initval = item.options[0] ? item.options[0].Value : ''
-
-        if (this.props.form.getFieldValue(item.field) !== undefined) {
-          fieldsvalue[item.field] = item.initval
-        }
-
-        subfields.push(item)
       }
+
+      if (['select', 'link', 'radio'].includes(item.type) && typeof(item.initval) === 'string' && item.initval.indexOf('$first') > -1) { // 閫変腑绗竴椤�
+        item.initval = item.options[0] ? item.options[0].value : ''
+        this.record[item.field] = item.initval
+      }
+      
       return item
     })
-    
-    // 琛ㄥ崟鍒囨崲鏃讹紝鏇存柊鍏宠仈瀛楁
-    if (_field.linkSubField) {
-      let _data = _field.options.filter(op => op.Value === value)[0]
-      
-      if (_data) {
-        _field.linkSubField.forEach(subfield => {
-          if (this.props.form.getFieldValue(subfield) !== undefined) {
-            fieldsvalue[subfield] = (_data[subfield] || _data[subfield] === 0) ? _data[subfield] : ''
-          } else {
-            _record[subfield] = (_data[subfield] || _data[subfield] === 0) ? _data[subfield] : ''
-          }
-        })
-      }
-    }
 
-    if (subfields.length === 0) {
-      this.props.form.setFieldsValue(fieldsvalue)
-      this.setState({
-        record: {...record, ..._record}
-      })
-    } else {
-      let result = this.resetform(formlist, subfields, 0, fieldsvalue)
-
-      this.props.form.setFieldsValue(fieldsvalue)
-      this.setState({
-        formlist: result.formlist,
-        record: {...record, ..._record}
-      })
-    }
-
-    this.setState({}, () => {
-      if (!_field.enter || _field.enter === 'false') return
-
-      if (_field.enter === 'tab') {
-        this.selectInput(_field.tabField)
-      } else if (_field.enter === 'sub') {
-        this.handleSubmit()
-      }
+    this.setState({
+      formlist: _formlist
     })
   }
 
@@ -663,26 +585,45 @@
     callback()
   }
 
-  handleChange = (e, item) => {
-    let val = e.target.value
+  recordChange = (values, item) => {
+    this.record = {...this.record, ...values}
 
-    if (item.enter === 'false') return
-    if (!val || !/\n/ig.test(val)) return
-    if (item.enter === 'tab') {
-      this.selectInput(item.tabField)
-    } else {
-      this.handleSubmit(e)
-      this.selectInput(item.tabField || item.field)
-    }
-  }
+    if (item && item.controlFields) {
+      let map = new Map()
+      this.state.formlist.forEach(cell => {
+        if (!cell.field) return
+        map.set(cell.field, cell)
+      })
 
-  handleInputSubmit = (e, item) => {
-    if (item.enter === 'false') return
-    if (item.enter === 'tab') {
-      this.selectInput(item.tabField)
-    } else {
-      this.handleSubmit(e)
-      this.selectInput(item.tabField || item.field)
+      let reset = (current) => {
+        let val = this.record[current.field]
+
+        current.controlFields.forEach(cell => {
+          let m = map.get(cell.field)
+          m.hidden = current.hidden || !cell.values.includes(val)
+
+          if (m.hidden) {
+            m.initval = this.record[m.field]
+          }
+
+          map.set(cell.field, m)
+
+          if (m.controlFields) {
+            reset(m)
+          }
+        })
+      }
+
+      reset(item)
+
+      this.setState({
+        formlist: this.state.formlist.map(cell => {
+          if (cell.field) {
+            return map.get(cell.field)
+          }
+          return cell
+        })
+      })
     }
   }
 
@@ -691,24 +632,9 @@
     const { formlist } = this.state
 
     const fields = []
-    let filtration = {}
 
     formlist.forEach((item, index) => {
-      if ((!item.field && item.type !== 'split' && item.type !== 'hint') || item.hidden === 'true' || item.type === 'funcvar') return
-      if (item.supField) { // 澶氬眰琛ㄥ崟鎺у埗
-        let _supVal = this.props.form.getFieldValue(item.supField)
-
-        if (_supVal === undefined && filtration[item.supField]) {
-          _supVal = filtration[item.supField]
-        }
-
-        if (item.supvalue.includes(_supVal)) {
-          let _subVal = this.props.form.getFieldValue(item.field)
-          filtration[item.field] = _subVal === undefined ? item.initval : _subVal
-        } else {
-          return
-        }
-      }
+      if (item.hidden) return
 
       if (item.type === 'split') {
         fields.push(
@@ -719,559 +645,59 @@
       } else if (item.type === 'hint') {
         fields.push(
           <Col span={item.span || 24} key={index}>
-            <Form.Item
-              colon={!!item.label}
-              label={item.label}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              className="hint"
-            >
+            <Form.Item className="hint" colon={!!item.label} label={item.label} labelCol={item.labelCol} wrapperCol={item.wrapperCol}>
               <div className="message">{item.message}</div>
             </Form.Item>
           </Col>
         )
-      } else if (item.type === 'text') {
-        let _max = item.fieldlength || 50
-        let _rules = [{
-          pattern: /^[^']*$/ig,
-          message: formRule.input.quotemsg
-        }]
-
-        if (item.regular) {
-          if (item.regular === 'number') {
-            _rules = [{
-              pattern: /^[0-9.-]*$/ig,
-              message: formRule.input.numbermsg
-            }]
-          } else if (item.regular === 'letter') {
-            _rules = [{
-              pattern: /^[a-zA-Z]*$/ig,
-              message: formRule.input.lettermsg
-            }]
-          } else if (item.regular === 'letter&number') {
-            _rules = [{
-              pattern: /^[a-zA-Z0-9]*$/ig,
-              message: formRule.input.letternummsg
-            }]
-          } else if (item.regular === 'funcname') {
-            _rules = [{
-              pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
-              message: formRule.input.funcname
-            }]
-          }
+      } else {
+        let content = null
+        let className = ''
+        let label = item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}><Icon type="question-circle" />{item.label}</Tooltip> : item.label
+      
+        if (item.type === 'text' || item.type === 'linkMain') {
+          content = (<MKInput config={item} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
+        } else if (item.type === 'number') {
+          content = (<MKNumberInput config={item} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
+        } else if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') {
+          content = (<MKSelect config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} onSubmit={this.props.inputSubmit} />)
+        } else if (item.type === 'color') {
+          content = (<MKColor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
+        } else if (item.type === 'checkcard') {
+          className = "checkcard"
+          content = (<MKCheckCard config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)}/>)
+        } else if (item.type === 'switch') {
+          content = (<MKSwitch config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
+        } else if (item.type === 'checkbox') {
+          content = (<MKCheckbox config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
+        } else if (item.type === 'radio') {
+          content = (<MKRadio config={item} onChange={(val) => this.recordChange({[item.field]: val}, item)}/>)
+        } else if (item.type === 'date' || item.type === 'datemonth' || item.type === 'datetime') {
+          content = (<MKDatePicker config={item} onChange={(val) => this.recordChange({[item.field]: val})} />)
+        } else if (item.type === 'fileupload') {
+          content = (<MKFileUpload config={item} onChange={(val) => this.recordChange({[item.field]: val})} />)
+        } else if (item.type === 'textarea') {
+          content = (<MKTextArea config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
+        } else if (item.type === 'brafteditor') {
+          content = (<MKEditor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
+          label = item.hidelabel !== 'true' ? label : ''
         }
 
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval + '',
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.input'] + item.label + '!'
-                  },
-                  {
-                    max: _max,
-                    message: formRule.input.formMessage.replace('@max', _max)
-                  },
-                  ..._rules
-                ]
-              })(<Input placeholder="" autoComplete="off" disabled={item.readonly === 'true'} onChange={(e) => this.handleChange(e, item)} onPressEnter={(e) => this.handleInputSubmit(e, item)} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'number') { // 鏁板瓧
-        let precision = (item.decimal || item.decimal === 0) ? item.decimal : null
+        if (!content) return
 
         fields.push(
           <Col span={item.span || 24} key={index}>
             <Form.Item
+              label={label}
+              className={className}
               extra={item.extra || null}
               labelCol={item.labelCol}
               wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
             >
               {getFieldDecorator(item.field, {
                 initialValue: item.initval,
-                rules: [
-                  {
-                    required: true,
-                    message: this.props.dict['form.required.input'] + item.label + '!'
-                  },
-                  {
-                    validator: (rule, value, callback) => this.handleConfirmPassword(rule, value, callback, item)
-                  }
-                ]
-              })(
-                precision === null ?
-                <InputNumber disabled={item.readonly === 'true'} onPressEnter={(e) => this.handleInputSubmit(e, item)} /> :
-                <InputNumber precision={precision} disabled={item.readonly === 'true'} onPressEnter={(e) => this.handleInputSubmit(e, item)} />
-                )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'color') { // 棰滆壊閫夋嫨
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval || 'transparent',
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <ColorSketch />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'checkcard') { // 澶氶�夋
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              className="checkcard"
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(<CheckCard card={item} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'switch') { // 澶氶�夋
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(<CustomSwitch Item={item} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'checkbox') { // 澶氶�夋
-        let _initval = item.initval ? item.initval.split(',').filter(Boolean) : []
-        
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: _initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Checkbox.Group disabled={item.readonly === 'true'}>
-                  {item.options.map(option => <Checkbox key={option.key} title={option.Text} value={option.Value}>{option.Text}</Checkbox>)}
-                </Checkbox.Group>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'radio') { // 鍗曢�夋
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Radio.Group disabled={item.readonly === 'true'} onChange={(e) => {this.selectChange(item, e.target.value)}}>
-                  {item.options.map(option => <Radio key={option.key} value={option.Value}>{option.Text}</Radio>)}
-                </Radio.Group>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'select' || item.type === 'link') { // 涓嬫媺鎼滅储
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Select
-                  showSearch
-                  allowClear={true}
-                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                  onSelect={(value) => {this.selectChange(item, value)}}
-                  disabled={item.readonly === 'true'}
-                >
-                  {item.options.map(option =>
-                    <Select.Option id={option.key} title={option.Text} key={option.key} value={option.Value}>{option.Text}</Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'multiselect') { // 澶氶��
-        let _initval = item.initval ? item.initval.split(',').filter(Boolean) : []
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: _initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Select
-                  showSearch
-                  mode="multiple"
-                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                  disabled={item.readonly === 'true'}
-                >
-                  {item.options.map(option =>
-                    <Select.Option id={option.key} title={option.Text} key={option.key} value={option.Value}>{option.Text}</Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'date') { // 鏃堕棿鎼滅储
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <DatePicker disabled={item.readonly === 'true'} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'datemonth') {
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <MonthPicker disabled={item.readonly === 'true'} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'datetime') {
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <DatePicker showTime disabled={item.readonly === 'true'} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'fileupload') {
-        let filelist = this.props.data ? this.props.data[item.field] : item.initval
-        if (filelist && this.state.readin[item.field]) {
-          try {
-            filelist = filelist.split(',').map((url, index) => {
-              return {
-                uid: `${index}`,
-                name: url.slice(url.lastIndexOf('/') + 1),
-                status: 'done',
-                url: url,
-                origin: true
-              }
-            })
-          } catch {
-            filelist = []
-          }
-        } else {
-          filelist = []
-        }
-
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: filelist,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <FileUpload accept={item.suffix} maxFile={item.maxfile} fileType={item.fileType || 'text'} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'linkMain') {
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.input'] + item.label + '!'
-                  }
-                ]
-              })(<Input placeholder="" autoComplete="off" disabled={item.readonly === 'true'} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'funcvar') {
-        // 鍑芥暟鍙橀噺瀛楁锛岄粯璁や笉鏄剧ず
-      } else if (item.type === 'textarea') {
-        let _max = item.fieldlength || 512
-        let _rules = []
-        if (item.encryption !== 'true') {
-          _rules = [{
-            pattern: /^[^']*$/ig,
-            message: formRule.input.quotemsg
-          }]
-        }
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : item.label
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.input'] + item.label + '!'
-                  },
-                  {
-                    max: _max,
-                    message: formRule.input.formMessage.replace('@max', _max)
-                  },
-                  ..._rules
-                ]
-              })(<CustomTextArea Item={item} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'brafteditor') {
-        let _max = item.fieldlength || 512
-
-        fields.push(
-          <Col span={item.span || 24} key={index}>
-            <Form.Item
-              extra={item.extra || null}
-              labelCol={item.labelCol}
-              wrapperCol={item.wrapperCol}
-              label={item.hidelabel !== 'true' && item.tooltip ?
-                <Tooltip placement="topLeft" title={item.tooltip}>
-                  <Icon type="question-circle" />
-                  {item.label}
-                </Tooltip> : (item.hidelabel !== 'true' ? item.label : '')
-              }
-            >
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval || '',
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: this.props.dict['form.required.input'] + item.label + '!'
-                  },
-                  {
-                    max: _max,
-                    message: formRule.input.formMessage.replace('@max', _max)
-                  }
-                ]
-              })(<Editor Item={item}/>)}
+                rules: item.rules
+              })(content)}
             </Form.Item>
           </Col>
         )
@@ -1282,164 +708,57 @@
   }
 
   handleConfirm = () => {
-    const { record, intercepts, writein } = this.state
-    let _format = {
-      date: 'YYYY-MM-DD',
-      datemonth: 'YYYY-MM',
-      datetime: 'YYYY-MM-DD HH:mm:ss'
-    }
+    const { formlist } = this.state
 
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     return new Promise((resolve, reject) => {
       this.props.form.validateFieldsAndScroll((err, values) => {
-        if (!err) {
-          let search = []
-          // 闅愯棌琛ㄥ崟
-          this.state.formlist.forEach(item => {
-            if (!item.field) return
+        if (err) {
+          reject(err)
+          return
+        }
+        let search = []
+        let record = {...this.record, ...values}
 
-            let _item = null
-            if (item.type === 'funcvar') {
-              _item = {
-                type: 'funcvar',
-                readonly: 'true',
-                readin: false,
-                writein: writein[item.field],
-                fieldlen: this.state.fieldlen[item.field],
-                key: item.field,
-                value: ''
-              }
-            } else if (item.hidden === 'true') {
-              let _val = item.initval
-              if (record.hasOwnProperty(item.field)) {
-                _val = record[item.field]
-              }
-              
-              _item = {
-                type: this.state.datatype[item.field],
-                readonly: this.state.readtype[item.field],
-                readin: this.state.readin[item.field],
-                writein: writein[item.field],
-                fieldlen: this.state.fieldlen[item.field],
-                key: item.field,
-                value: _val
-              }
-            } else if (item.supField && !item.supvalue.includes(this.props.form.getFieldValue(item.supField))) {
-              _item = {
-                type: this.state.datatype[item.field],
-                readonly: this.state.readtype[item.field],
-                readin: this.state.readin[item.field],
-                writein: writein[item.field],
-                fieldlen: this.state.fieldlen[item.field],
-                key: item.field,
-                value: item.initval
-              }
+        formlist.forEach(item => {
+          if (!item.field) return
+    
+          let _item = {
+            type: item.type,
+            readonly: item.readonly,
+            readin: item.readin,
+            writein: item.writein,
+            fieldlen: item.fieldlength,
+            key: item.field
+          }
+    
+          _item.value = record[item.field] !== undefined ? record[item.field] : ''
+    
+          if (item.type === 'funcvar') {
+            _item.value = ''
+          } else if (_item.value && (item.type === 'text' || item.type === 'textarea' || item.type === 'linkMain')) {
+            _item.value = _item.value.replace(/\t*|\v*/g, '')       // 鍘婚櫎鍒惰〃绗�
+    
+            if (item.interception === 'true') {           // 鍘婚櫎棣栧熬绌烘牸
+              _item.value = _item.value.replace(/(^\s*|\s*$)/g, '')
             }
-
-            if (!_item) return
-
-            if (_item.value === undefined) {
-              _item.value = ''
-            } else if (item.type === 'date' || item.type === 'datemonth' || item.type === 'datetime') {
-              if (!_item.value) {
-                _item.value = ''
-              } else if (_item.value.format) {
-                _item.value = _item.value.format(_format[item.type])
-              }
-            } else if (item.type === 'text' && _item.value && typeof(_item.value) === 'string') { // 鐗规畩瀛楁鏇挎崲
+            if (item.type === 'text' && typeof(_item.value) === 'string') { // 鐗规畩瀛楁鏇挎崲
               _item.value = _item.value.replace(/^(\s*)@appkey@(\s*)$/ig, window.GLOB.appkey)
               _item.value = _item.value.replace(/^(\s*)@SessionUid@(\s*)$/ig, (localStorage.getItem('SessionUid') || ''))
               _item.value = _item.value.replace(/^(\s*)@bid@(\s*)$/ig, (this.props.BID || ''))
             }
-
-            search.push(_item)
-          })
-
-          Object.keys(values).forEach(key => {
-            if (values[key] === undefined) { // 琛ㄥ崟寮傚父锛燂紵锛�
-              if (search.filter(s => s.key === key).length === 0) {
-                search.push({
-                  type: this.state.datatype[key],
-                  readonly: this.state.readtype[key],
-                  readin: this.state.readin[key],
-                  writein: writein[key],
-                  fieldlen: this.state.fieldlen[key],
-                  key: key,
-                  value: ''
-                })
-              }
-              return
+          } else if (item.type.indexOf('date') > -1) {
+            if (item.declareType === 'nvarchar(50)') {
+              _item.type = 'text'
             }
+          }
+    
+          search.push(_item)
+        })
 
-            let _value = ''
-            let _type = this.state.datatype[key]
-            if (_type === 'datetime') {
-              _value = values[key] ? moment(values[key]).format('YYYY-MM-DD HH:mm:ss') : ''
-            } else if (_type === 'datemonth') {
-              _value = values[key] ? moment(values[key]).format('YYYY-MM') : ''
-            } else if (_type === 'date') {
-              _value = values[key] ? moment(values[key]).format('YYYY-MM-DD') : ''
-            } else if (_type === 'number') {
-              _value = values[key]
-
-            } else if (_type === 'multiselect' || _type === 'checkbox') {
-              _value = values[key] ? values[key].join(',') : ''
-
-            } else if (_type === 'fileupload') {
-              let vals = []
-
-              if (values[key] && values[key].length > 0) {
-                values[key].forEach(_val => {
-                  if (_val.origin && _val.url) {
-                    vals.push(_val.url)
-                  } else if (!_val.origin && _val.status === 'done' && _val.response) {
-                    vals.push(Utils.getrealurl(_val.response))
-                  }
-                })
-              }
-
-              _value = vals.join(',')
-            } else if (_type === 'text' || _type === 'textarea') {
-              _value = values[key].replace(/\t*|\v*/g, '') // 鍘婚櫎鍒惰〃绗�
-
-              if (intercepts.includes(key)) {              // 鍘婚櫎棣栧熬绌烘牸
-                _value = _value.replace(/(^\s*|\s*$)/g, '')
-              }
-              if (_type === 'text' && _value) { // 鐗规畩瀛楁鏇挎崲
-                _value = _value.replace(/^(\s*)@appkey@(\s*)$/ig, window.GLOB.appkey)
-                _value = _value.replace(/^(\s*)@SessionUid@(\s*)$/ig, (localStorage.getItem('SessionUid') || ''))
-                _value = _value.replace(/^(\s*)@bid@(\s*)$/ig, (this.props.BID || ''))
-              }
-            } else {
-              _value = values[key]
-            }
-
-            if (_value === undefined) {
-              _value = ''
-            }
-
-            search.push({
-              type: this.state.datatype[key],
-              readonly: this.state.readtype[key],
-              readin: this.state.readin[key],
-              writein: writein[key],
-              fieldlen: this.state.fieldlen[key],
-              key: key,
-              value: _value
-            })
-          })
-
-          resolve(search)
-        } else {
-          reject(err)
-        }
+        resolve(search)
       })
     })
-  }
-
-  handleSubmit = (e) => {
-    e && e.preventDefault()
-    this.props.inputSubmit()
   }
 
   render() {
diff --git a/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
new file mode 100644
index 0000000..316fb81
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
@@ -0,0 +1,140 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Col, Row } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class MKCheckCard extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    selectKeys: null
+  }
+
+  UNSAFE_componentWillMount() {
+    const { config } = this.props
+
+    if (config.multiple === 'true') {
+      this.setState({
+        selectKeys: config.initval ? config.initval.split(',') : []
+      })
+    } else {
+      this.setState({
+        selectKeys: config.initval
+      })
+    }
+  }
+
+  changeCard = (item) => {
+    const { config } = this.props
+    const { selectKeys } = this.state
+
+    if (config.readonly) return
+
+    if (config.multiple === 'true') {
+      let keys = []
+      if (selectKeys.includes(item.$value)) {
+        keys = selectKeys.filter(key => key !== item.$value)
+      } else {
+        keys = [...selectKeys, item.$value]
+      }
+
+      this.setState({
+        selectKeys: keys
+      }, () => {
+        this.props.onChange(keys.join(','))
+      })
+    } else if (selectKeys !== item.$value) {
+      let other = {}
+      config.subFields && config.subFields.forEach((n, i) => {
+        other[n.field] = item[n.field]
+        setTimeout(() => {
+          MKEmitter.emit('mkFC', 'input', n.uuid, item[n.field])
+        }, i * 5)
+      })
+      config.linkFields && config.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkFP', m.uuid, item.$value, 0)
+        }, (i + 1) * 100)
+      })
+
+      this.setState({
+        selectKeys: item.$value
+      }, () => {
+        this.props.onChange(item.$value, other)
+      })
+    }
+  }
+
+  getCards = () => {
+    const { display, width, options, fields, ratio, multiple, backgroundColor, borderColor } = this.props.config
+    const { selectKeys } = this.state
+
+    let paddingTop = '100%'
+    if (ratio === '4:3') {
+      paddingTop = '75%'
+    } else if (ratio === '3:2') {
+      paddingTop = '66.7%'
+    } else if (ratio === '16:9') {
+      paddingTop = '56.25%'
+    }
+
+    let style = borderColor ? {borderColor} : {}
+    let _style = backgroundColor ? {backgroundColor} : null
+
+    if (!options || options.length === 0) {
+      return null
+    } else if (display !== 'picture') {
+      if (!fields || fields.length === 0) {
+        return null
+      }
+      return options.map(item => {
+        let _active = false
+        if (multiple === 'true' && selectKeys.includes(item.$value)) {
+          _active = true
+        } else if (multiple !== 'true' && selectKeys === item.$value) {
+          _active = true
+        }
+
+        return <Col span={width} key={item.key}>
+          <div className={'card-cell' + (_active ? ' active' : '') + (_style ? ' bg-control' : '')} style={style} onClick={() => this.changeCard(item)}>
+            <div className="bg-mask" style={_style}></div>
+            {fields.map(col => {
+              return <span key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{item[col.field]}</span>
+            })}
+          </div>
+        </Col>
+      })
+    } else {
+      return options.map(item => {
+        let _active = false
+        if (multiple === 'true' && selectKeys.includes(item.$value)) {
+          _active = true
+        } else if (multiple !== 'true' && selectKeys === item.$value) {
+          _active = true
+        }
+
+        return <Col span={width} key={item.key}>
+          <div className={'card-pic-cell ' + (_active ? 'active' : '')} onClick={() => this.changeCard(item)} style={{...style, paddingTop, backgroundImage: `url(${item.$url})`}}>
+          </div>
+        </Col>
+      })
+    }
+  }
+
+  render() {
+    const { config } = this.props
+
+    return (
+      <div className={'check-card-form-box' + (config.readonly ? ' readonly' : '')}>
+        <Row gutter={12}>{this.getCards()}</Row>
+      </div>
+    )
+  }
+}
+
+export default MKCheckCard
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkCheckCard/index.scss b/src/tabviews/zshare/mutilform/mkCheckCard/index.scss
new file mode 100644
index 0000000..922b70f
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkCheckCard/index.scss
@@ -0,0 +1,98 @@
+.check-card-form-box {
+  margin-top: 10px;
+  margin-bottom: -10px;
+  .card-cell {
+    position: relative;
+    border: 1px solid #bcbcbc;
+    border-radius: 4px;
+    padding: 6px;
+    margin-bottom: 12px;
+    line-height: 1.5;
+    transition: all 0.3s;
+    cursor: pointer;
+    span {
+      display: block;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+      position: relative;
+      z-index: 1;
+    }
+    .bg-mask {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      opacity: 0.5;
+      border-radius: 4px;
+      background-color: transparent;
+      transition: opacity 0.3s;
+    }
+  }
+  .card-cell:not(.bg-control).active {
+    border-color: #1890ff;
+    background: #1890ff;
+    span {
+      color: #ffffff!important;
+    }
+  }
+  .card-cell.bg-control.active {
+    .bg-mask {
+      opacity: 1;
+    }
+  }
+  .card-pic-cell {
+    position: relative;
+    border: 1px solid #bcbcbc;
+    border-radius: 4px;
+    background-size: cover;
+    background-position: center;
+    margin-bottom: 12px;
+    line-height: 1.5;
+    cursor: pointer;
+    transition: all 0.3s;
+  }
+  .card-pic-cell.active {
+    border-color: #1890ff;
+    box-shadow: 0px 0px 4px #1890ff;
+  }
+
+  .card-cell:not(.bg-control).active::after {
+    content: ' ';
+    position: absolute;
+    display: table;
+    border: 2px solid #ffffff;
+    border-top: 0;
+    border-left: 0;
+    bottom: 0;
+    right: 10px;
+    width: 6px;
+    height: 12px;
+    transform: rotate(45deg) scale(1) translate(-50%, -50%);
+  }
+}
+
+.check-card-form-box:not(.readonly) {
+  .card-cell:not(.bg-control):hover {
+    border-color: #1890ff;
+    background: #1890ff;
+    span {
+      color: #ffffff!important;
+    }
+  }
+  .card-cell.bg-control:not(.active):hover {
+    .bg-mask {
+      opacity: 0.7;
+    }
+  }
+  .card-pic-cell:hover {
+    border-color: #1890ff;
+    box-shadow: 0px 0px 4px #1890ff;
+  }
+}
+.check-card-form-box.readonly {
+  .card-cell, .card-pic-cell {
+    cursor: not-allowed;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx b/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx
new file mode 100644
index 0000000..494719d
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkCheckbox/index.jsx
@@ -0,0 +1,39 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Checkbox } from 'antd'
+
+import './index.scss'
+
+class MKCheckbox extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    defaultValue: this.props.config.initval ? this.props.config.initval.split(',').filter(Boolean) : []
+  }
+
+  onChange = (values) => {
+    this.props.onChange(values.join(','))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { defaultValue } = this.state
+
+    return (
+      <Checkbox.Group defaultValue={defaultValue} disabled={config.readonly} onChange={this.onChange}>
+        {config.options.map(option => <Checkbox key={option.key} title={option.label} value={option.value}>{option.label}</Checkbox>)}
+      </Checkbox.Group>
+    )
+  }
+}
+
+export default MKCheckbox
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/mutilform/mkCheckbox/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/mutilform/mkCheckbox/index.scss
diff --git a/src/tabviews/zshare/mutilform/mkColor/index.jsx b/src/tabviews/zshare/mutilform/mkColor/index.jsx
new file mode 100644
index 0000000..d783e56
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkColor/index.jsx
@@ -0,0 +1,60 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { SketchPicker } from 'react-color'
+import { Popover } from 'antd'
+
+import './index.scss'
+
+const presetColors = [
+  '#f5222d', '#fa541c', '#fa8c16', '#faad14', '#fadb14', '#a0d911', '#52c41a', '#13c2c2', '#1890ff', '#2f54eb', '#722ed1',
+  '#eb2f96', '#595959', '#ffa39e', '#ffbb96', '#ffd591', '#ffe58f', '#fffb8f', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff',
+  '#adc6ff', '#d3adf7', '#ffadd2', '#d9d9d9', '#434343', '#000000', '#ffffff', 'transparent'
+]
+
+class MkColor extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    onChange: PropTypes.func
+  }
+  state = {
+    color: '',
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+    
+    this.setState({color: config.initval})
+  }
+
+  handleChange = (color) => {
+    let _color = `rgba(${ color.rgb.r }, ${ color.rgb.g }, ${ color.rgb.b }, ${ color.rgb.a })`
+
+    this.setState({ color: _color }, () => {
+      this.props.onChange(_color)
+    })
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { color } = this.state
+    return (
+      <div className="color-sketch-block">
+        <Popover content={
+          <SketchPicker color={ color } presetColors={presetColors} onChange={ this.handleChange } />
+        } overlayClassName="color-sketch-popover" placement="bottomRight" title="" trigger="click">
+          <div className="color-sketch-block-box">
+            <div className="color-sketch-block-inner" style={ {background: color} }></div>
+          </div>
+        </Popover>
+        <div className="color-sketch-value">{color}</div>
+      </div>
+    )
+  }
+}
+
+export default MkColor
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkColor/index.scss b/src/tabviews/zshare/mutilform/mkColor/index.scss
new file mode 100644
index 0000000..b6aec44
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkColor/index.scss
@@ -0,0 +1,41 @@
+.color-sketch-block {
+  height: 25px;
+  width: 100%;
+
+  .color-sketch-block-box {
+    display: inline-block;
+    width: calc(100% - 160px);
+    height: 100%;
+    border-radius: 4px;
+    background: #ffffff url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAMUlEQVQ4T2NkYGAQYcAP3uCTZhw1gGGYhAGBZIA/nYDCgBDAm9BGDWAAJyRCgLaBCAAgXwixzAS0pgAAAABJRU5ErkJggg==') left center;
+  }
+  .color-sketch-block-inner {
+    display: inline-block;
+    cursor: pointer;
+    border-radius: 4px;
+    box-shadow: 0 0 0 1px rgba(0, 0, 0, .1);
+    width: 100%;
+    height: 100%;
+  }
+  .color-sketch-value {
+    display: inline-block;
+    font-size: 13px;
+    width: 160px;
+    padding-left: 10px;
+    height: 25px;
+    line-height: 25px;
+    vertical-align: top;
+    white-space: nowrap;
+    overflow: visible;
+  }
+}
+
+.color-sketch-popover {
+  z-index: 1090!important;
+  .ant-popover-inner-content {
+    padding: 0;
+    .sketch-picker {
+      width: 250px!important;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
new file mode 100644
index 0000000..ad7558d
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkDatePicker/index.jsx
@@ -0,0 +1,71 @@
+import React, { Component } from 'react'
+import { is, fromJS } from 'immutable'
+import { DatePicker } from 'antd'
+import moment from 'moment'
+
+import './index.scss'
+
+const { MonthPicker } = DatePicker
+
+/**
+ * @description 鑷畾涔夋椂闂撮�夋嫨鍣�
+ */
+class MkDatePicker extends Component {
+  constructor(props) {
+    super(props)
+
+    const config = props.config
+
+    let mode = 'date'
+    let format = 'YYYY-MM-DD'
+
+    if (config.type === 'datemonth') {
+      mode = 'month'
+      format = 'YYYY-MM'
+    } else if (config.type === 'datetime') {
+      mode = 'datetime'
+      format = 'YYYY-MM-DD HH:mm:ss'
+    }
+    let value = config.initval || null
+    if (value) {
+      value = moment(value, format)
+    }
+
+    this.state = {
+      value,
+      mode,
+      format
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  onChange = (val) => {
+    const { format } = this.state
+
+    this.props.onChange(val ? moment(val).format(format) : '')
+  }
+
+  render() {
+    const { config } = this.props
+    const { value, mode } = this.state
+
+    if (mode === 'date') {
+      return <DatePicker defaultValue={value} disabled={config.readonly} onChange={this.onChange}/>
+    } else if (mode === 'month') {
+      return <MonthPicker defaultValue={value} disabled={config.readonly} onChange={this.onChange}/>
+    } else if (mode === 'datetime') {
+      return <DatePicker defaultValue={value} showTime disabled={config.readonly} onChange={this.onChange}/>
+    }
+  }
+}
+
+export default MkDatePicker
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/mutilform/mkDatePicker/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/mutilform/mkDatePicker/index.scss
diff --git a/src/tabviews/zshare/mutilform/mkInput/index.jsx b/src/tabviews/zshare/mutilform/mkInput/index.jsx
new file mode 100644
index 0000000..9b090dd
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkInput/index.jsx
@@ -0,0 +1,84 @@
+import React, { Component } from 'react'
+import { is, fromJS } from 'immutable'
+import { Input } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+
+import './index.scss'
+
+/**
+ * @description 鑷畾涔夋枃鏈緭鍏�
+ */
+class MKInput extends Component {
+  constructor(props) {
+    super(props)
+    
+    const config = props.config
+    
+    this.state = {
+      value: config.initval
+    }
+  }
+  
+  inputRef = React.createRef()
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('mkFC', this.mkFormHandle)
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkFC', this.mkFormHandle)
+  }
+
+  mkFormHandle = (type, uuid, value) => {
+    if (uuid !== this.props.config.uuid) return
+    if (type === 'focus') {
+      this.inputRef.current.select()
+    } else if (type === 'input') {
+      this.setState({value})
+    }
+  }
+
+  handleChange = (e) => {
+    let val = e.target.value
+
+    if (!/\n/ig.test(val)) {
+      this.props.onChange(val)
+      this.setState({value: val})
+    } else {
+      val = val.replace(/\n/ig, '')
+
+      this.props.onChange(val)
+      this.setState({value: val}, () => {
+        this.handleInputSubmit()
+      })
+    }
+  }
+
+  handleInputSubmit = () => {
+    const { config } = this.props
+
+    if (config.enter === 'false') return
+    if (config.enter === 'tab') {
+      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+    } else {
+      this.props.onSubmit()
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { value } = this.state
+
+    return <Input ref={this.inputRef} placeholder="" value={value} autoComplete="off" disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleInputSubmit} />
+  }
+}
+
+export default MKInput
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkInput/index.scss b/src/tabviews/zshare/mutilform/mkInput/index.scss
new file mode 100644
index 0000000..93dcc24
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkInput/index.scss
@@ -0,0 +1,27 @@
+.am-list-item.am-input-item {
+  .am-input-control {
+    height: 100%;
+    input {
+      height: 100%;
+    }
+  }
+  .am-input-label {
+    width: 28%;
+    max-width: 120px;
+    text-overflow: ellipsis;
+  }
+  .am-input-extra {
+    max-height: 40px;
+    .anticon-scan {
+      font-size: 22px;
+      padding: 8px 5px;
+    }
+  }
+}
+.am-input-item.right {
+  .am-input-control {
+    input {
+      text-align: right;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx b/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
new file mode 100644
index 0000000..7dde469
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
@@ -0,0 +1,67 @@
+import React, { Component } from 'react'
+import { is, fromJS } from 'immutable'
+import { InputNumber } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+
+import './index.scss'
+
+class MKNumberInput extends Component {
+  constructor(props) {
+    super(props)
+
+    const config = props.config
+
+    let precision = (config.decimal || config.decimal === 0) ? config.decimal : null
+    
+    this.state = {
+      precision,
+      value: config.initval
+    }
+  }
+
+  inputNumberRef = React.createRef()
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('mkFC', this.mkFormHandle)
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkFC', this.mkFormHandle)
+  }
+
+  mkFormHandle = (type, uuid, value) => {
+    if (uuid !== this.props.config.uuid) return
+    if (type === 'focus') {
+      this.inputNumberRef.current.focus()
+    } else if (type === 'input') {
+      this.setState({value})
+    }
+  }
+
+  handleChange = (val) => {
+
+    this.props.onChange(val)
+    this.setState({value: val})
+  }
+
+  render() {
+    const { config, onSubmit } = this.props
+    const { value, precision } = this.state
+
+    if (precision === null) {
+      return (<InputNumber ref={this.inputNumberRef} value={value} disabled={config.readonly} onChange={this.handleChange} onPressEnter={onSubmit}/>)
+    } else {
+      return (<InputNumber ref={this.inputNumberRef} value={value} precision={precision} disabled={config.readonly} onChange={this.handleChange} onPressEnter={onSubmit} />)
+    }
+  }
+}
+
+export default MKNumberInput
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkNumberInput/index.scss b/src/tabviews/zshare/mutilform/mkNumberInput/index.scss
new file mode 100644
index 0000000..93dcc24
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkNumberInput/index.scss
@@ -0,0 +1,27 @@
+.am-list-item.am-input-item {
+  .am-input-control {
+    height: 100%;
+    input {
+      height: 100%;
+    }
+  }
+  .am-input-label {
+    width: 28%;
+    max-width: 120px;
+    text-overflow: ellipsis;
+  }
+  .am-input-extra {
+    max-height: 40px;
+    .anticon-scan {
+      font-size: 22px;
+      padding: 8px 5px;
+    }
+  }
+}
+.am-input-item.right {
+  .am-input-control {
+    input {
+      text-align: right;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/mkRadio/index.jsx b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
new file mode 100644
index 0000000..18022bf
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkRadio/index.jsx
@@ -0,0 +1,40 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Radio } from 'antd'
+
+import './index.scss'
+
+class MKRadio extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    defaultValue: this.props.config.initval
+  }
+
+  onChange = (e) => {
+    let value = e.target.value
+    this.props.onChange(value)
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { defaultValue } = this.state
+
+    return (
+      <Radio.Group defaultValue={defaultValue} disabled={config.readonly} onChange={this.onChange}>
+        {config.options.map(option => <Radio key={option.key} value={option.value}>{option.label}</Radio>)}
+      </Radio.Group>
+    )
+  }
+}
+
+export default MKRadio
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/mutilform/mkRadio/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/mutilform/mkRadio/index.scss
diff --git a/src/tabviews/zshare/mutilform/mkSelect/index.jsx b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
new file mode 100644
index 0000000..24da440
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -0,0 +1,179 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Select } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class MKSelect extends Component {
+  constructor(props) {
+    super(props)
+    
+    const config = props.config
+    let value = config.initval
+
+    if (config.type === 'multiselect') {
+      if (value) {
+        value = value.split(',')
+      } else {
+        value = []
+      }
+    }
+
+    this.state = {
+      config: fromJS(config).toJS(),
+      options: fromJS(config.options).toJS(),
+      value,
+    }
+  }
+
+  componentDidMount () {
+    const { config } = this.state
+
+    if (config.type !== 'multiselect') {
+      MKEmitter.addListener('mkFP', this.mkFormHandle)
+    }
+    MKEmitter.addListener('mkFC', this.mkFormFocus)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { config } = this.state
+
+    if (!is(fromJS(config.oriOptions), fromJS(nextProps.config.oriOptions))) {
+      this.setState({
+        config: fromJS(nextProps.config).toJS(),
+        options: fromJS(nextProps.config.options).toJS()
+      })
+
+      if (typeof(config.initval) === 'string' && config.initval.indexOf('$first') > -1) {
+        this.setState({
+          value: nextProps.config.initval,
+        })
+      }
+    }
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkFP', this.mkFormHandle)
+    MKEmitter.removeListener('mkFC', this.mkFormFocus)
+  }
+
+  mkFormFocus = (type, uuid) => {
+    if (uuid !== this.props.config.uuid) return
+    if (type !== 'focus') return
+
+    let _div = document.getElementById(uuid)
+    _div && _div.click && _div.click()
+  }
+
+  mkFormHandle = (uuid, parentId, level) => {
+    if (uuid !== this.state.config.uuid) return
+
+    const { config } = this.state
+
+    let options = config.oriOptions.filter(option => option.ParentID === parentId || option.value === '')
+    let val = options[0] ? options[0].value : ''
+
+    this.setState({
+      options,
+      value: val
+    })
+
+    this.props.onChange(val)
+
+    if (level < 7 && config.linkFields) {
+      config.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkFP', m.uuid, val, level + 1)
+        }, (i + 1) * 70)
+      })
+    }
+  }
+
+  selectChange = (val) => {
+    const { config } = this.state
+    let other = {}
+
+    if (config.subFields) {
+      let option = this.state.options.filter(m => m.value === val)[0]
+      option && config.subFields.forEach((n, i) => {
+        other[n.field] = option[n.field]
+        setTimeout(() => {
+          MKEmitter.emit('mkFC', 'input', n.uuid, option[n.field])
+        }, i * 5)
+      })
+    }
+    if (config.linkFields) {
+      config.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkFP', m.uuid, val, 0)
+        }, (i + 1) * 100)
+      })
+    }
+
+    this.props.onChange(val, other)
+    this.setState({value: val}, () => {
+      if (config.enter === 'tab') {
+        MKEmitter.emit('mkFC', 'focus', config.tabUuid)
+      } else if (config.enter === 'sub') {
+        if (config.linkFields || config.subFields || config.controlFields) {
+          setTimeout(() => {
+            this.props.onSubmit()
+          }, 1000)
+        } else {
+          this.props.onSubmit()
+        }
+      }
+    })
+  }
+
+  mutilselectChange = (val) => {
+    this.props.onChange(val.join(','))
+  }
+
+  render() {
+    const { value, config, options } = this.state
+
+    if (config.type !== 'multiselect') {
+      return (
+        <Select
+          showSearch
+          allowClear
+          id={config.uuid}
+          value={value}
+          filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+          onSelect={this.selectChange}
+          onClear={() => this.selectChange('')}
+          disabled={config.readonly}
+        >
+          {options.map(option =>
+            <Select.Option id={option.key} title={option.label} key={option.key} value={option.value}>{option.label}</Select.Option>
+          )}
+        </Select>
+      )
+    } else {
+      return (<Select
+        showSearch
+        id={config.uuid}
+        mode="multiple"
+        defaultValue={value}
+        filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+        onChange={this.mutilselectChange}
+        disabled={config.readonly}
+      >
+        {options.map(option =>
+          <Select.Option id={option.key} title={option.label} key={option.key} value={option.value}>{option.label}</Select.Option>
+        )}
+      </Select>)
+    }
+  }
+}
+
+export default MKSelect
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/mutilform/mkSelect/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/mutilform/mkSelect/index.scss
diff --git a/src/tabviews/zshare/mutilform/mkSwitch/index.jsx b/src/tabviews/zshare/mutilform/mkSwitch/index.jsx
new file mode 100644
index 0000000..b3eff86
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkSwitch/index.jsx
@@ -0,0 +1,43 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Switch } from 'antd'
+
+import './index.scss'
+
+class MKSwitch extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    defaultChecked: this.props.config.initval === this.props.config.openVal
+  }
+
+  onChange = (val) => {
+    const { config } = this.props
+    
+    if (val) {
+      this.props.onChange(config.openVal)
+    } else {
+      this.props.onChange(config.closeVal)
+    }
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  render() {
+    const { config } = this.props
+    const { defaultChecked } = this.state
+
+    return (
+      <Switch checkedChildren={config.openText || ''} unCheckedChildren={config.closeText || ''} defaultChecked={defaultChecked} onChange={this.onChange}/>
+    )
+  }
+}
+
+export default MKSwitch
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/mutilform/mkSwitch/index.scss
similarity index 100%
rename from src/tabviews/zshare/mutilform/customSwitch/index.scss
rename to src/tabviews/zshare/mutilform/mkSwitch/index.scss
diff --git a/src/tabviews/zshare/mutilform/mkTextArea/index.jsx b/src/tabviews/zshare/mutilform/mkTextArea/index.jsx
new file mode 100644
index 0000000..531aa49
--- /dev/null
+++ b/src/tabviews/zshare/mutilform/mkTextArea/index.jsx
@@ -0,0 +1,92 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Input } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class MkTextArea extends Component {
+  static propTpyes = {
+    config: PropTypes.bool,
+    onChange: PropTypes.func
+  }
+
+  inputRef = React.createRef()
+
+  state = {
+    value: '',
+    encryption: 'false'
+  }
+
+  UNSAFE_componentWillMount () {
+    const { config } = this.props
+    let _value = config.initval
+    let encryption = 'false'
+
+    if (config.encryption === 'true') {
+      encryption = 'true'
+      if (_value) {
+        try {
+          _value = window.decodeURIComponent(window.atob(_value))
+        } catch {
+          _value = config.initval
+        }
+      }
+    }
+    
+    this.setState({
+      value: _value,
+      encryption
+    })
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('mkFC', this.mkFormHandle)
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkFC', this.mkFormHandle)
+  }
+
+  mkFormHandle = (type, uuid, value) => {
+    if (uuid !== this.props.config.uuid) return
+    if (type === 'focus') {
+      this.inputRef.current.focus()
+    } else if (type === 'input') {
+      this.setState({value})
+    }
+  }
+
+  onChange = (e) => {
+    const { encryption } = this.state
+    let val = e.target.value
+
+    this.setState({ value: val })
+
+    let _val = val
+    if (encryption === 'true') {
+      try {
+        _val = window.btoa(window.encodeURIComponent(_val))
+      } catch {
+        _val = val
+      }
+    }
+    this.props.onChange(_val)
+  }
+
+  render() {
+    const { config } = this.props
+    const { value } = this.state
+
+    return (
+      <TextArea ref={this.inputRef} value={value} autoSize={{ minRows: 2, maxRows: config.maxRows || 6 }} onChange={this.onChange} disabled={config.readonly} />
+    )
+  }
+}
+
+export default MkTextArea
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customTextArea/index.scss b/src/tabviews/zshare/mutilform/mkTextArea/index.scss
similarity index 100%
rename from src/tabviews/zshare/mutilform/customTextArea/index.scss
rename to src/tabviews/zshare/mutilform/mkTextArea/index.scss
diff --git a/src/tabviews/zshare/normalTable/index.jsx b/src/tabviews/zshare/normalTable/index.jsx
index 3746355..aa989fb 100644
--- a/src/tabviews/zshare/normalTable/index.jsx
+++ b/src/tabviews/zshare/normalTable/index.jsx
@@ -17,6 +17,7 @@
 const PopupButton = asyncComponent(() => import('@/tabviews/zshare/actionList/popupbutton'))
 const TabButton = asyncComponent(() => import('@/tabviews/zshare/actionList/tabbutton'))
 const NewPageButton = asyncComponent(() => import('@/tabviews/zshare/actionList/newpagebutton'))
+const ImgScale = asyncComponent(() => import('@/tabviews/zshare/imgScale'))
 
 class NormalTable extends Component {
   static propTpyes = {
@@ -45,7 +46,7 @@
     pageSize: 10,         // 姣忛〉鏁版嵁鏉℃暟
     columns: null,        // 鏄剧ず鍒�
     imgShow: false,       // 鍥剧墖鏀惧ぇ妯℃�佹
-    imgSrc: '',           // 鍥剧墖璺緞
+    imgData: {},          // 鍥剧墖闆�
     lineMarks: null,      // 琛屾爣璁�
     activeIndex: null,    // 鏍囪褰撳墠閫変腑琛�
     rowspans: null        // 琛屽悎骞跺瓧娈典俊鎭�
@@ -139,7 +140,10 @@
         if (item.rowspan === 'true') {
           rowspans.push(item.field)
         }
-        if (_format && !Math.floor(Math.random() * radio)) {
+        if (item.type === 'index') {
+          item.field = '$Index'
+          item.type = 'text'
+        } else if (_format && !Math.floor(Math.random() * radio)) {
           item.blur = true
         }
 
@@ -165,14 +169,6 @@
           render: (text, record) => {
             return this.getContent(item, record)
           }
-        }
-      }
-      
-      if (item.fixed === true || item.fixed === 'true') {
-        if (index < columns.length / 2) {
-          cell.fixed = 'left'
-        } else {
-          cell.fixed = 'right'
         }
       }
       
@@ -552,7 +548,7 @@
       let photos = ''
       if (item.field && record.hasOwnProperty(item.field)) {
         photos = record[item.field] + ''
-        photos = photos.split(',')
+        photos = photos.split(',').filter(Boolean)
       } else {
         photos = ''
       }
@@ -562,7 +558,7 @@
         <div className="picture-col">
           {photos && photos.map((url, i) => {
             if (item.scale === 'true') {
-              return <img style={{maxHeight: maxHeight}} className="image-scale" onClick={this.imgScale} key={`${i}`} src={url} alt=""/>
+              return <img style={{maxHeight: maxHeight}} className="image-scale" onClick={() => this.imgScale(photos, i)} key={`${i}`} src={url} alt=""/>
             } else {
               return <img style={{maxHeight: maxHeight}} key={`${i}`} src={url} alt=""/>
             }
@@ -738,7 +734,7 @@
           let photos = []
           try {
             photos = record[col.field] + ''
-            photos = photos.split(',')
+            photos = photos.split(',').filter(Boolean)
           } catch {
             photos = []
           }
@@ -874,9 +870,8 @@
         <div className="content-fence">
           <div className="content-fence-top" style={images[0] ? {textAlign: images[0].align} : null}>
             {images.map((_img, index) => {
-              if (!_img.url) return ''
               if (_img.scale) {
-                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={this.imgScale} key={`${index}`} src={_img.url} alt=""/>
+                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => this.imgScale(images, index)} key={`${index}`} src={_img.url} alt=""/>
               } else {
                 return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
               }
@@ -894,9 +889,8 @@
         <div className="content-fence">
           <div className="content-fence-left" style={images[0] ? {textAlign: images[0].align} : null}>
             {images.map((_img, index) => {
-              if (!_img.url) return ''
               if (_img.scale) {
-                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={this.imgScale} key={`${index}`} src={_img.url} alt=""/>
+                return <img style={{maxHeight: _img.maxHeight}} className="image-scale" onClick={() => this.imgScale(images, index)} key={`${index}`} src={_img.url} alt=""/>
               } else {
                 return (<img style={{maxHeight: _img.maxHeight}} key={`${index}`} src={_img.url} alt=""/>)
               }
@@ -915,18 +909,19 @@
   /**
    * @description 鍥剧墖缂╂斁
    */
-  imgScaleClose = () => {
+  imgScale = (images, index) => {
     this.setState({
-     imgShow: false
+      imgShow: true,
+      imgData: {
+        list: images.map(item => {
+          if (typeof(item) === 'string') {
+            return item
+          }
+          return item.url
+        }),
+        index
+      }
     })
-  }
-  imgScale = (e) => {
-    if (e.target.nodeName === 'IMG') {
-      this.setState({
-        imgShow: true,
-        imgSrc: e.target.src
-      })
-    }
   }
 
   /**
@@ -1242,12 +1237,12 @@
           visible={this.state.imgShow}
           width="70vw"
           maskClosable={true}
-          onCancel={this.imgScaleClose}
+          onCancel={() => {this.setState({ imgShow: false })}}
           title={this.props.dict['main.form.picture.check']}
-          footer={[<span key="close" onClick={this.imgScaleClose}>{this.props.dict['main.close']}</span>]}
+          footer={[<span key="close" onClick={() => {this.setState({ imgShow: false })}}>{this.props.dict['main.close']}</span>]}
           destroyOnClose
         >
-         <img style={{maxWidth:'100%'}} src={this.state.imgSrc} alt="" />
+          <ImgScale data={this.state.imgData}/>
         </Modal>
       </div>
     )
diff --git a/src/tabviews/zshare/topSearch/advanceform/index.jsx b/src/tabviews/zshare/topSearch/advanceform/index.jsx
new file mode 100644
index 0000000..dd07f57
--- /dev/null
+++ b/src/tabviews/zshare/topSearch/advanceform/index.jsx
@@ -0,0 +1,112 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Row, Col, Input, Button } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const { Search } = Input
+const MKCheckCard = asyncComponent(() => import('@/tabviews/zshare/mutilform/checkCard'))
+const MKSelect = asyncComponent(() => import('../mkSelect'))
+const MKDatePicker = asyncComponent(() => import('../mkDatePicker'))
+
+class AdvanceSearch extends Component {
+  static propTpyes = {
+    record: PropTypes.object,       // 鎼滅储鏉′欢鍊�
+    searchlist: PropTypes.array,    // 鎼滅储鏉′欢鍒楄〃
+    advanceSubmit: PropTypes.func,  // 鎼滅储鏉′欢鎻愪氦
+    handleClose: PropTypes.func     // 鍏抽棴
+  }
+
+  state = {
+    searchlist: fromJS(this.props.searchlist).toJS()
+  }
+
+  getFields() {
+    const { getFieldDecorator } = this.props.form
+    const { record } = this.props
+    const fields = []
+
+    this.state.searchlist.forEach((item, index) => {
+      if (!item.advanced || item.hidden) return
+      
+      const _rules = [
+        {
+          required: item.required,
+          message: item.label + '涓嶅彲涓虹┖!'
+        }
+      ]
+
+      let content = null
+      item.initval = record[item.field] || ''
+
+      if (item.type === 'text') {
+        if (item.inputType === 'search') {
+          content = <Search placeholder={item.labelShow === 'false' ? item.label : ''} autoComplete="off" onSearch={this.handleSubmit} enterButton/>
+        } else {
+          content = <Input placeholder={item.labelShow === 'false' ? item.label : ''} autoComplete="off" onPressEnter={this.handleSubmit} />
+        }
+      } else if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') {
+        content = (<MKSelect config={item}/>)
+      } else if (item.type === 'date' || item.type === 'datemonth' || item.type === 'dateweek' || item.type === 'daterange') {
+        content = (<MKDatePicker config={item}/>)
+      } else if (item.type === 'checkcard') {
+        content = <MKCheckCard card={item}/>
+      }
+
+      if (content) {
+        fields.push(
+          <Col span={item.ratio || 6} key={index}>
+            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
+              {getFieldDecorator(item.field, {
+                initialValue: item.initval,
+                rules: _rules
+              })(content)}
+            </Form.Item>
+          </Col>
+        )
+      }
+    })
+    
+    return fields
+  }
+
+  handleSubmit = () => {
+    // 鍥炶溅鎴栫偣鍑绘悳绱�
+    this.props.form.validateFields((err, values) => {
+      if (err) return
+        
+      this.props.advanceSubmit(values)
+    })
+  }
+
+  render() {
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+
+    return (
+      <Form {...formItemLayout} className="advance-search">
+        <Row gutter={24}>{this.getFields()}</Row>
+        <div className="advance-button">
+          <Button style={{ marginRight: 8 }} onClick={this.props.handleClose}>
+            鍏抽棴
+          </Button>
+          <Button type="primary" onClick={this.handleSubmit}>
+            纭畾
+          </Button>
+        </div>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(AdvanceSearch)
\ No newline at end of file
diff --git a/src/tabviews/zshare/topSearch/advanceform/index.scss b/src/tabviews/zshare/topSearch/advanceform/index.scss
new file mode 100644
index 0000000..74b0bca
--- /dev/null
+++ b/src/tabviews/zshare/topSearch/advanceform/index.scss
@@ -0,0 +1,41 @@
+.advance-search {
+  background: #ffffff;
+  margin-bottom: 35px;
+  .ant-form-item {
+    display: flex;
+    margin-bottom: 0px;
+    min-height: 60px;
+    .ant-form-explain {
+      white-space: nowrap;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    flex: 1;
+    width: calc(100% - 100px);
+  }
+  .ant-form-item-label {
+    text-overflow: ellipsis;
+  }
+  .daterange .ant-calendar-picker-input {
+    padding: 4px 20px 4px 5px;
+    font-size: 13px;
+  }
+  .ant-select-dropdown {
+    z-index: 10 !important;
+  }
+  .ant-calendar-picker-container {
+    z-index: 10 !important;
+  }
+  .check-card-form-box {
+    margin-top: 5px;
+  }
+  .advance-button {
+    position: absolute;
+    left: 0;
+    bottom: 0;
+    width: 100%;
+    text-align: right;
+    padding: 10px;
+    border-top: 1px solid #f0f0f0;
+  }
+}
\ No newline at end of file
diff --git a/src/tabviews/zshare/topSearch/dategroup/index.jsx b/src/tabviews/zshare/topSearch/dategroup/index.jsx
new file mode 100644
index 0000000..ab2b3a2
--- /dev/null
+++ b/src/tabviews/zshare/topSearch/dategroup/index.jsx
@@ -0,0 +1,138 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { DatePicker, Tooltip, Icon } from 'antd'
+import moment from 'moment'
+
+import Utils from '@/utils/utils.js'
+import QuarterPicker from './quarterpicker'
+import YearPicker from './yearpicker'
+import './index.scss'
+
+const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+
+class DateGroup extends Component {
+  static propTpyes = {
+    config: PropTypes.object,
+    position: PropTypes.number,     // 绱㈠紩锛岀敤浜庢帶鍒跺搴﹀拰骞寸殑灞曞紑鏂瑰悜
+    onChange: PropTypes.func
+  }
+
+  state = {
+    active: '',
+    quarterId: Utils.getuuid(),
+    yearId: Utils.getuuid(),
+    dateRange: '',
+    placement: this.props.position % 4 !== 3 ? 'bottomLeft' : 'bottomRight'
+  }
+
+  UNSAFE_componentWillMount() {
+    const { config } = this.props
+
+    this.setState({
+      active: config.initType,
+      dateRange: config.initval
+    })
+  }
+
+  onChange = (date, type) => {
+    let values = []
+    if (type === 'day') {
+      values = [moment(date).format('YYYY-MM-DD'), moment(date).format('YYYY-MM-DD')]
+    } else if (type === 'week') {
+      values = [moment(date).startOf('week').format('YYYY-MM-DD'), moment(date).endOf('week').format('YYYY-MM-DD')]
+    } else if (type === 'month') {
+      values = [moment(date).startOf('month').format('YYYY-MM-DD'), moment(date).endOf('month').format('YYYY-MM-DD')]
+    } else if (type === 'quarter') {
+      values = date
+      document.getElementById(this.state.quarterId).click()
+    } else if (type === 'year') {
+      values = date
+      document.getElementById(this.state.yearId).click()
+    } else if (type === 'customized') {
+      values = [moment(date[0]).format('YYYY-MM-DD'), moment(date[1]).format('YYYY-MM-DD')]
+    }
+
+    values = values.join(',')
+
+    this.setState({
+      active: type,
+      dateRange: values
+    }, () => {
+      this.props.onChange(values, type)
+    })
+  }
+
+  clearTime = () => {
+    this.setState({
+      active: '',
+      dateRange: ''
+    }, () => {
+      this.props.onChange('', '')
+    })
+  }
+
+  render() {
+    const { config } = this.props
+    const { active, quarterId, yearId, dateRange, placement } = this.state
+    let tabs = {day: '鏃�', week: '鍛�', month: '鏈�', quarter: '瀛�', year: '骞�', customized: '鑷畾涔�'}
+
+    return (
+      <div className="table-search-date-group">
+        {config.items.map(tab => {
+          if (tab === 'day') {
+            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+              {tabs[tab]}
+              <DatePicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
+            </span>)
+          } else if (tab === 'week') {
+            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+              {tabs[tab]}
+              <WeekPicker dropdownClassName="group-week-picker" allowClear={false} onChange={(date) => this.onChange(date, tab)} />
+            </span>)
+          } else if (tab === 'month') {
+            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+              {tabs[tab]}
+              <MonthPicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
+            </span>)
+          } else if (tab === 'quarter') {
+            return (
+              <Tooltip key={tab} placement={placement} overlayClassName={'quarter-picker-tooltip ' + placement} trigger="click" title={
+                <div>
+                  <QuarterPicker card={config} onChange={(date) => this.onChange(date, tab)}/>
+                </div>
+              }>
+                <span id={quarterId} className={'ant-tag ant-tag-quarter ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+                  {tabs[tab]}
+                </span>
+              </Tooltip>
+            )
+          } else if (tab === 'year') {
+            return (
+              <Tooltip key={tab} placement={placement} overlayClassName={'year-picker-tooltip ' + placement} trigger="click" title={
+                <div>
+                  <YearPicker card={config} onChange={(date) => this.onChange(date, tab)}/>
+                </div>
+              }>
+                <span id={yearId} className={'ant-tag ant-tag-quarter ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+                  {tabs[tab]}
+                </span>
+              </Tooltip>
+            )
+          } else {
+            return (<span key={tab} className={'ant-tag ant-tag-checkable ' + (active === tab ? 'ant-tag-checkable-checked' : '')} >
+              {tabs[tab]}
+              <RangePicker allowClear={false} onChange={(date) => this.onChange(date, tab)} />
+            </span>)
+          }
+        })}
+        
+        {dateRange ? <div className="table-search-date-group-value">
+          {dateRange.replace(',', ' ~ ')}
+          <Icon type="close-circle" onClick={this.clearTime} className="ant-calendar-picker-clear" />
+        </div> : null}
+      </div>
+    )
+  }
+}
+
+export default DateGroup
\ No newline at end of file
diff --git a/src/tabviews/zshare/dategroup/index.scss b/src/tabviews/zshare/topSearch/dategroup/index.scss
similarity index 100%
rename from src/tabviews/zshare/dategroup/index.scss
rename to src/tabviews/zshare/topSearch/dategroup/index.scss
diff --git a/src/tabviews/zshare/dategroup/quarterpicker/index.jsx b/src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.jsx
similarity index 100%
rename from src/tabviews/zshare/dategroup/quarterpicker/index.jsx
rename to src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.jsx
diff --git a/src/tabviews/zshare/dategroup/quarterpicker/index.scss b/src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.scss
similarity index 100%
rename from src/tabviews/zshare/dategroup/quarterpicker/index.scss
rename to src/tabviews/zshare/topSearch/dategroup/quarterpicker/index.scss
diff --git a/src/tabviews/zshare/dategroup/yearpicker/index.jsx b/src/tabviews/zshare/topSearch/dategroup/yearpicker/index.jsx
similarity index 100%
rename from src/tabviews/zshare/dategroup/yearpicker/index.jsx
rename to src/tabviews/zshare/topSearch/dategroup/yearpicker/index.jsx
diff --git a/src/tabviews/zshare/dategroup/yearpicker/index.scss b/src/tabviews/zshare/topSearch/dategroup/yearpicker/index.scss
similarity index 100%
rename from src/tabviews/zshare/dategroup/yearpicker/index.scss
rename to src/tabviews/zshare/topSearch/dategroup/yearpicker/index.scss
diff --git a/src/tabviews/zshare/topSearch/index.jsx b/src/tabviews/zshare/topSearch/index.jsx
index 79a77e4..c16a881 100644
--- a/src/tabviews/zshare/topSearch/index.jsx
+++ b/src/tabviews/zshare/topSearch/index.jsx
@@ -1,18 +1,25 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Form, Row, Col, Input, Button, Select, DatePicker, notification } from 'antd'
+import { Form, Row, Col, Input, Button, notification, Modal, Icon } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
 import options from '@/store/options.js'
-import DateGroup from '@/tabviews/zshare/dategroup'
+import asyncComponent from '@/utils/asyncComponent'
+import asyncSpinComponent from '@/utils/asyncSpinComponent'
 import Utils from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/main.js'
 import enUS from '@/locales/en-US/main.js'
 import './index.scss'
 
-const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+const { Search } = Input
+
+const MutilForm = asyncSpinComponent(() => import('./advanceform'))
+const MKCheckCard = asyncComponent(() => import('@/tabviews/zshare/mutilform/checkCard'))
+const MKSelect = asyncComponent(() => import('./mkSelect'))
+const DateGroup = asyncComponent(() => import('./dategroup'))
+const MKDatePicker = asyncComponent(() => import('./mkDatePicker'))
 
 class MainSearch extends Component {
   static propTpyes = {
@@ -20,33 +27,30 @@
     menuType: PropTypes.any,     // 鑿滃崟鏉冮檺锛屾槸鍚︿负HS
     searchlist: PropTypes.array, // 鎼滅储鏉′欢鍒楄〃
     config: PropTypes.object,    // 缁勪欢閰嶇疆淇℃伅(鑷畾涔夐〉闈�)
+    setting: PropTypes.object,   // 缁勪欢閰嶇疆淇℃伅(鑷畾涔夐〉闈�)
     refreshdata: PropTypes.func  // 鍒锋柊鏁版嵁
   }
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    oriId: Utils.getuuid(),  // 鎼滅储琛ㄥ崟Id
-    formId: '',              // 鎼滅储琛ㄥ崟Id
-    match: null,             // 鎼滅储鏉′欢鍖归厤瑙勫垯
-    style: null,             // 鎼滅储鏉′欢绫诲瀷
-    label: null,             // 鎻愮ず鏂囧瓧
-    required: null,          // 鏄惁蹇呭~
     searchlist: null,        // 鎼滅储椤�
-    groups: null,            // 缁勫悎鎼滅储椤�
+    reset: true,             // 鎺у埗缁勫悎鎼滅储椤归噸缃�
     float: '',               // 娴姩
     showButton: true,        // 鏄惁鏄剧ず鎼滅储鎸夐挳
-    searchStyle: null        // 鎼滅储鏉′欢鏍峰紡
+    showAdvanced: false,     // 鏄惁鏄剧ず楂樼骇鎼滅储
+    searchStyle: null,       // 鎼滅储鏉′欢鏍峰紡
+    advanceValues: [],       // 楂樼骇鎼滅储鏉′欢淇濆瓨鍊�
+    visible: false,
+    adModelWidth: '1000px',
+    hasReqFields: false
   }
 
+  record = {}
+
   UNSAFE_componentWillMount () {
-    const { config, menuType, searchlist } = this.props
+    const { config, menuType, searchlist, setting } = this.props
 
     let _searchlist = []
-    let match = {}
-    let label = {}
-    let style = {}
-    let required = {}
-    let _list = []
     let fieldMap = new Map()
     let mainItems = []  // 浜戠鎴栧崟鐐规暟鎹�
     let localItems = [] // 鏈湴鏁版嵁
@@ -54,7 +58,24 @@
     let float = ''
     let showButton = true
     let searchStyle = null
-    let formId = Utils.getuuid()
+    let advanceValues = []
+    let showAdvanced = false
+    let adModelWidth = 1000
+    let linkFields = {}
+    let record = {}
+    let hasReqFields = false
+
+    if (setting && setting.advanceWidth) {
+      adModelWidth = setting.advanceWidth
+    } else if (config && config.wrap && config.wrap.advanceWidth) {
+      adModelWidth = config.wrap.advanceWidth
+    }
+
+    if (adModelWidth < 100) {
+      adModelWidth = adModelWidth + 'vw'
+    } else {
+      adModelWidth = adModelWidth + 'px'
+    }
 
     if (searchlist) {
       _searchlist = fromJS(searchlist).toJS()
@@ -62,28 +83,48 @@
       _searchlist = fromJS(config.search).toJS()
       if (config.type === 'search' && config.subtype === 'mainsearch') {
         float = config.wrap.float
-        showButton = config.wrap.float === 'left' && config.wrap.show === 'true'
+        showButton = config.wrap.show !== 'false'
         searchStyle = config.style
       } else {
-        formId = ''
         showButton = false
         float = 'right'
       }
     }
 
     _searchlist.forEach(item => {
+      if (item.type === 'link') {
+        linkFields[item.linkField] = linkFields[item.linkField] || []
+        linkFields[item.linkField].push({field: item.field, uuid: item.uuid})
+      }
+
       if (fieldMap.has(item.field)) {
         item.field = item.field + '@tail@'
       }
-      fieldMap.set(item.field, item)
 
-      match[item.field] = item.match
-      label[item.field] = item.label
-      style[item.field] = item.type
-      required[item.field] = item.required === 'true'
+      if (item.required) {
+        hasReqFields = true
+      }
 
-      if (['select', 'link', 'multiselect'].includes(item.type)) {
-        if (item.setAll === 'true' && item.type !== 'multiselect') {
+      if (showButton && item.advanced) {
+        showAdvanced = true
+      } else {
+        item.advanced = false
+      }
+
+      if (item.advanced && item.initval) {
+        advanceValues.push({field: item.field, type: item.type, label: item.label, value: item.initval})
+      }
+
+      if (item.type === 'group') {
+        record[item.field] = item.initType
+        record[item.datefield] = item.initval
+      } else {
+        record[item.field] = item.initval
+      }
+      
+      if (['select', 'link', 'multiselect', 'checkcard'].includes(item.type)) {
+        item.options = item.options || []
+        if (item.setAll === 'true' && ['select', 'link'].includes(item.type)) {
           item.options.unshift({
             key: Utils.getuuid(),
             Value: '',
@@ -103,10 +144,6 @@
               data_sql: Utils.formatOptions(_option.sql)
             })
           } else { // 鍚堝苟璇锋眰锛屽尯鍒嗘湰鍦板強绯荤粺
-            // 澶栬仈鏁版嵁搴撴浛鎹�
-            if (window.GLOB.externalDatabase !== null) {
-              _option.sql = _option.sql.replace(/@db@/ig, window.GLOB.externalDatabase)
-            }
             if (item.database === 'sso') {
               mainItems.push(`select '${item.field}' as obj_name,'${_option.field}' as arr_field,'${window.btoa(window.encodeURIComponent(_option.sql))}' as LText`)
             } else {
@@ -117,11 +154,18 @@
         item.oriOptions = fromJS(item.options).toJS()
       }
 
-      _list.push(item)
+      fieldMap.set(item.field, item)
     })
 
-    let _groups = []
-    _list = _list.map(item => {
+    this.record = record
+
+    let _list = _searchlist.map(item => {
+      if (item.hidden) return item
+
+      if (linkFields[item.field]) {
+        item.linkFields = linkFields[item.field]
+      }
+
       if (item.type === 'link') {
         let supItem = fieldMap.get(item.linkField)
         
@@ -131,29 +175,25 @@
             message: '鏈煡璇㈠埌鎼滅储鏉′欢銆�' + item.label + '銆嬪叧鑱斿瓧娈碉紒',
             duration: 5
           })
-          item.supInitVal = ''
+          item.type = 'select'
         } else {
           item.supInitVal = supItem.initval
           item.options = item.oriOptions.filter(option => option.ParentID === supItem.initval || option.Value === '')
         }
-      } else if (item.type === 'group' && item.Hide !== 'true') {
-        _groups.push(fromJS(item).toJS())
       }
 
       return item
     })
 
     this.setState({
-      match,
-      label,
-      style,
       float,
-      formId,
-      required,
       showButton,
       searchStyle,
-      searchlist: _list,
-      groups: _groups
+      hasReqFields,
+      showAdvanced,
+      adModelWidth,
+      advanceValues,
+      searchlist: _list
     }, () => {
       if (menuType !== 'HS' && options.sysType === 'local' && !window.GLOB.systemType) {
         this.improveSimpleSearch(deForms)
@@ -264,42 +304,7 @@
       delete result.message
       delete result.status
 
-      let _searchlist = this.state.searchlist.map(item => {
-        if (['select', 'link', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
-          let options = result[item.field].map(cell => {
-            let _item = {
-              key: Utils.getuuid(),
-              Value: cell[item.valueField],
-              Text: cell[item.valueText]
-            }
-
-            if (item.type === 'link') {
-              _item.ParentID = cell[item.linkField]
-            }
-
-            return _item
-          })
-
-          item.oriOptions = [...item.oriOptions, ...options]
-        }
-        return item
-      })
-
-      this.setState({
-        searchlist: _searchlist.map(item => {
-          if (item.type === 'link') {
-            if (item.supInitVal) {
-              item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-            } else {
-              item.options = item.oriOptions
-            }
-          } else if (item.type === 'select' || item.type === 'multiselect') {
-            item.options = item.oriOptions
-          }
-
-          return item
-        })
-      })
+      this.resetSearch(result)
     })
   }
 
@@ -350,283 +355,119 @@
       delete result.message
       delete result.status
 
-      let _searchlist = this.state.searchlist.map(item => {
-        if (['select', 'link', 'multiselect'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
-          let options = result[item.field].map(cell => {
-            let _item = {
-              key: Utils.getuuid(),
-              Value: cell[item.valueField],
-              Text: cell[item.valueText]
-            }
+      this.resetSearch(result)
+    })
+  }
 
-            if (item.type === 'link') {
-              _item.ParentID = cell[item.linkField]
-            }
+  resetSearch = (result) => {
+    let _searchlist = this.state.searchlist.map(item => {
+      if (['select', 'link', 'multiselect', 'checkcard'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
+        let options = result[item.field].map(cell => {
+          let _item = {
+            key: Utils.getuuid()
+          }
 
-            return _item
-          })
+          if (item.type !== 'checkcard') {
+            _item.Value = cell[item.valueField]
+            _item.Text = cell[item.valueText]
+          } else {
+            _item.$value = cell[item.cardValField]
+            _item = {..._item, ...cell}
+          }
 
-          item.oriOptions = [...item.oriOptions, ...options]
-        }
-        return item
-      })
-
-      this.setState({
-        searchlist: _searchlist.map(item => {
           if (item.type === 'link') {
-            if (item.supInitVal) {
-              item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
-            } else {
-              item.options = item.oriOptions
-            }
-          } else if (item.type === 'select' || item.type === 'multiselect') {
-            item.options = item.oriOptions
+            _item.ParentID = cell[item.linkField]
           }
 
-          return item
+          return _item
         })
-      })
-    })
-  }
 
-  resetform = (formlist, supfields, index, fieldsvalue) => {
-    index++
-    let subfields = []
-
-    supfields.forEach(supfield => {
-      formlist = formlist.map(item => {
-        if (item.type === 'link' && item.linkField === supfield.field) {
-          item.options = item.oriOptions.filter(option => option.ParentID === supfield.initval || option.Value === '')
-          item.initval = item.options[0] ? item.options[0].Value : ''
-          
-          if (this.props.form.getFieldValue(item.field) !== undefined) {
-            fieldsvalue[item.field] = item.initval
-          }
-  
-          subfields.push(item)
-        }
-        return item
-      })
-    })
-
-    if (subfields.length === 0 || index > 6) {
-      return formlist
-    } else {
-      return this.resetform(formlist, subfields, index, fieldsvalue)
-    }
-  }
-
-  selectChange = (_field, value) => {
-    let formlist = fromJS(this.state.searchlist).toJS()
-
-    let subfields = []
-    let fieldsvalue = {}
-    formlist = formlist.map(item => {
-      if (item.type === 'link' && item.linkField === _field.field) {
-        item.options = item.oriOptions.filter(option => option.ParentID === value || option.Value === '')
-        item.initval = item.options[0] ? item.options[0].Value : ''
-
-        if (this.props.form.getFieldValue(item.field) !== undefined) {
-          fieldsvalue[item.field] = item.initval
-        }
-
-        subfields.push(item)
+        item.oriOptions = [...item.oriOptions, ...options]
       }
       return item
     })
 
-    if (subfields.length === 0) {
-      this.searchChange()
-      return
-    }
-
-    formlist = this.resetform(formlist, subfields, 0, fieldsvalue)
-
-    if (Object.keys(fieldsvalue).length > 0) {
-      this.props.form.setFieldsValue(fieldsvalue)
-    }
-
     this.setState({
-      searchlist: formlist
-    }, () => {
-      this.searchChange()
+      searchlist: _searchlist.map(item => {
+        if (item.type === 'link') {
+          if (item.supInitVal) {
+            item.options = item.oriOptions.filter(option => option.ParentID === item.supInitVal || option.Value === '')
+          } else {
+            item.options = item.oriOptions
+          }
+        } else if (item.type === 'select' || item.type === 'multiselect' || item.type === 'checkcard') {
+          item.options = item.oriOptions
+        }
+
+        return item
+      })
     })
+  }
+
+  recordChange = (val, defer, item) => {
+    this.record[item.field] = val
+
+    if (defer) return
+
+    if (item.linkFields) {
+      setTimeout(() => {
+        this.handleSubmit()
+      }, 1000)
+    } else {
+      this.handleSubmit()
+    }
+  }
+
+  dateGroupChange = (val, type, item) => {
+    this.record[item.datefield] = val
+    this.record[item.field] = type
+
+    this.handleSubmit()
   }
 
   getFields() {
     const { getFieldDecorator } = this.props.form
-    const { dict, showButton, formId } = this.state
+    const { dict, showButton, showAdvanced, float } = this.state
     const fields = []
 
     this.state.searchlist.forEach((item, index) => {
-      if (item.Hide === 'true') return
-      
-      if (item.type === 'text') { // 鏂囨湰鎼滅储
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.input'] + item.label + '!'
-                  }
-                ]
-              })(<Input placeholder={item.labelShow === 'false' ? item.label : ''} autoComplete="off" onPressEnter={this.handleSearch} />)}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'select') { // 涓嬫媺鎼滅储
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Select
-                  showSearch
-                  onChange={(value) => {this.selectChange(item, value)}}
-                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                  getPopupContainer={() => formId ? document.getElementById(formId) : document.body}
-                >
-                  {item.options.map((option, i) =>
-                    <Select.Option id={`${i}`} title={option.Text} key={`${i}`} value={option.Value}>{option.Text}</Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'multiselect') { // 涓嬫媺澶氶��
-        let _initval = item.initval ? item.initval.split(',').filter(Boolean) : []
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: _initval,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <Select
-                  showSearch
-                  mode="multiple"
-                  onChange={this.searchChange}
-                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
-                  getPopupContainer={() => formId ? document.getElementById(formId) : document.body}
-                >
-                  {item.options.map((option, i) =>
-                    <Select.Option id={`${i}`} title={option.Text} key={`${i}`} value={option.Value}>{option.Text}</Select.Option>
-                  )}
-                </Select>
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'date') { // 鏃堕棿鎼滅储
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval ? moment().subtract(item.initval, 'days') : null,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <DatePicker onChange={this.searchChange} getCalendarContainer={() => formId ? document.getElementById(formId) : document.body} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'datemonth') {
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval ? moment().subtract(item.initval, 'month') : null,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <MonthPicker onChange={this.searchChange} getCalendarContainer={() => formId ? document.getElementById(formId) : document.body} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'dateweek') {
-        fields.push(
-          <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field, {
-                initialValue: item.initval ? moment().subtract(item.initval * 7, 'days') : null,
-                rules: [
-                  {
-                    required: item.required === 'true',
-                    message: dict['form.required.select'] + item.label + '!'
-                  }
-                ]
-              })(
-                <WeekPicker onChange={this.searchChange} getCalendarContainer={() => formId ? document.getElementById(formId) : document.body} />
-              )}
-            </Form.Item>
-          </Col>
-        )
-      } else if (item.type === 'daterange') {
-        let _defaultValue = [null, null]
+      if (item.hidden || item.advanced) return
 
-        if (item.initval) {
-          try {
-            let _initval = JSON.parse(item.initval)
-            _defaultValue = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
-          } catch {
-            _defaultValue = [null, null]
-          }
+      const _rules = [
+        {
+          required: item.required,
+          message: item.label + '涓嶅彲涓虹┖!'
         }
+      ]
 
-        fields.push(
-          <Col className="daterange" span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
-              {getFieldDecorator(item.field,
-                {
-                  initialValue: _defaultValue,
-                  rules: [
-                    {
-                      required: item.required === 'true',
-                      message: dict['form.required.select'] + item.label + '!'
-                    }
-                  ]
-                })(
-                <RangePicker
-                  placeholder={['寮�濮嬫棩鏈�', '缁撴潫鏃ユ湡']}
-                  renderExtraFooter={() => 'extra footer'}
-                  onChange={this.searchChange}
-                  getCalendarContainer={() => formId ? document.getElementById(formId) : document.body}
-                />
-              )}
-            </Form.Item>
-          </Col>
-        )
+      let content = null
+      let field = item.field
+
+      if (item.type === 'text') {
+        if (item.inputType === 'search') {
+          content = <Search placeholder={item.labelShow === 'false' ? item.label : ''} autoComplete="off" onSearch={this.handleSubmit} enterButton/>
+        } else {
+          content = <Input placeholder={item.labelShow === 'false' ? item.label : ''} autoComplete="off" onPressEnter={this.handleSubmit} />
+        }
+      } else if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') {
+        content = (<MKSelect config={item} onChange={(val, defer) => this.recordChange(val, defer, item)} />)
+      } else if (item.type === 'date' || item.type === 'datemonth' || item.type === 'dateweek' || item.type === 'daterange') {
+        content = (<MKDatePicker config={item} onChange={(val) => this.recordChange(val, false, item)} />)
       } else if (item.type === 'group') {
+        field = item.datefield
+        content = <DateGroup position={index} config={item} onChange={(val, type) => this.dateGroupChange(val, type, item)} />
+      } else if (item.type === 'checkcard') {
+        content = <MKCheckCard card={item} onChange={this.handleSubmit} />
+      }
+
+      if (content) {
         fields.push(
           <Col span={item.ratio || 6} key={index}>
-            <Form.Item label={item.labelShow !== 'false' ? item.label : ''} className={item.required === 'true' ? 'group-required' : ''}>
-              <DateGroup ref={item.uuid} position={index} card={item} onGroupChange={this.searchChange} />
+            <Form.Item label={item.labelShow !== 'false' ? item.label : ''}>
+              {getFieldDecorator(field, {
+                initialValue: item.initval,
+                rules: _rules
+              })(content)}
             </Form.Item>
           </Col>
         )
@@ -634,78 +475,58 @@
     })
 
     if (showButton) {
-      fields.push(
+      let action = (
         <Col span={6} style={{ whiteSpace: 'nowrap' }} className="search-button" key="actions">
           <Form.Item label={' '} colon={false} style={{ minHeight: '40px' }}>
-            <Button type="primary" onClick={this.handleSearch}>
+            <Button type="primary" onClick={this.handleSubmit}>
               {dict['main.search']}
             </Button>
             <Button style={{ marginLeft: 8 }} onClick={this.handleReset}>
               {dict['main.reset']}
             </Button>
+            {showAdvanced ? <Button type="link" onClick={this.handleAdvance}>
+              楂樼骇
+            </Button> : null}
           </Form.Item>
         </Col>
       )
+      if (float === 'right') {
+        fields.unshift(action)
+      } else {
+        fields.push(action)
+      }
     }
     
     return fields
   }
 
-  addHideFieldValue = (values) => {
-    const { searchlist } = this.state
-    let hideValue = {}
-    searchlist.forEach(item => {
-      if (item.Hide === 'true') {
-        let value = ''
-
-        if (item.type === 'multiselect') { // 涓嬫媺澶氶��
-          value = item.initval ? item.initval.split(',').filter(Boolean) : []
-        } else if (item.type === 'date') { // 鏃堕棿鎼滅储
-          value = item.initval ? moment().subtract(item.initval, 'days') : ''
-        } else if (item.type === 'datemonth') {
-          value = item.initval ? moment().subtract(item.initval, 'month') : ''
-        } else if (item.type === 'dateweek') {
-          value = item.initval ? moment().subtract(item.initval * 7, 'days') : ''
-        } else if (item.type === 'daterange') {
-          if (item.initval) {
-            try {
-              let _initval = JSON.parse(item.initval)
-              value = [moment().subtract(_initval[0], 'days'), moment().subtract(_initval[1], 'days')]
-            } catch {
-              value = ''
-            }
-          }
-        } else if (item.type !== 'group') {
-          value = item.initval
-        }
-
-        hideValue[item.field] = value
-      }
-    })
-
-    return {...hideValue, ...values}
+  handleAdvance = () => {
+    this.setState({visible: true})
   }
 
-  handleSearch = (e) => {
-    // 鍥炶溅鎴栫偣鍑绘悳绱�
-    e.preventDefault()
-    this.props.form.validateFields((err, values) => {
-      if (!err) {
-        values = this.addHideFieldValue(values)
-        let searches = this.getFieldsValues(values)
-        this.props.refreshdata(searches)
-      }
-    })
-  }
-
-  searchChange = () => {
+  handleSubmit = () => {
     this.setState({}, () => {
       this.props.form.validateFields((err, values) => {
-        if (!err) {
-          values = this.addHideFieldValue(values)
-          let searches = this.getFieldsValues(values)
-          this.props.refreshdata(searches)
+        if (err) return
+  
+        let searches = this.getFieldsValues(values)
+  
+        if (this.state.hasReqFields) {
+          let requireFields = searches.filter(item => item.required && item.value === '')
+          if (requireFields.length > 0) {
+            let labels = requireFields.map(item => item.label)
+            labels = Array.from(new Set(labels))
+      
+            notification.warning({
+              top: 92,
+              message: this.state.dict['form.required.input'] + labels.join('銆�') + ' !',
+              duration: 3
+            })
+            return
+          }
         }
+
+        this.props.refreshdata(searches)
       })
     })
   }
@@ -714,87 +535,109 @@
    * @description 鎼滅储鏉′欢閲嶇疆
    */
   handleReset = () => {
-    const { groups } = this.state
-
-    if (groups.length > 0) {
-      groups.forEach(item => {
-        this.refs[item.uuid].reset()
-      })
-    }
-
+    let record = {}
+    let advanceValues = []
     let searchlist = this.state.searchlist.map(item => {
       item.initval = item.oriInitval
+
+      if (item.type === 'group') {
+        record[item.datefield] = item.initval
+        record[item.field] = item.initType
+      } else {
+        record[item.field] = item.initval
+      }
+      if (item.advanced && item.initval) {
+        advanceValues.push({field: item.field, type: item.type, label: item.label, value: item.initval})
+      }
+
       return item
     })
 
-    this.setState({searchlist}, () => {
-      this.props.form.resetFields()
-      this.props.form.validateFields((err, values) => {
-        if (!err) {
-          // 寮傛鑾峰彇鏇存柊鍚庣殑鏃堕棿缁�
-          this.setState({}, () => {
-            values = this.addHideFieldValue(values)
-            let searches = this.getFieldsValues(values)
-            this.props.refreshdata(searches)
-          })
-        }
+    this.record = record
+
+    this.setState({searchlist: [], advanceValues}, () => {
+      this.setState({searchlist}, () => {
+        this.handleSubmit()
       })
     })
   }
 
-  getFieldsValues = (values) => {
-    const { groups } = this.state
+  getFieldsValues = (vals) => {
+    const { searchlist } = this.state
+    let values = {...this.record, ...vals}
+    this.record = values
+
     // 鑾峰彇鎼滅储鏉′欢鍊�
     let search = []
-    Object.keys(values).forEach(key => {
-      let _value = ''
-      if (this.state.style[key] === 'daterange') {
-        if (values[key].length > 0 && values[key][0] && values[key][1]) {
-          _value = [moment(values[key][0]).format('YYYY-MM-DD'), moment(values[key][1]).format('YYYY-MM-DD')]
-        }
-      } else if (this.state.style[key] === 'dateweek') {
-        if (values[key]) {
-          _value = [moment(values[key]).startOf('week').format('YYYY-MM-DD'), moment(values[key]).endOf('week').format('YYYY-MM-DD')]
-        }
-      } else if (this.state.style[key] === 'date') {
-        if (values[key]) {
-          _value = moment(values[key]).format('YYYY-MM-DD')
-        }
-      } else if (this.state.style[key] === 'datemonth') {
-        if (values[key]) {
-          _value = moment(values[key]).format('YYYY-MM')
-        }
-      } else if (this.state.style[key] === 'multiselect') {
-        _value = values[key] || []
-
+    searchlist.forEach(item => {
+      if (item.type === 'group') {
+        search.push({
+          type: 'daterange',
+          key: item.datefield,
+          value: values[item.datefield] || '',
+          label: item.label,
+          match: 'between',
+          required: item.required
+        }, {
+          type: 'group',
+          key: item.field,
+          value: values[item.field] || '',
+          label: item.label,
+          match: '=',
+          forbid: true,
+          required: item.required
+        })
       } else {
-        _value = (values[key] || values[key] === 0) ? values[key] : ''
+        let type = item.type
+        if (type === 'multiselect' || (type === 'checkcard' && item.multiple === 'true')) {
+          type = 'multi'
+        }
+        let val = values[item.field] !== undefined ? values[item.field] : ''
 
-        _value = _value.replace(/(^\s*|\s*$)/ig, '')
+        if (typeof(val) === 'string') {
+          val = val.replace(/(^\s*|\s*$)/ig, '')
+        }
+
+        search.push({
+          type: type,
+          key: item.field.replace(/@tail@$/, ''),
+          value: val,
+          label: item.label,
+          match: item.match,
+          required: item.required
+        })
       }
-
-      search.push({
-        type: this.state.style[key],
-        key: key.replace(/@tail@$/, ''),
-        value: _value,
-        label: this.state.label[key],
-        match: this.state.match[key],
-        required: this.state.required[key]
-      })
     })
-
-    if (groups.length > 0) {
-      groups.forEach(item => {
-        let items = this.refs[item.uuid].getSearchItems()
-        search.push(...items)
-      })
-    }
 
     return search
   }
 
+  handleOk = (values) => {
+    this.record = {...this.record, ...values}
+
+    let advanceValues = []
+    this.state.searchlist.forEach(item => {
+      if (!item.advanced) return
+
+      let val = this.record[item.field]
+      if (val || val === 0) {
+        advanceValues.push({field: item.field, type: item.type, label: item.label, value: val})
+      }
+    })
+
+    this.setState({advanceValues, visible: false})
+    this.handleSubmit()
+  }
+
+  closeAdvanceForm = (cell) => {
+    this.record[cell.field] = ''
+
+    this.setState({advanceValues: this.state.advanceValues.filter(item => item.field !== cell.field)})
+    this.handleSubmit()
+  }
+
   render() {
-    const { float, searchStyle } = this.state
+    const { float, searchStyle, visible, searchlist, showAdvanced, advanceValues, adModelWidth } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -807,9 +650,39 @@
     }
 
     return (
-      <Form {...formItemLayout} className={`top-search ${float}`} style={searchStyle} id={this.state.formId || this.state.oriId}>
-        <Row gutter={24}>{this.getFields()}</Row>
-      </Form>
+      <>
+        <Form {...formItemLayout} className={`top-search ${float}`} style={searchStyle}>
+          <Row gutter={24}>{this.getFields()}</Row>
+          <Row gutter={24}>
+            {showAdvanced ? <div className="advanced-list">
+              {advanceValues.map((item, index) => {
+                return (
+                  <div key={index}>
+                    <span>{item.label}: </span>
+                    <span className="advance-value">{item.value}</span>
+                    <Icon type="close" onClick={() => this.closeAdvanceForm(item)} />
+                  </div>)
+              })}
+            </div> : null}
+          </Row>
+        </Form>
+        <Modal
+          title="楂樼骇鎼滅储"
+          maskClosable={false}
+          visible={visible}
+          width={adModelWidth}
+          closable={false}
+          footer={null}
+          destroyOnClose
+        >
+          <MutilForm
+            searchlist={searchlist}
+            record={this.record}
+            advanceSubmit={this.handleOk}
+            handleClose={() => this.setState({visible: false})}
+          />
+        </Modal>
+      </>
     )
   }
 }
diff --git a/src/tabviews/zshare/topSearch/index.scss b/src/tabviews/zshare/topSearch/index.scss
index 9388a99..f5378b0 100644
--- a/src/tabviews/zshare/topSearch/index.scss
+++ b/src/tabviews/zshare/topSearch/index.scss
@@ -36,6 +36,37 @@
       content: '*';
     }
   }
+  .search-button {
+    .ant-btn-link, .ant-btn-link:hover, .ant-btn-link:active{
+      border-color: transparent;
+      span {
+        position: relative;
+        top: 5px;
+      }
+    }
+  }
+  .advanced-list {
+    font-size: 13px;
+    padding: 0 12px;
+    > div {
+      display: inline-block;
+      margin-right: 10px;
+      border: 1px solid #dddddd;
+      padding: 0 4px 0 4px;
+      background: rgba(0, 0, 0, 0.02);
+
+      .anticon-close {
+        margin-left: 5px;
+        cursor: pointer;
+        color: #bcbcbc;
+        font-size: 12px;
+        padding: 2px;
+      }
+    }
+  }
+  .check-card-form-box {
+    margin-top: 5px;
+  }
 }
 .top-search.right {
   >.ant-row {
@@ -43,4 +74,4 @@
       float: right;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
new file mode 100644
index 0000000..036049b
--- /dev/null
+++ b/src/tabviews/zshare/topSearch/mkDatePicker/index.jsx
@@ -0,0 +1,93 @@
+import React, { Component } from 'react'
+import { is, fromJS } from 'immutable'
+import { DatePicker } from 'antd'
+import moment from 'moment'
+
+import './index.scss'
+
+const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+
+/**
+ * @description 鑷畾涔夋椂闂撮�夋嫨鍣�
+ */
+class MkDatePicker extends Component {
+  constructor(props) {
+    super(props)
+
+    const config = props.config
+
+    let mode = 'date'
+    let format = 'YYYY-MM-DD'
+
+    if (config.type === 'datemonth') {
+      mode = 'month'
+      format = 'YYYY-MM'
+    } else if (config.type === 'week') {
+      mode = 'week'
+      format = 'YYYY-MM-DD'
+    } else if (config.type === 'daterange') {
+      mode = 'daterange'
+      format = 'YYYY-MM-DD'
+    }
+    let value = config.initval || null
+
+    if (mode === 'daterange') {
+      if (value) {
+        let val = value.split(',')
+        value = [moment(val[0], format), moment(val[1], format)]
+      } else {
+        value = [null, null]
+      }
+    } else if (value) {
+      value = moment(value, format)
+    }
+
+    this.state = {
+      value,
+      mode,
+      format
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  onChange = (val) => {
+    const { format, mode } = this.state
+
+    this.setState({value: val})
+
+    if (mode === 'daterange') {
+      let _val = val
+      if (_val && !_val[0]) {
+        _val = ''
+      }
+      this.props.onChange(_val ? `${moment(_val[0]).format(format)},${moment(_val[1]).format(format)}` : '')
+    } else {
+      this.props.onChange(val ? moment(val).format(format) : '')
+    }
+  }
+
+  render() {
+    const { value, mode } = this.state
+
+    if (mode === 'date') {
+      return <DatePicker value={value} onChange={this.onChange}/>
+    } else if (mode === 'month') {
+      return <MonthPicker value={value} onChange={this.onChange}/>
+    } else if (mode === 'week') {
+      return <WeekPicker value={value} onChange={this.onChange}/>
+    } else if (mode === 'daterange') {
+      return <RangePicker placeholder={['寮�濮嬫棩鏈�', '缁撴潫鏃ユ湡']} value={value} onChange={this.onChange}/>
+    }
+  }
+}
+
+export default MkDatePicker
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/topSearch/mkDatePicker/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/topSearch/mkDatePicker/index.scss
diff --git a/src/tabviews/zshare/topSearch/mkSelect/index.jsx b/src/tabviews/zshare/topSearch/mkSelect/index.jsx
new file mode 100644
index 0000000..725c805
--- /dev/null
+++ b/src/tabviews/zshare/topSearch/mkSelect/index.jsx
@@ -0,0 +1,121 @@
+import React, {Component} from 'react'
+import { is, fromJS } from 'immutable'
+import { Select } from 'antd'
+
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+class MKSearchSelect extends Component {
+  constructor(props) {
+    super(props)
+    
+    const config = props.config
+    let value = config.initval
+
+    if (config.type === 'multiselect') {
+      if (value) {
+        value = value.split(',')
+      } else {
+        value = []
+      }
+    }
+
+    this.state = {
+      config: fromJS(config).toJS(),
+      options: fromJS(config.options).toJS(),
+      value,
+    }
+  }
+
+  componentDidMount () {
+    const { config } = this.state
+
+    if (config.type !== 'multiselect') {
+      MKEmitter.addListener('mkSP', this.mkFormHandle)
+    }
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  UNSAFE_componentWillReceiveProps (nextProps) {
+    const { config } = this.state
+
+    if (!is(fromJS(config.oriOptions), fromJS(nextProps.config.oriOptions))) {
+      this.setState({
+        config: fromJS(nextProps.config).toJS(),
+        options: fromJS(nextProps.config.options).toJS()
+      })
+    }
+  }
+
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('mkSP', this.mkFormHandle)
+  }
+
+  mkFormHandle = (uuid, parentId, level) => {
+    const { config } = this.state
+
+    if (uuid !== config.uuid) return
+
+    let options = config.oriOptions.filter(option => option.ParentID === parentId || option.Value === '')
+    let val = options[0] ? options[0].Value : ''
+
+    this.setState({
+      options,
+      value: val
+    })
+
+    this.props.onChange(val, true)
+
+    if (level < 7 && config.linkFields) {
+      config.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkSP', m.uuid, val, level + 1)
+        }, (i + 1) * 10)
+      })
+    }
+  }
+
+  selectChange = (val) => {
+    const { config } = this.state
+
+    if (config.type === 'multiselect') {
+      this.props.onChange(val.join(','))
+    } else {
+      config.linkFields && config.linkFields.forEach((m, i) => {
+        setTimeout(() => {
+          MKEmitter.emit('mkSP', m.uuid, val, 0)
+        }, (i + 1) * 10)
+      })
+
+      this.props.onChange(val)
+    }
+
+    this.setState({value: val})
+  }
+
+  render() {
+    const { value, config, options } = this.state
+
+    return (
+      <Select
+        showSearch
+        mode={config.type === 'multiselect' ? 'multiple' : ''}
+        value={value}
+        filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
+        onChange={this.selectChange}
+      >
+        {options.map(option =>
+          <Select.Option id={option.key} key={option.key} value={option.Value}>{option.Text}</Select.Option>
+        )}
+      </Select>
+    )
+  }
+}
+
+export default MKSearchSelect
\ No newline at end of file
diff --git a/src/tabviews/zshare/mutilform/customSwitch/index.scss b/src/tabviews/zshare/topSearch/mkSelect/index.scss
similarity index 100%
copy from src/tabviews/zshare/mutilform/customSwitch/index.scss
copy to src/tabviews/zshare/topSearch/mkSelect/index.scss
diff --git a/src/templates/calendarconfig/source.jsx b/src/templates/calendarconfig/source.jsx
index 061fc0c..9ed369e 100644
--- a/src/templates/calendarconfig/source.jsx
+++ b/src/templates/calendarconfig/source.jsx
@@ -106,6 +106,12 @@
     },
     {
       type: 'search',
+      label: '閫夐」鍗�',
+      subType: 'checkcard',
+      url: ''
+    },
+    {
+      type: 'search',
       label: CommonDict['model.form.dateday'],
       subType: 'date',
       url: ''
diff --git a/src/templates/comtableconfig/index.jsx b/src/templates/comtableconfig/index.jsx
index 2b88631..c7b4f43 100644
--- a/src/templates/comtableconfig/index.jsx
+++ b/src/templates/comtableconfig/index.jsx
@@ -26,6 +26,7 @@
 const { Panel } = Collapse
 const { confirm } = Modal
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
 const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -1205,6 +1206,7 @@
               </div>
             } bordered={false} extra={
               <div>
+                <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
                 <EditComponent dict={this.state.dict} options={['search', 'action', 'columns']} config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/>
                 <Switch className="big" checkedChildren={this.state.dict['model.enable']} unCheckedChildren={this.state.dict['model.disable']} checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                 <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['model.save']}</Button>
diff --git a/src/templates/comtableconfig/source.jsx b/src/templates/comtableconfig/source.jsx
index 6a33c64..d5297f9 100644
--- a/src/templates/comtableconfig/source.jsx
+++ b/src/templates/comtableconfig/source.jsx
@@ -228,6 +228,12 @@
     },
     {
       type: 'search',
+      label: '閫夐」鍗�',
+      subType: 'checkcard',
+      url: ''
+    },
+    {
+      type: 'search',
       label: CommonDict['model.form.dateday'],
       subType: 'date',
       url: ''
@@ -351,6 +357,12 @@
       label: CommonDict['model.form.colspan'],
       subType: 'colspan',
       url: ''
+    },
+    {
+      type: 'columns',
+      label: '搴忓彿',
+      subType: 'index',
+      url: ''
     }
   ]
 
diff --git a/src/templates/formtabconfig/index.jsx b/src/templates/formtabconfig/index.jsx
index 47db6ac..c5bca12 100644
--- a/src/templates/formtabconfig/index.jsx
+++ b/src/templates/formtabconfig/index.jsx
@@ -16,23 +16,25 @@
 
 import TabsComponent from '@/templates/sharecomponent/tabscomponent'
 
-import ModalForm from '@/templates/zshare/modalform'
 import PasteForm from '@/templates/zshare/pasteform'
 import ActionForm from './actionform'
 import SettingForm from './settingform'
 import DragElement from './dragelement'
 import GroupForm from './groupform'
 import EditCard from '@/templates/zshare/editcard'
-import VerifyCard from '@/templates/zshare/verifycard'
+
 import MenuForm from '@/templates/zshare/menuform'
 import SourceElement from '@/templates/zshare/dragsource'
-import CreateFunc from '@/templates/zshare/createfunc'
+import asyncComponent from '@/utils/asyncComponent'
 import Source from './source'
 import './index.scss'
 
 const { Panel } = Collapse
 const { Option } = Select
 const { confirm } = Modal
+const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
+const CreateFunc = asyncComponent(() => import('@/templates/zshare/createfunc'))
+const VerifyCard = asyncComponent(() => import('@/templates/zshare/verifycard'))
 
 class ComTableConfig extends Component {
   static propTpyes = {
diff --git a/src/templates/formtabconfig/settingform/index.jsx b/src/templates/formtabconfig/settingform/index.jsx
index 9a407ea..54c7b3a 100644
--- a/src/templates/formtabconfig/settingform/index.jsx
+++ b/src/templates/formtabconfig/settingform/index.jsx
@@ -197,8 +197,8 @@
                     message: dict['form.required.input'] + '琛ㄥ悕!'
                   },
                   {
-                    max: formRule.input.max,
-                    message: formRule.input.message
+                    max: 50,
+                    message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
                   }
                 ]
               })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
diff --git a/src/templates/menuconfig/editfirstmenu/index.jsx b/src/templates/menuconfig/editfirstmenu/index.jsx
index 3df062c..200a619 100644
--- a/src/templates/menuconfig/editfirstmenu/index.jsx
+++ b/src/templates/menuconfig/editfirstmenu/index.jsx
@@ -39,6 +39,7 @@
     thawMvisible: false, // 瑙i櫎鍐荤粨妯℃�佹
     confirmLoading: false, // 鎻愪氦涓�傘�傘��
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    targetKeys: [] // 瑙e喕鑿滃崟鍒楄〃
   }
 
   handlePreviewList = (List) => {
@@ -165,7 +166,9 @@
   }
 
   thawMemuSubmit = () => {
-    if (this.refs.trawmenu.state.targetKeys.length === 0) {
+    const { targetKeys } = this.state
+
+    if (targetKeys.length === 0) {
       notification.warning({
         top: 92,
         message: this.state.dict['form.required.select'] + this.state.dict['model.menu'],
@@ -175,7 +178,7 @@
       this.setState({
         confirmLoading: true
       })
-      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
+      let defers = targetKeys.map(item => {
         return new Promise((resolve) => {
           Api.getSystemConfig({
             func: 'sPC_MainMenu_ReDel',
@@ -201,6 +204,7 @@
           this.setState({
             confirmLoading: false,
             thawMvisible: false,
+            targetKeys: [],
             thawmenulist: null
           })
           this.props.reload()
@@ -212,6 +216,7 @@
   thawMemuCancel = () => {
     this.setState({
       thawMvisible: false,
+      targetKeys: [],
       thawmenulist: null
     })
   }
@@ -276,7 +281,8 @@
       })
     } else if (type === 'thawmenu') {
       this.setState({
-        thawMvisible: true
+        thawMvisible: true,
+        targetKeys: []
       })
       Api.getSystemConfig({
         func: 'sPC_Get_FrozenMenu',
@@ -378,7 +384,7 @@
           destroyOnClose
         >
           {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
-          {this.state.thawmenulist && <TransferForm ref="trawmenu" menulist={this.state.thawmenulist}/>}
+          {this.state.thawmenulist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
         </Modal>
         {/* 缂栬緫鑿滃崟妯℃�佹 */}
         <Modal
diff --git a/src/templates/menuconfig/editsecmenu/index.jsx b/src/templates/menuconfig/editsecmenu/index.jsx
index 6d9733e..a30f148 100644
--- a/src/templates/menuconfig/editsecmenu/index.jsx
+++ b/src/templates/menuconfig/editsecmenu/index.jsx
@@ -33,15 +33,16 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
-    menulist: null,       // 鑿滃崟鍒楄〃
-    type: '',             // 缂栬緫绫诲瀷锛宎dd or edit
-    title: '',            // 妯℃�佹鏍囬
-    visible: null,        // 妯℃�佹鏄惁鍙
-    formlist: null,       // 琛ㄥ崟淇℃伅
-    editMenu: null,       // 缂栬緫鑿滃崟
-    thawmenulist: null,   // 宸插喕缁撶殑浜岀骇鑿滃崟
-    thawMvisible: false,  // 瑙i櫎鍐荤粨妯℃�佹
-    confirmLoading: false // 鎻愪氦涓�傘�傘��
+    menulist: null,        // 鑿滃崟鍒楄〃
+    type: '',              // 缂栬緫绫诲瀷锛宎dd or edit
+    title: '',             // 妯℃�佹鏍囬
+    visible: null,         // 妯℃�佹鏄惁鍙
+    formlist: null,        // 琛ㄥ崟淇℃伅
+    editMenu: null,        // 缂栬緫鑿滃崟
+    thawmenulist: null,    // 宸插喕缁撶殑浜岀骇鑿滃崟
+    thawMvisible: false,   // 瑙i櫎鍐荤粨妯℃�佹
+    confirmLoading: false, // 鎻愪氦涓�傘�傘��
+    targetKeys: []         // 瑙e喕鑿滃崟鍒楄〃 
   }
 
   handlePreviewList = (List) => {
@@ -170,7 +171,8 @@
       })
     } else if (type === 'thaw') { // 瑙e喕宸叉湁鑿滃崟
       this.setState({
-        thawMvisible: true
+        thawMvisible: true,
+        targetKeys: []
       })
       Api.getSystemConfig({
         func: 'sPC_Get_FrozenMenu',
@@ -329,7 +331,9 @@
   }
 
   thawMemuSubmit = () => { // 瑙e喕鑿滃崟锛屾彁浜わ紝瀛樺湪澶氫釜鏃讹紝寰幆鎻愪氦
-    if (this.refs.trawmenu.state.targetKeys.length === 0) {
+    const { targetKeys } = this.state
+
+    if (targetKeys.length === 0) {
       notification.warning({
         top: 92,
         message: this.state.dict['form.required.select'] + this.state.dict['model.menu'],
@@ -339,7 +343,7 @@
       this.setState({
         confirmLoading: true
       })
-      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
+      let defers = targetKeys.map(item => {
         return new Promise((resolve) => {
           Api.getSystemConfig({
             func: 'sPC_MainMenu_ReDel',
@@ -365,6 +369,7 @@
           this.setState({
             confirmLoading: false,
             thawMvisible: false,
+            targetKeys: [],
             thawmenulist: null
           })
           this.props.reload()
@@ -376,6 +381,7 @@
   thawMemuCancel = () => { // 瑙e喕鑿滃崟鍙栨秷
     this.setState({
       thawMvisible: false,
+      targetKeys: [],
       thawmenulist: null
     })
   }
@@ -458,7 +464,7 @@
           onCancel={this.thawMemuCancel}
         >
           {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
-          {this.state.thawmenulist && <TransferForm ref="trawmenu" menulist={this.state.thawmenulist}/>}
+          {this.state.thawmenulist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
         </Modal>
       </div>
     )
diff --git a/src/templates/menuconfig/editthdmenu/index.jsx b/src/templates/menuconfig/editthdmenu/index.jsx
index 72cc5e2..76cc412 100644
--- a/src/templates/menuconfig/editthdmenu/index.jsx
+++ b/src/templates/menuconfig/editthdmenu/index.jsx
@@ -79,6 +79,7 @@
     btnTabConfig: null,     // 鎵撳紑鏂版爣绛炬寜閽厤缃�
     handleMVisible: false,  // 娣诲姞鎴栦慨鏀硅彍鍗曟ā鎬佹锛堣鑹叉潈闄愬垎閰嶇瓑锛�
     sysMenu: false,         // 娣诲姞鎴栫紪杈戣彍鍗曪紙瑙掕壊鏉冮檺鍒嗛厤绛夛級
+    targetKeys: []          // 瑙e喕鑿滃崟鍒楄〃 
   }
 
   /**
@@ -268,7 +269,8 @@
         return
       }
       this.setState({
-        thawMvisible: true
+        thawMvisible: true,
+        targetKeys: []
       })
       Api.getSystemConfig({
         func: 'sPC_Get_FrozenMenu',
@@ -347,8 +349,9 @@
   }
 
   thawMemuSubmit = () => {
+    const { targetKeys } = this.state
     // 涓夌骇鑿滃崟瑙i櫎鍐荤粨
-    if (this.refs.trawmenu.state.targetKeys.length === 0) {
+    if (targetKeys.length === 0) {
       notification.warning({
         top: 92,
         message: this.state.dict['form.required.select'] + this.state.dict['model.menu'],
@@ -358,7 +361,7 @@
       this.setState({
         confirmLoading: true
       })
-      let defers = this.refs.trawmenu.state.targetKeys.map(item => {
+      let defers = targetKeys.map(item => {
         return new Promise((resolve) => {
           Api.getSystemConfig({
             func: 'sPC_MainMenu_ReDel',
@@ -384,6 +387,7 @@
           this.setState({
             confirmLoading: false,
             thawMvisible: false,
+            targetKeys: [],
             thawmenulist: null
           })
           this.props.reload()
@@ -396,7 +400,8 @@
     // 瑙i櫎鍐荤粨-鍙栨秷
     this.setState({
       thawMvisible: false,
-      thawmenulist: null
+      thawmenulist: null,
+      targetKeys: []
     })
   }
 
@@ -560,7 +565,7 @@
         } else if (temp.Template === 'CustomPage' && memberLevel < 20) {
           return
         }
-
+        
         _templates.push({
           uuid: temp.MenuID,
           title: temp.MenuName,
@@ -612,7 +617,7 @@
     let sysTemplates = fromJS(this.state.sysTemplates).toJS()
 
     // 瑙掕壊鏉冮檺鍒嗛厤妯℃澘锛屽彧鍙互娣诲姞涓�娆�
-    if (sysMenu.isSystem && sysMenu.Template === 'RolePermission') {
+    if (sysMenu.isSystem && (sysMenu.Template === 'RolePermission')) {
       sysTemplates = sysTemplates.map(temp => {
         if (temp.type === sysMenu.type) {
           temp.hidden = true
@@ -673,6 +678,7 @@
             })
   
             this.props.reload()
+            document.getElementById('root').style.overflowY = 'unset'
           } else {
             this.setState({
               confirmLoading: false
@@ -725,6 +731,7 @@
             })
   
             this.props.reload()
+            document.getElementById('root').style.overflowY = 'unset'
           } else {
             this.setState({
               confirmLoading: false
@@ -932,7 +939,7 @@
           destroyOnClose
         >
           {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
-          {this.state.thawmenulist && <TransferForm ref="trawmenu" menulist={this.state.thawmenulist}/>}
+          {this.state.thawmenulist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
         </Modal>
         {/* 娣诲姞绯荤粺鑿滃崟 */}
         <Modal
diff --git a/src/templates/modalconfig/checkCard/index.jsx b/src/templates/modalconfig/checkCard/index.jsx
index 63c3164..3575d22 100644
--- a/src/templates/modalconfig/checkCard/index.jsx
+++ b/src/templates/modalconfig/checkCard/index.jsx
@@ -6,33 +6,38 @@
 
 class CheckCard extends Component {
   static propTpyes = {
-    multiple: PropTypes.bool,    // 鏄惁鍙閫�
-    ratio: PropTypes.string,     // 鍥剧墖姣斾緥
-    width: PropTypes.number,     // 瀹藉害
-    display: PropTypes.string,   // 鏄剧ず涓猴細text锛堟枃鏈級銆乸icture锛堝浘鐗囷級
-    fields: PropTypes.array,     // 瀛楁闆�
-    options: PropTypes.array,    // 鏁版嵁鍒楄〃
+    config: PropTypes.object,    // 琛ㄥ崟閰嶇疆淇℃伅
     onChange: PropTypes.func,    // 鏁版嵁鍒囨崲
   }
 
   state = {}
 
   getCards = () => {
-    const { display, width, options, fields, ratio } = this.props
+    const { display, width, options, fields, ratio, picratio, backgroundColor, borderColor } = this.props.config
 
+    let _ratio = picratio || ratio
     let paddingTop = '100%'
-    if (ratio === '4:3') {
+    if (_ratio === '4:3') {
       paddingTop = '75%'
-    } else if (ratio === '3:2') {
+    } else if (_ratio === '3:2') {
       paddingTop = '66.7%'
-    } else if (ratio === '16:9') {
+    } else if (_ratio === '16:9') {
       paddingTop = '56.25%'
     }
 
+    let style = {}
+    
+    if (borderColor) {
+      style.borderColor = borderColor
+    }
+
     if (display !== 'picture') {
+      let _style = backgroundColor ? {backgroundColor} : null
+ 
       if (!options || options.length === 0) {
         return <Col span={width}>
-          <div className="card-cell">
+          <div className="card-cell" style={style}>
+            <div className="bg-mask" style={_style}></div>
             {fields ? fields.map(col => {
               return <span key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{col.field}</span>
             }) : null}
@@ -42,7 +47,8 @@
       }
       return options.map(item => {
         return <Col span={width} key={item.key}>
-          <div className="card-cell">
+          <div className="card-cell" style={style}>
+            <div className="bg-mask" style={_style}></div>
             {fields.map(col => {
               return <span key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{item[col.field]}</span>
             })}
@@ -52,13 +58,13 @@
     } else {
       if (!options || options.length === 0) {
         return <Col span={width}>
-          <div className="card-pic-cell" style={{paddingTop, background: '#91d5ff'}}>
+          <div className="card-pic-cell" style={{...style, paddingTop, background: '#91d5ff'}}>
           </div>
         </Col>
       }
       return options.map(item => {
         return <Col span={width} key={item.key}>
-          <div className="card-pic-cell" style={{paddingTop, backgroundImage: `url(${item.$url})`}}>
+          <div className="card-pic-cell" style={{...style, paddingTop, backgroundImage: `url(${item.$url})`}}>
           </div>
         </Col>
       })
diff --git a/src/templates/modalconfig/checkCard/index.scss b/src/templates/modalconfig/checkCard/index.scss
index 985c786..8a6d3aa 100644
--- a/src/templates/modalconfig/checkCard/index.scss
+++ b/src/templates/modalconfig/checkCard/index.scss
@@ -1,5 +1,7 @@
 .check-card-edit-box {
+  line-height: 1.5;
   .card-cell {
+    position: relative;
     border: 1px solid #bcbcbc;
     border-radius: 4px;
     padding: 6px;
@@ -9,6 +11,18 @@
       overflow: hidden;
       text-overflow: ellipsis;
       white-space: nowrap;
+      position: relative;
+      z-index: 1;
+    }
+    .bg-mask {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      opacity: 1;
+      border-radius: 4px;
+      background-color: transparent;
     }
   }
   .card-pic-cell {
diff --git a/src/templates/modalconfig/dragelement/card.jsx b/src/templates/modalconfig/dragelement/card.jsx
index bfb0c5b..f5ad414 100644
--- a/src/templates/modalconfig/dragelement/card.jsx
+++ b/src/templates/modalconfig/dragelement/card.jsx
@@ -114,7 +114,7 @@
   } else if (card.type === 'split') {
     formItem = <div className="split-line">{card.label}</div>
   } else if (card.type === 'checkcard') {
-    formItem = <CheckCard width={card.width} ratio={card.ratio} display={card.display} fields={card.fields} options={card.options} />
+    formItem = <CheckCard config={card} />
   }
 
   let _label = card.label
@@ -145,7 +145,7 @@
             wrapperCol={card.labelwidth ? {style: {width: (100 - card.labelwidth) + '%'}} : null}
           >
             {formItem}
-            {showField ? <div className="field-name">{card.field}</div> : ''}
+            {showField ? <div className="field-name">{card.field}{card.hidden === 'true' ? '(闅愯棌)' : ''}</div> : ''}
           </Form.Item>}
         </div>
       </div>
diff --git a/src/templates/modalconfig/dragelement/index.jsx b/src/templates/modalconfig/dragelement/index.jsx
index 42ded36..d09acc7 100644
--- a/src/templates/modalconfig/dragelement/index.jsx
+++ b/src/templates/modalconfig/dragelement/index.jsx
@@ -33,6 +33,7 @@
 
   const editCard = id => {
     const { card } = findCard(id)
+    delete card.focus
     handleForm(card)
   }
 
@@ -106,7 +107,7 @@
   return (
     <div ref={drop} className={'ant-row modal-fields-row ' + (setting.align || 'left_right')} >
       {cards.map(card => {
-        return <Col key={card.uuid} span={card.span || 24}>
+        return <Col key={card.uuid} span={card.type === 'split' ? 24 : (card.span || 24)}>
           <Card
             id={card.uuid}
             card={card}
diff --git a/src/templates/modalconfig/index.jsx b/src/templates/modalconfig/index.jsx
index 8934dad..3ab3c92 100644
--- a/src/templates/modalconfig/index.jsx
+++ b/src/templates/modalconfig/index.jsx
@@ -13,7 +13,6 @@
 import enUS from '@/locales/en-US/model.js'
 import { getModalForm } from '@/templates/zshare/formconfig'
 
-import ModalForm from '@/templates/zshare/modalform'
 import SourceElement from './dragelement/source'
 import SettingForm from './settingform'
 import MenuForm from './menuform'
@@ -25,6 +24,9 @@
 const { Panel } = Collapse
 const { confirm } = Modal
 const CommonDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
+const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
 const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
 const DragElement = asyncComponent(() => import('./dragelement'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -218,7 +220,7 @@
       if (card.uuid === item.uuid) {
         index = i
       }
-      if (item.type !== 'select' && item.type !== 'link' && item.type !== 'radio') return
+      if (!['select', 'link', 'radio', ''].includes(item.type)) return
       if (item.field && !uniq.has(item.field)) {
         uniq.set(item.field, true)
 
@@ -338,7 +340,7 @@
 
       _config.fields = _config.fields.filter(item => !item.origin)
 
-      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
@@ -645,6 +647,7 @@
           <div className="setting">
             <Card title={dict['header.menu.form.configurable']} bordered={false} extra={
               <div>
+                <ReplaceField type="form" config={config} updateConfig={this.updateconfig}/>
                 <EditComponent dict={dict} options={['form']} config={this.state.config} refresh={this.updateEditConfig}/>
                 <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{dict['model.save']}</Button>
                 <Button onClick={this.cancelConfig}>{dict['model.back']}</Button>
@@ -710,7 +713,7 @@
         <Modal
           title={dict['model.edit']}
           visible={this.state.settingVisible}
-          width={700}
+          width={850}
           maskClosable={false}
           onOk={this.settingSave}
           onCancel={() => { this.setState({ settingVisible: false }) }}
diff --git a/src/templates/modalconfig/settingform/index.jsx b/src/templates/modalconfig/settingform/index.jsx
index 14517aa..a4ff109 100644
--- a/src/templates/modalconfig/settingform/index.jsx
+++ b/src/templates/modalconfig/settingform/index.jsx
@@ -1,7 +1,8 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, InputNumber, Select } from 'antd'
+import { Form, Row, Col, Input, Radio, InputNumber, Select, Tooltip, Icon } from 'antd'
 import { formRule } from '@/utils/option.js'
+import StyleInput from '@/menu/stylecontroller/styleInput'
 import './index.scss'
 
 class SettingForm extends Component {
@@ -14,11 +15,13 @@
 
   state = {
     fields: null,
+    display: this.props.config.setting.display,
     appType: sessionStorage.getItem('appType')
   }
 
   UNSAFE_componentWillMount () {
     const { config } = this.props
+    const { appType, display } = this.state
     let fields = []
 
     config.fields.forEach(f => {
@@ -27,8 +30,14 @@
       }
     })
 
+    let _display = display 
+    if (appType === 'mob' && display !== 'prompt' && display !== 'drawer') {
+      _display = 'drawer'
+    }
+
     this.setState({
-      fields: fields
+      fields: fields,
+      display: _display
     })
   }
 
@@ -56,7 +65,7 @@
 
   render() {
     const { config, dict } = this.props
-    const { fields, appType } = this.state
+    const { fields, appType, display } = this.state
     const { getFieldDecorator } = this.props.form
 
     const formItemLayout = {
@@ -86,13 +95,25 @@
               })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
             </Form.Item>
           </Col>
-          <Col span={12}>
-            <Form.Item label="瀹藉害">
+          {appType !== 'mob' ? <Col span={12}>
+            <Form.Item label="瀹藉害锛�%锛�">
               {getFieldDecorator('width', {
                 initialValue: config.setting.width
-              })(<InputNumber min={10} max={90} precision={0} />)}
+              })(<InputNumber min={10} max={90} precision={0} onPressEnter={this.handleSubmit}/>)}
             </Form.Item>
-          </Col>
+          </Col> : null}
+          {appType === 'mob' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="瀹藉害灏忎簬100鏃朵负鐧惧垎鐜囷紝澶т簬100鏃朵负缁濆鍊笺��">
+                <Icon type="question-circle" />
+                瀹藉害
+              </Tooltip>
+            }>
+              {getFieldDecorator('width', {
+                initialValue: config.setting.width
+              })(<InputNumber min={10} max={2000} precision={0} onPressEnter={this.handleSubmit}/>)}
+            </Form.Item>
+          </Col> : null}
           <Col span={12}>
             <Form.Item label="鐒︾偣">
               {getFieldDecorator('focus', {
@@ -114,7 +135,7 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={12}>
+          {appType !== 'mob' ? <Col span={12}>
             <Form.Item label="琛ㄥ崟鎺掑垪">
               {getFieldDecorator('align', {
                 initialValue: config.setting.align || 'left_right'
@@ -125,7 +146,7 @@
                 </Radio.Group>
               )}
             </Form.Item>
-          </Col>
+          </Col> : null}
           <Col span={12}>
             <Form.Item label="瀹屾垚鍚�">
               {getFieldDecorator('finish', {
@@ -150,7 +171,20 @@
               )}
             </Form.Item>
           </Col>
-          {!this.props.isSubTab && appType !== 'pc' ? <Col span={12}>
+          <Col span={12}>
+            <Form.Item label="鏄剧ず鏂瑰紡">
+              {getFieldDecorator('display', {
+                initialValue: display || 'modal'
+              })(
+                <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({display: e.target.value})}>
+                  {appType !== 'mob' ? <Radio value="modal">妯℃�佹</Radio> : null}
+                  <Radio value="prompt">鏄惁妗�</Radio>
+                  <Radio value="drawer">鎶藉眽</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {!this.props.isSubTab && !appType && display === 'modal' ? <Col span={12}>
             <Form.Item label="鎸傝浇瀵硅薄">
               {getFieldDecorator('container', {
                 initialValue: config.setting.container || 'tab'
@@ -162,18 +196,38 @@
               )}
             </Form.Item>
           </Col> : null}
-          <Col span={12}>
-            <Form.Item label="鏄剧ず鏂瑰紡">
-              {getFieldDecorator('display', {
-                initialValue: config.setting.display || 'modal'
+          {display === 'drawer' ? <Col span={12}>
+            <Form.Item label="鎶藉眽鏂瑰悜">
+              {getFieldDecorator('placement', {
+                initialValue: config.setting.placement || 'right'
               })(
-                <Radio.Group>
-                  <Radio value="modal">妯℃�佹</Radio>
-                  <Radio value="prompt">鏄惁妗�</Radio>
+                <Radio.Group style={{whiteSpace: 'nowrap'}}>
+                  <Radio value="right">鍙充晶</Radio>
+                  <Radio value="left">宸︿晶</Radio>
+                  <Radio value="top">涓婁晶</Radio>
+                  <Radio value="bottom">涓嬩晶</Radio>
                 </Radio.Group>
               )}
             </Form.Item>
-          </Col>
+          </Col> : null}
+          {appType === 'mob' ? <Col span={12}>
+            <Form.Item label="宸﹁竟璺�">
+              {getFieldDecorator('paddingLeft', {
+                initialValue: config.setting.paddingLeft || '10px'
+              })(
+                <StyleInput options={['px', '%']} />
+              )}
+            </Form.Item>
+          </Col> : null}
+          {appType === 'mob' ? <Col span={12}>
+            <Form.Item label="鍙宠竟璺�">
+              {getFieldDecorator('paddingRight', {
+                initialValue: config.setting.paddingRight || '10px'
+              })(
+                <StyleInput options={['px', '%']} />
+              )}
+            </Form.Item>
+          </Col> : null}
         </Row>
       </Form>
     )
diff --git a/src/templates/modalconfig/settingform/index.scss b/src/templates/modalconfig/settingform/index.scss
index 091801f..9a74987 100644
--- a/src/templates/modalconfig/settingform/index.scss
+++ b/src/templates/modalconfig/settingform/index.scss
@@ -10,4 +10,9 @@
   .ant-input-number {
     width: 100%;
   }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
 }
\ No newline at end of file
diff --git a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
index 1addfe3..53a733a 100644
--- a/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -38,6 +38,7 @@
     position: null,  // 鎸夐挳浣嶇疆
     procMode: null,  // 澶栭儴鎺ュ彛鍙傛暟澶勭悊鏂瑰紡
     pageTemplate: null,
+    Ot: null,
     requireOptions: [{
       value: 'notRequired',
       text: this.props.dict['header.form.notRequired']
@@ -97,6 +98,7 @@
     let _funcType = card.funcType || ''         // 鍔熻兘鎸夐挳榛樿绫诲瀷
     let _tabTemplate = card.tabTemplate         // 鎸夐挳涓烘爣绛鹃〉鏃讹紝鏍囩绫诲瀷锛氫笁绾ц彍鍗曟垨琛ㄥ崟鏍囩椤�
     let _pageTemplate = card.pageTemplate       // 鏂伴〉闈㈢被鍨�
+    let _Ot = card.Ot || 'requiredSgl'
 
     if (_opentype === 'outerpage') {
       card.pageTemplate = 'custom'
@@ -104,9 +106,10 @@
     }
 
     let _tabs = this.props.tabs.filter(tab => tab.type === 'SubTable')
-    let _options = this.getOptions(_opentype, _intertype, _funcType, _pageTemplate, _tabTemplate, _procMode)
+    let _options = this.getOptions(_opentype, _intertype, _funcType, _pageTemplate, _tabTemplate, _procMode, _Ot)
     
     this.setState({
+      Ot: _Ot,
       openType: _opentype,
       pageTemplate: _pageTemplate,
       interType: _intertype,
@@ -172,7 +175,7 @@
     }
   }
 
-  getOptions = (_opentype, _intertype, _funcType, _pageTemplate, _tabTemplate, _procMode) => {
+  getOptions = (_opentype, _intertype, _funcType, _pageTemplate, _tabTemplate, _procMode, _Ot) => {
     let _options = fromJS(actionTypeOptions[_opentype]).toJS() // 閫夐」鍒楄〃
     
     if (_opentype === 'innerpage') {         // 鏂伴〉闈紝鍙�夋ā鏉�(鑷畾涔夋椂锛屽彲濉叆澶栭儴閾炬帴)
@@ -227,6 +230,10 @@
       _options.push('resetPageIndex')
     }
 
+    if (_Ot !== 'notRequired' && _opentype !== 'excelOut') {
+      _options.push('controlField', 'controlVal')
+    }
+
     return _options
   }
 
@@ -234,11 +241,11 @@
    * @description 鍒囨崲
    */
   optionChange = (key, value) => {
-    const { openType, funcType, procMode } = this.state
+    const { openType, funcType, procMode, Ot } = this.state
     const { card } = this.props
 
     if (key === 'OpenType') {
-      let _options = this.getOptions(value, 'system', '', this.state.pageTemplate, card.tabTemplate, 'system')
+      let _options = this.getOptions(value, 'system', '', this.state.pageTemplate, card.tabTemplate, 'system', Ot)
       let _fieldval = {}
       let _formlist = this.state.formlist.map(item => {
         item.hidden = !_options.includes(item.key)
@@ -343,7 +350,7 @@
     //     this.props.form.setFieldsValue(_fieldval)
     //   })
     } else if (key === 'funcType') {
-      let _options = this.getOptions('funcbutton', this.state.interType, value, card.pageTemplate, card.tabTemplate, procMode)
+      let _options = this.getOptions('funcbutton', this.state.interType, value, card.pageTemplate, card.tabTemplate, procMode, Ot)
       let _fieldval = {}
 
       this.setState({
@@ -397,7 +404,7 @@
         this.props.form.setFieldsValue(_fieldval)
       })
     } else if (key === 'pageTemplate') {
-      let _options = this.getOptions('innerpage', this.state.interType, this.state.funcType, value, card.tabTemplate, procMode)
+      let _options = this.getOptions('innerpage', this.state.interType, this.state.funcType, value, card.tabTemplate, procMode, Ot)
       let _fieldval = {}
 
       this.setState({
@@ -438,7 +445,7 @@
         })
       })
     } else if (key === 'intertype') {
-      let _options = this.getOptions(openType, value, funcType, '', '', procMode)
+      let _options = this.getOptions(openType, value, funcType, '', '', procMode, Ot)
 
       this.setState({
         interType: value,
@@ -458,7 +465,7 @@
         })
       })
     } else if (key === 'procMode') {
-      let _options = this.getOptions(openType, this.state.interType, funcType, '', '', value)
+      let _options = this.getOptions(openType, this.state.interType, funcType, '', '', value, Ot)
 
       this.setState({
         procMode: value,
@@ -468,6 +475,16 @@
           if (item.key === 'innerFunc') {
             item.required = true
           }
+          return item
+        })
+      })
+    } else if (key === 'Ot') {
+      let _options = this.getOptions(openType, this.state.interType, funcType, this.state.pageTemplate, card.tabTemplate, procMode, value)
+
+      this.setState({
+        Ot: value,
+        formlist: this.state.formlist.map(item => {
+          item.hidden = !_options.includes(item.key)
           return item
         })
       })
@@ -599,8 +616,8 @@
                   getPopupContainer={() => document.getElementById('winter')}
                 >
                   {item.options.map((option, index) =>
-                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
-                      {item.key === 'icon' && option.value && <Icon type={option.value} />} {option.text}
+                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value || option.field}>
+                      {item.key === 'icon' && option.value ? <Icon type={option.value} /> : null} {option.text || option.label}
                     </Select.Option>
                   )}
                 </Select>
diff --git a/src/templates/sharecomponent/actioncomponent/index.scss b/src/templates/sharecomponent/actioncomponent/index.scss
index d5643e2..93cc1b7 100644
--- a/src/templates/sharecomponent/actioncomponent/index.scss
+++ b/src/templates/sharecomponent/actioncomponent/index.scss
@@ -16,7 +16,7 @@
   .page-card {
     display: inline-block;
     margin: 0px 0px 0px 0px;
-    padding: 0px 10px 0 0;
+    padding: 0px 10px 10px 0;
     position: relative;
     div {
       cursor: move;
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
index 26c87fe..dd5f292 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -229,8 +229,10 @@
         fields = fields + ','
       }
 
-      let database = btn.sheet.match(/(.*)\.(.*)\./ig) || ''
-      let sheet = btn.sheet.replace(/(.*)\.(.*)\./ig, '')
+      let database = btn.sheet.match(/(.*)\.(.*)\.|@db@/ig) || ''
+      let sheet = btn.sheet.replace(/(.*)\.(.*)\.|@db@/ig, '')
+
+      database = database ? (database[0] || '') : ''
 
       _value = `Insert into ${database}${sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From @${sheet}`
     } else {
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
index 01ec3e6..d050d57 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Button, Input, InputNumber } from 'antd'
+import { Form, Row, Col, Button, Input, InputNumber, Radio } from 'antd'
 import './index.scss'
 
 class ExcelOutColumn extends Component {
@@ -40,7 +40,7 @@
     return (
       <Form {...formItemLayout} className="verify-form">
         <Row gutter={24}>
-          <Col span={7}>
+          <Col span={5}>
             <Form.Item label={dict['model.form.field']}>
               {getFieldDecorator('Column', {
                 initialValue: '',
@@ -53,7 +53,7 @@
               })(<Input placeholder="" autoComplete="off" />)}
             </Form.Item>
           </Col>
-          <Col span={7}>
+          <Col span={5}>
             <Form.Item label={dict['model.name']}>
               {getFieldDecorator('Text', {
                 initialValue: '',
@@ -66,7 +66,7 @@
               })(<Input placeholder="" autoComplete="off" />)}
             </Form.Item>
           </Col>
-          <Col span={7}>
+          <Col span={5}>
             <Form.Item label={dict['model.form.columnWidth']}>
               {getFieldDecorator('Width', {
                 initialValue: 20,
@@ -79,7 +79,19 @@
               })(<InputNumber min={5} max={200} precision={0} />)}
             </Form.Item>
           </Col>
-          <Col span={3} className="add">
+          <Col span={5}>
+            <Form.Item label="绫诲瀷">
+              {getFieldDecorator('type', {
+                initialValue: 'text'
+              })(
+                <Radio.Group>
+                  <Radio value="text">鏂囨湰</Radio>
+                  <Radio value="image">鍥剧墖</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={4} className="add">
             <Button onClick={this.handleConfirm} type="primary" className="mk-green">
               娣诲姞
             </Button>
diff --git a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
index 8fb4902..f937f81 100644
--- a/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
+++ b/src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -33,14 +33,14 @@
         inputType: 'input',
         editable: true,
         unique: true,
-        width: '25%'
+        width: '20%'
       },
       {
         title: this.props.dict['model.name'],
         dataIndex: 'Text',
         inputType: 'input',
         editable: true,
-        width: '25%'
+        width: '20%'
       },
       {
         title: this.props.dict['model.form.columnWidth'],
@@ -49,7 +49,26 @@
         min: 5,
         max: 200,
         editable: true,
-        width: '25%'
+        width: '20%'
+      },
+      {
+        title: '绫诲瀷',
+        dataIndex: 'type',
+        inputType: 'select',
+        editable: true,
+        required: false,
+        width: '20%',
+        render: (text) => {
+          if (text === 'image') {
+            return '鍥剧墖'
+          } else {
+            return '鏂囨湰'
+          }
+        },
+        options: [
+          {value: 'text', text: '鏂囨湰'},
+          {value: 'image', text: '鍥剧墖'}
+        ]
       },
       {
         title: '鍙栫粷瀵瑰��',
@@ -57,7 +76,7 @@
         inputType: 'select',
         editable: true,
         required: false,
-        width: '25%',
+        width: '20%',
         render: (text) => {
           if (text === 'true') {
             return '鏄�'
@@ -87,11 +106,18 @@
     if (card.intertype !== 'system') {
       _verify.enable = 'false'
     }
+    if (_verify.columns[0] && !_verify.columns[0].type) {
+      _verify.columns = _verify.columns.map(col => {
+        col.type = col.type || 'text'
+        return col
+      })
+    }
 
     let defaultscript = ''
     if (!_verify.script && card.intertype === 'system') {
       let search = this.formatSearch(config.search)
       search = Utils.joinMainSearchkey(search)
+      search = search.replace(/@\$@/ig, '')
       search = search ? 'where ' + search : ''
       
       defaultscript = `update ${config.setting.tableName || ''} set idefine5= idefine5+1 ,modifydate=getdate(),cdefine5='宸插鍑�',modifyuserid=@userid@ ${search}`
@@ -113,36 +139,37 @@
 
     let newsearches = []
     searches.forEach(search => {
+      if (!search.field) return
+      
       let item = {
         key: search.field,
         match: search.match,
         type: search.type,
         label: search.label,
-        value: `@${search.field}@`,
+        value: search.initval,
         required: search.required === 'true'
       }
       if (item.type === 'group') {
-        let copy = fromJS(item).toJS()
-        copy.key = search.datefield
+        item.key = search.datefield
+        item.type = 'daterange'
+        item.match = 'between'
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
 
-        item.value = `@${search.field}@`
-        item.match = '='
-        
-        copy.type = 'daterange'
-        copy.match = 'between'
-        copy.value = [`@${search.datefield}@`, `@${search.datefield}1@`]
-
-        if (search.transfer === 'true') {
-          newsearches.push(item)
-        }
-        newsearches.push(copy)
+        newsearches.push(item)
         return
+      } else if (item.type === 'date') {
+        item.value = moment().format('YYYY-MM-DD')
+      } else if (item.type === 'datemonth') {
+        item.value = moment().format('YYYY-MM')
       } else if (item.type === 'dateweek') {
-        item.value = [`@${search.field}@`, `@${search.field}1@`]
+        item.value = moment().format('YYYY-MM-DD')
       } else if (item.type === 'daterange') {
-        item.value = [`@${search.field}@`, `@${search.field}1@`]
-      } else if (item.type === 'multiselect') {
-        item.value = [`@${search.field}@`]
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
+      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
+        item.type = 'multi'
+        item.value = '@$@'
+      } else {
+        item.value = '@$@'
       }
       newsearches.push(item)
     })
@@ -370,6 +397,7 @@
         Text: item.label,
         Width: 20,
         abs: 'false',
+        type: 'text',
         uuid: Utils.getuuid()
       })
     })
@@ -428,6 +456,7 @@
             <Button className="excel-col-add mk-red" title="娓呯┖Excel鍒�" onClick={this.clearField}>
               娓呯┖Excel鍒�
             </Button>
+            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>濡傞渶瀵煎嚭搴忓彿锛岃浣跨敤瀛楁 $Index銆�</div>
             <EditTable actions={['edit', 'move', 'copy', 'del']} type="exceloutcolumn" data={verify.columns} columns={excelColumns} onChange={(columns) => this.setState({verify: {...verify, columns}})}/>
           </TabPane>
           {card.intertype === 'system' ? <TabPane tab={
diff --git a/src/templates/sharecomponent/columncomponent/columnform/index.jsx b/src/templates/sharecomponent/columncomponent/columnform/index.jsx
index 8bfffcb..5932983 100644
--- a/src/templates/sharecomponent/columncomponent/columnform/index.jsx
+++ b/src/templates/sharecomponent/columncomponent/columnform/index.jsx
@@ -11,7 +11,8 @@
   number: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'decimal', 'format', 'prefix', 'postfix', 'blacklist', 'perspective', 'sum', 'rowspan'],
   link: ['label', 'field', 'type', 'nameField', 'Align', 'Hide', 'IsSort', 'joint', 'Width', 'fieldlength', 'blacklist'],
   textarea: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'prefix', 'postfix', 'fieldlength', 'blacklist'],
-  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'fieldlength', 'blacklist', 'scale', 'maxHeight']
+  picture: ['label', 'field', 'type', 'Align', 'Hide', 'IsSort', 'Width', 'fieldlength', 'blacklist', 'scale', 'maxHeight'],
+  index: ['label', 'type', 'Align', 'Width']
 }
 
 class MainSearch extends Component {
diff --git a/src/templates/sharecomponent/fieldscomponent/index.jsx b/src/templates/sharecomponent/fieldscomponent/index.jsx
index 8447dd0..8f2a184 100644
--- a/src/templates/sharecomponent/fieldscomponent/index.jsx
+++ b/src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -19,6 +19,7 @@
 
   state = {
     dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
+    appType: sessionStorage.getItem('appType'),
     fields: [],          // 瀛楁闆�
     tableVisible: false,    // 妯℃�佹鎺у埗
   }
@@ -54,7 +55,7 @@
     } else if (type === 'columns') {
       // 娣诲姞鏄剧ず鍒楋紝瀛楁闆嗕腑瀛樺湪鏄剧ず鍒楀瓧娈碉紝浣跨敤鏄剧ず鍒楀璞℃浛鎹㈠瓧娈甸泦锛岃缃暟鎹被鍨�
       config.columns.forEach(item => {
-        if (columns.has(item.field.toLowerCase())) {
+        if (item.field && columns.has(item.field.toLowerCase())) {
           let _datatype = columns.get(item.field.toLowerCase()).datatype
           columns.set(item.field.toLowerCase(), {...item, selected: true, datatype: _datatype})
         }
@@ -162,7 +163,7 @@
       config.search = items
     } else if (type === 'columns') {
       config.columns.forEach(item => {
-        if (columnsMap.has(item.field.toLowerCase())) {
+        if (item.field && columnsMap.has(item.field.toLowerCase())) {
           let cell = columnsMap.get(item.field.toLowerCase())
 
           if (cell.selected) {
@@ -216,12 +217,13 @@
       let _columns = [...columnsMap.values()]
 
       _columns.forEach(item => {
+        let _t = item.$datatype || (item.type === 'number' ? 'Decimal(18,0)' : 'Nvarchar(50)')
         if (item.selected) {
           let newcard = {
             uuid: Utils.getuuid(),
             label: item.label,
             field: item.field,
-            datatype: item.type === 'number' ? 'Decimal(18,0)' : 'Nvarchar(50)'
+            datatype: _t
           }
 
           items.push(newcard)
@@ -247,7 +249,10 @@
   
       let _columns = [...columnsMap.values()]
       let lastItem = config.fields[config.fields.length - 1]
-      let span = lastItem ? lastItem.span || 12 : 12
+      let span = this.state.appType === 'mob' ? 24 : 12
+      if (lastItem && lastItem.span) {
+        span = lastItem.span
+      }
 
       _columns.forEach(item => { // 寰幆娣诲姞鏂板瀛楁
         if (item.selected) {
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
index 812ed31..1981f06 100644
--- a/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/card.jsx
@@ -4,11 +4,13 @@
 import moment from 'moment'
 
 import DateGroup from '../dategroup'
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
 const { MonthPicker, WeekPicker, RangePicker } = DatePicker
+const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard'))
 
-const Card = ({ id, card, moveCard, copyCard, findCard, editCard, delCard }) => {
+const Card = ({ id, card, showField, moveCard, copyCard, findCard, editCard, delCard }) => {
   const originalIndex = findCard(id).index
   const [{ isDragging }, drag] = useDrag({
     item: { type: 'search', id, originalIndex },
@@ -57,6 +59,30 @@
     }
   }
 
+  let formItem = null
+  if (card.type === 'text') {
+    formItem = (<Input style={{marginTop: '4px'}} placeholder={card.labelShow === 'false' ? card.label : ''} value={card.initval} />)
+  } else if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') {
+    formItem = (<Select value={_defaultValue}></Select>)
+  } else if (card.type === 'date') {
+    formItem = (<DatePicker value={card.initval ? moment().subtract(card.initval, 'days') : null} />)
+  } else if (card.type === 'dateweek') {
+    formItem = (<WeekPicker value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} />)
+  } else if (card.type === 'datemonth') {
+    formItem = (<MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} />)
+  } else if (card.type === 'daterange') {
+    formItem = (<RangePicker
+      className="data-range"
+      placeholder={['BeginTime', 'EndTime']}
+      renderExtraFooter={() => 'extra footer'}
+      value={_defaultValue}
+    />)
+  } else if (card.type === 'group') {
+    formItem = (<DateGroup card={card} />)
+  } else if (card.type === 'checkcard') {
+    formItem = <CheckCard config={card} />
+  }
+
   return (
     <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
       <div className="mk-popover-control">
@@ -72,31 +98,9 @@
             wrapperCol = {{xs: { span: 24 }, sm: { span: 16 }}}
             label={card.labelShow !== 'false' ? card.label : ''}
             required={card.required === 'true'}
+            help={showField ? card.field + (card.datefield ? ', ' + card.datefield : '') : ''}
           >
-            {card.type === 'text' ?
-              <Input style={{marginTop: '4px'}} value={card.initval} /> : null
-            }
-            {(card.type === 'multiselect' || card.type === 'select' || card.type === 'link') ?
-              <Select value={_defaultValue}></Select> : null
-            }
-            {card.type === 'date' ?
-              <DatePicker value={card.initval ? moment().subtract(card.initval, 'days') : null} /> : null
-            }
-            {card.type === 'dateweek' ?
-              <WeekPicker value={card.initval ? moment().subtract(card.initval * 7, 'days') : null} /> : null
-            }
-            {card.type === 'datemonth' ?
-              <MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} /> : null
-            }
-            {card.type === 'daterange' ?
-              <RangePicker
-                className="data-range"
-                placeholder={['BeginTime', 'EndTime']}
-                renderExtraFooter={() => 'extra footer'}
-                value={_defaultValue}
-              /> : null
-            }
-            {card.type === 'group' ? <DateGroup card={card} /> : null }
+            {formItem}
           </Form.Item>
         </div>
       </div>
diff --git a/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
index 4af02e9..d65fdec 100644
--- a/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
@@ -7,7 +7,7 @@
 import Card from './card'
 import './index.scss'
 
-const Container = ({list, placeholder, handleList, handleMenu, deleteMenu }) => {
+const Container = ({list, placeholder, showField, handleList, handleMenu, deleteMenu }) => {
   const [cards, setCards] = useState(list)
   const moveCard = (id, atIndex) => {
     const { card, index } = findCard(id)
@@ -94,7 +94,7 @@
       newcard.display = 'dropdown'
       
       let _match = 'like'
-      if (item.subType === 'select' || item.subType === 'link') {
+      if (item.subType === 'select' || item.subType === 'link' || item.subType === 'checkcard') {
         _match = '='
       } else if (item.subType === 'date' || item.subType === 'datemonth') {
         _match = '>='
@@ -130,6 +130,7 @@
           <Card
             id={`${card.uuid}`}
             card={card}
+            showField={showField}
             moveCard={moveCard}
             copyCard={copyCard}
             editCard={editCard}
@@ -139,7 +140,7 @@
         </Col>
       ))}
       {cards.length > 0 ? <Col key="action" className="action" span={6}>
-        <div className="ant-row ant-form-item" style={{lineHeight: '40px', height: '55px', marginBottom: 0}}>
+        <div className="ant-row ant-form-item" style={{whiteSpace: 'nowrap', lineHeight: '40px', height: '55px', marginBottom: 0}}>
           <div className="ant-col ant-form-item-label ant-col-xs-24 ant-col-sm-8">
           </div>
           <div className="ant-col ant-form-item-control-wrapper ant-col-xs-24 ant-col-sm-16">
diff --git a/src/templates/sharecomponent/searchcomponent/index.jsx b/src/templates/sharecomponent/searchcomponent/index.jsx
index c17f639..44d9716 100644
--- a/src/templates/sharecomponent/searchcomponent/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Icon, Tooltip, Modal, notification } from 'antd'
+import { Icon, Tooltip, Modal, notification, Switch } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -27,6 +27,7 @@
     searchlist: null,    // 鎼滅储鏉′欢闆�
     sqlVerifing: false,  // sql楠岃瘉涓�
     visible: false,      // 妯℃�佹鎺у埗
+    showField: false,
     card: null           // 缂栬緫涓厓绱�
   }
 
@@ -79,12 +80,14 @@
     let linkableFields = []
 
     searchlist.forEach(item => {
-      if (item.uuid !== card.uuid && (item.type === 'select' || item.type === 'link')) {
-        linkableFields.push({
-          value: item.field,
-          text: item.label
-        })
-      }
+      if (item.uuid === card.uuid) return
+      if (!['select', 'link', 'checkcard'].includes(item.type)) return
+      if (item.type === 'checkcard' && item.multiple === 'true') return
+      
+      linkableFields.push({
+        value: item.field,
+        text: item.label
+      })
     })
 
     this.setState({
@@ -187,7 +190,7 @@
         return
       }
 
-      if ((res.type === 'select' || res.type === 'multiselect' || res.type === 'link') && res.resourceType === '1' && /\s/.test(res.dataSource)) {
+      if (['checkcard', 'select', 'multiselect', 'link'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
         this.setState({
           sqlVerifing: true
         })
@@ -261,6 +264,15 @@
     })
   }
 
+  onFieldChange = () => {
+    const { showField } = this.state
+
+    this.setState({
+      showField: !showField
+    })
+  }
+
+
   /**
    * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
    */
@@ -275,15 +287,17 @@
   }
 
   render() {
-    const { dict, searchlist, visible, sqlVerifing, card } = this.state
+    const { dict, searchlist, visible, sqlVerifing, card, showField } = this.state
 
     return (
       <div className={'model-table-search-list length' + searchlist.length}>
         <Tooltip placement="bottomLeft" overlayClassName="middle" title={dict['model.tooltip.search.guide']}>
           <Icon type="question-circle" />
         </Tooltip>
+        <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={showField} onChange={this.onFieldChange} />
         <DragElement
           list={searchlist}
+          showField={showField}
           handleList={this.handleList}
           handleMenu={this.handleSearch}
           deleteMenu={this.deleteElement}
diff --git a/src/templates/sharecomponent/searchcomponent/index.scss b/src/templates/sharecomponent/searchcomponent/index.scss
index cf4253b..2b8857c 100644
--- a/src/templates/sharecomponent/searchcomponent/index.scss
+++ b/src/templates/sharecomponent/searchcomponent/index.scss
@@ -1,6 +1,7 @@
 .model-table-search-list {
   padding: 1px 24px 20px;
   min-height: 87px;
+  position: relative;
   border-bottom: 1px solid #d9d9d9;
 
   .anticon-question-circle {
@@ -8,6 +9,12 @@
     position: relative;
     left: -15px;
     top: 5px;
+  }
+  >.ant-switch {
+    position: absolute;
+    z-index: 1;
+    right: 20px;
+    bottom: 10px;
   }
   > .ant-row {
     min-height: 65px;
@@ -68,4 +75,7 @@
     min-width: 100px!important;
     width: 100%;
   }
+  .check-card-edit-box {
+    margin-top: 5px!important;
+  }
 }
\ No newline at end of file
diff --git a/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx b/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
index 7465a79..eb43982 100644
--- a/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/searcheditable/index.jsx
@@ -113,14 +113,14 @@
         render: (text, record) =>
           this.state.dataSource.length >= 1 ? (
             <div>
-              <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
               <span className="operation-btn" title={props.dict['header.form.down']} onClick={() => this.handleUpDown(record, 'down')} style={{color: '#ff4d4f'}}><Icon type="arrow-down" /></span>
+              <span className="operation-btn" title={props.dict['header.form.up']} onClick={() => this.handleUpDown(record, 'up')} style={{color: '#1890ff'}}><Icon type="arrow-up" /></span>
               <Popconfirm
                 overlayClassName="popover-confirm"
                 title={props.dict['model.query.delete']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
-                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+                <span style={{color: '#ff4d4f', cursor: 'pointer'}}><Icon type="delete" /></span>
               </Popconfirm>
             </div>
           ) : null,
@@ -171,8 +171,9 @@
   }
 
   handleDelete = key => {
-    const dataSource = [...this.state.dataSource]
-    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
+    const dataSource = this.state.dataSource.filter(item => item.key !== key)
+    this.setState({ dataSource })
+    this.props.onChange && this.props.onChange(dataSource)
   }
 
   handleAdd = () => {
@@ -185,10 +186,12 @@
     if (type === 'link') {
       newData.ParentID = `${count}`
     }
+    let data = [...dataSource, newData]
     this.setState({
-      dataSource: [...dataSource, newData],
+      dataSource: data,
       count: count + 1
     })
+    this.props.onChange && this.props.onChange(data)
   }
 
   handleSave = row => {
@@ -200,6 +203,7 @@
       ...row
     })
     this.setState({ dataSource: newData })
+    this.props.onChange && this.props.onChange(newData)
   }
 
   resetColumn = (type) => {
diff --git a/src/templates/sharecomponent/searchcomponent/searchform/index.jsx b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
index 843331c..96c3459 100644
--- a/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
+++ b/src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -1,11 +1,17 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
 import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Checkbox, Cascader } from 'antd'
 import { dateOptions, matchReg, formRule } from '@/utils/option.js'
 import EditTable from '../searcheditable'
 import Utils from '@/utils/utils.js'
 import CodeMirror from '@/templates/zshare/codemirror'
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
+
+const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
+const FieldsTable = asyncComponent(() => import('@/templates/zshare/modalform/fieldtable'))
+const DataTable = asyncComponent(() => import('@/templates/zshare/modalform/datatable'))
 
 const groupOptions = [
   {
@@ -80,6 +86,20 @@
   },
 ]
 
+const searchTypeOptions = {
+  text: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'inputType', 'advanced'],
+  select: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
+  multiselect: ['label', 'field', 'resourceType', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
+  link: ['label', 'field', 'resourceType', 'initval', 'type', 'linkField', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced', 'setAll'],
+  date: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
+  checkcard: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'resourceType', 'display', 'width', 'multiple', 'borderColor', 'required', 'Hide', 'labelShow', 'advanced'],
+  dateweek: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
+  datemonth: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
+  daterange: ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow', 'advanced'],
+  group: ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'labelShow'],
+  range: ['label', 'type', 'field', 'initval', 'match', 'blacklist', 'Hide', 'required', 'maxValue', 'minValue', 'step', 'labelShow']
+}
+
 class MainSearch extends Component {
   static propTpyes = {
     dict: PropTypes.object,     // 瀛楀吀椤�
@@ -92,6 +112,8 @@
     openType: null,          // 鎼滅储鏉′欢鏄剧ず绫诲瀷
     resourceType: null,      // 涓嬫媺鎼滅储鏃讹紝閫夐」鏉ユ簮绫诲瀷
     formlist: null,          // 琛ㄥ崟
+    display: null,
+    cFields: [],
     textTooltip: '瀛楁鍚嶅彲浠ヤ娇鐢ㄩ�楀彿鍒嗛殧锛岃繘琛岀患鍚堟悳绱�',
   }
 
@@ -103,31 +125,37 @@
   UNSAFE_componentWillMount () {
     const { formlist, dict } = this.props
 
-    let type = formlist.filter(cell => cell.key === 'type')[0].initVal
-    let _items = formlist.filter(cell => cell.key === 'items')[0].initVal
-    let resourceType = formlist.filter(cell => cell.key === 'resourceType')[0].initVal
-    let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow']                // 榛樿鏄剧ず椤�
+    let type = ''
+    let _items = []
+    let resourceType = ''
+    let display = ''
+    let cFields = []
+    let multiple = 'false'
 
-    if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
-      _options = [..._options, 'resourceType', 'options', 'display']
-    } else if ((type === 'multiselect' || type === 'select' || type === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
-      _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
-    } else if (type === 'group') {
-      _options = ['label', 'type', 'field', 'datefield', 'initval', 'blacklist', 'ratio', 'items', 'required', 'transfer', 'labelShow']
-    }
+    formlist.forEach(cell => {
+      if (cell.key === 'type') {
+        type = cell.initVal
+      } else if (cell.key === 'items') {
+        _items = cell.initVal
+      } else if (cell.key === 'display') {
+        display = cell.initVal
+      } else if (cell.key === 'resourceType') {
+        resourceType = cell.initVal
+      } else if (cell.key === 'fields') {
+        cFields = cell.initVal
+      } else if (cell.key === 'multiple') {
+        multiple = cell.initVal
+      }
+    })
 
-    if (type === 'select' || type === 'link') {
-      _options.push('setAll')
-    }
-
-    if (type === 'link') { // 鍏宠仈绫诲瀷銆佸鍔犲叧鑱斾笂绾х殑瀛楁鍚�
-      _options = [..._options, 'linkField']
-    }
+    let _options = this.getOptions(type, resourceType, display)
     
     this.setState({
+      display,
+      cFields,
       openType: type,
       items: _items,
-      resourceType: resourceType,
+      resourceType,
       formlist: formlist.map(form => {
         // 琛ㄥ崟涓哄垵濮嬪�煎瓧娈碉紝涓旀暟鎹被鍨嬪睘浜庢椂闂寸被鍨嬫椂锛岃缃垵濮嬪�间负涓嬫媺閫夋嫨锛屽苟閲嶇疆閫夋嫨椤�
         if (form.key === 'initval' && dateOptions.hasOwnProperty(type)) {
@@ -139,20 +167,21 @@
         } else if (form.key === 'match') { // 琛ㄥ崟涓哄尮閰嶅瓧娈垫椂锛屾牴鎹笉鍚岀殑绫诲瀷锛屾樉绀哄搴旂殑鍖归厤瑙勫垯
           if (type === 'text') {
             form.options = matchReg.text
-          } else if (type === 'multiselect') {
+          } else if (type === 'multiselect' || (type === 'checkcard' && multiple === 'true')) {
             form.options = matchReg.multiselect
-          } else if (type === 'select' || type === 'link') {
+          } else if (type === 'select' || type === 'link' || type === 'checkcard') {
             form.options = matchReg.select
           } else if (type === 'date') {
             form.options = matchReg.date
           } else if (type === 'datemonth') {
             form.options = matchReg.datemonth
-          } else if (type === 'dateweek' || type === 'daterange') {
+          } else if (type === 'dateweek' || type === 'daterange' || type === 'range') {
             form.options = matchReg.daterange
           }
-        } else if (form.key === 'field' && type === 'text') {
+        } else if (form.key === 'field' && (type === 'text' || type === 'select')) {
           form.tooltip = this.state.textTooltip
         } else if (form.key === 'field' && type === 'group') {
+          form.tooltip = '鏌ヨ鏁版嵁鏃讹紙鑷畾涔夎剼鏈垨缁熻鏁版嵁婧愶級锛岀被鍨嬪瓧娈靛皢鐢ㄤ綔鏇挎崲鑴氭湰涓殑 @瀛楁@ 锛岀被鍨嬪瓧娈靛搴斿�间负 {"鏃�": "day", "鍛�": "week", "鏈�": "month", "瀛�": "quarter", "骞�": "year", "鑷畾涔�": "customized"}銆�'
           form.label = dict['model.form.type'] + dict['model.form.field']
         }
         form.hidden = !_options.includes(form.key)
@@ -174,32 +203,41 @@
     }
   }
 
+  getOptions = (type, resourceType, display) => {
+    let _options = fromJS(searchTypeOptions[type]).toJS() // 閫夐」鍒楄〃
+    
+    if (['multiselect', 'select', 'link'].includes(type) && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
+      _options.push('options')
+    } else if (['multiselect', 'select', 'link'].includes(type) && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
+      _options.push('dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database')
+    } else if (type === 'checkcard') {
+      if (display === 'picture') {
+        if (resourceType === '0') {        // 鑷畾涔夎祫婧�
+          _options.push('options', 'picratio')
+        } else if (resourceType === '1') { // 鏁版嵁婧�
+          _options.push('dataSource', 'cardValField', 'urlField', 'orderBy', 'orderType', 'database', 'picratio')
+        }
+      } else {
+        if (resourceType === '0') {        // 鑷畾涔夎祫婧�
+          _options.push('options', 'fields', 'backgroundColor')
+        } else if (resourceType === '1') { // 鏁版嵁婧�
+          _options.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database', 'backgroundColor')
+        }
+      }
+    }
+
+    return _options
+  }
+
   /**
    * @description 鎼滅储鏉′欢绫诲瀷鍒囨崲
    */
   openTypeChange = (key, value) => {
     const { dict } = this.props
-    const { resourceType, items } = this.state
+    const { resourceType, items, display } = this.state
 
     if (key === 'type') {
-      let _options = ['label', 'field', 'initval', 'type', 'match', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow']
-
-      if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '0') {        // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓鸿嚜瀹氫箟璧勬簮
-        _options = [..._options, 'resourceType', 'options', 'display']
-      } else if ((value === 'multiselect' || value === 'select' || value === 'link') && resourceType === '1') { // 涓嬫媺閫夋嫨绫诲瀷銆侀�夐」涓哄悗鍙版暟鎹簮涓幏鍙�
-        _options = [..._options, 'resourceType', 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'display', 'database']
-      } else if (value === 'group') {
-        _options = ['label', 'type', 'field', 'datefield', 'initval', 'items', 'ratio', 'blacklist', 'required', 'transfer', 'labelShow']
-      }
-
-      if (value === 'select' || value === 'link') {
-        _options.push('setAll')
-      }
-      
-      if (value === 'link') {
-        _options = [..._options, 'linkField']
-      }
-
+      let _options = this.getOptions(value, resourceType, display)
       let matchs = []
 
       this.setState({
@@ -222,22 +260,23 @@
               form.options = matchReg.text
             } else if (value === 'multiselect') {
               form.options = matchReg.multiselect
-            } else if (value === 'select' || value === 'link') {
+            } else if (value === 'select' || value === 'link' || value === 'checkcard') {
               form.options = matchReg.select
             } else if (value === 'date') {
               form.options = matchReg.date
             } else if (value === 'datemonth') {
               form.options = matchReg.datemonth
-            } else if (value === 'dateweek' || value === 'daterange') {
+            } else if (value === 'dateweek' || value === 'daterange' || value === 'range') {
               form.options = matchReg.daterange
             }
             matchs = form.options
           } else if (form.key === 'field') {
             form.tooltip = ''
             form.label = dict['model.form.field']
-            if (value === 'text') {
+            if (value === 'text' || value === 'select') {
               form.tooltip = this.state.textTooltip
             } else if (value === 'group') {
+              form.tooltip = '鏌ヨ鏁版嵁鏃讹紙鑷畾涔夎剼鏈垨缁熻鏁版嵁婧愶級锛岀被鍨嬪瓧娈靛皢鐢ㄤ綔鏇挎崲鑴氭湰涓殑 @瀛楁@ 锛岀被鍨嬪瓧娈靛搴斿�间负 {"鏃�": "day", "鍛�": "week", "鏈�": "month", "瀛�": "quarter", "骞�": "year", "鑷畾涔�": "customized"}銆�'
               form.label = dict['model.form.type'] + dict['model.form.field']
             }
           }
@@ -251,6 +290,9 @@
         if (this.props.form.getFieldValue('match') !== undefined) {
           this.props.form.setFieldsValue({match: matchs[0].value})
         }
+        if (this.props.form.getFieldValue('multiple') !== undefined) {
+          this.props.form.setFieldsValue({multiple: 'false'})
+        }
       })
     }
   }
@@ -259,26 +301,12 @@
    * @description 鏁版嵁婧愮被鍨嬪垏鎹�
    */
   onChange = (e, key) => {
-    const { openType } = this.state
+    const { openType, display, resourceType } = this.state
     let value = e.target.value
 
     if (key === 'resourceType') {
-      let _options = ['label', 'field', 'initval', 'type', 'match', 'resourceType', 'display', 'ratio', 'blacklist', 'required', 'Hide', 'labelShow']
+      let _options = this.getOptions(openType, value, display)
 
-      if (value === '0') {
-        _options = [..._options, 'options']
-      } else if (value === '1') {
-        _options = [..._options, 'dataSource', 'valueField', 'valueText', 'orderBy', 'orderType', 'database']
-      }
-
-      if (openType === 'select' || openType === 'link') {
-        _options.push('setAll')
-      }
-      
-      if (openType === 'link') {
-        _options = [..._options, 'linkField']
-      }
-      
       this.setState({
         resourceType: value,
         formlist: this.state.formlist.map(form => {
@@ -286,7 +314,49 @@
           return form
         })
       })
+    } else if (key === 'display') {
+      let _options = this.getOptions(openType, resourceType, value)
+
+      this.setState({
+        display: value,
+        formlist: this.state.formlist.map(form => {
+          form.hidden = !_options.includes(form.key)
+          return form
+        })
+      })
+    } else if (key === 'multiple') {
+      let matchs = []
+      this.setState({
+        formlist: this.state.formlist.map(form => {
+          if (form.key === 'match') {
+            if (value === 'true') {
+              form.options = matchReg.multiselect
+            } else {
+              form.options = matchReg.select
+            }
+            matchs = form.options
+          }
+
+          return form
+        })
+      }, () => {
+        if (this.props.form.getFieldValue('match') !== undefined) {
+          this.props.form.setFieldsValue({match: matchs[0].value})
+        }
+      })
     }
+  }
+
+  changeField = (data) => {
+    this.setState({
+      cFields: data,
+      formlist: this.state.formlist.map(form => {
+        if (form.key === 'fields') {
+          form.initVal = data
+        }
+        return form
+      })
+    })
   }
 
   checkChange = (values, key) => {
@@ -324,7 +394,7 @@
     const { getFieldDecorator } = this.props.form
     const fields = []
     this.state.formlist.forEach((item, index) => {
-      if (item.hidden) return
+      if (item.hidden || item.forbid) return
 
       if (item.type === 'text') { // 鏂囨湰鎼滅储
         let rules = []
@@ -374,14 +444,17 @@
               </Tooltip> : item.label
             }>
               {getFieldDecorator(item.key, {
-                initialValue: item.initVal || 6,
+                initialValue: item.initVal,
                 rules: [
                   {
                     required: item.required,
                     message: this.props.dict['form.required.input'] + item.label + '!'
                   }
                 ]
-              })(<InputNumber min={item.min} max={item.max} precision={0} onPressEnter={this.handleSubmit}/>)}
+              })(item.max ?
+                  <InputNumber min={item.min} max={item.max} precision={0} onPressEnter={this.handleSubmit}/> : 
+                  <InputNumber onPressEnter={this.handleSubmit}/>
+                )}
             </Form.Item>
           </Col>
         )
@@ -447,8 +520,8 @@
         )
       } else if (item.type === 'textarea') {
         fields.push(
-          <Col span={20} offset={4} key={index}>
-            <Form.Item className="text-area">
+          <Col span={24} key={index}>
+            <Form.Item className="text-area" label={item.label}>
               {getFieldDecorator(item.key, {
                 initialValue: item.initVal,
                 rules: [
@@ -462,9 +535,35 @@
           </Col>
         )
       } else if (item.type === 'options') {
+        if (openType !== 'checkcard') {
+          fields.push(
+            <Col span={24} key={index}>
+              <Form.Item label={item.label} className="text-area">
+                {getFieldDecorator(item.key, {
+                  initialValue: item.initVal
+                })(<EditTable dict={this.props.dict} type={this.state.openType} data={item.initVal}/>)}
+              </Form.Item>
+            </Col>
+          )
+        } else {
+          fields.push(
+            <Col span={24} key={index}>
+              <Form.Item label={item.label} className="text-area">
+                {getFieldDecorator(item.key, {
+                  initialValue: item.initVal
+                })(<DataTable dict={this.props.dict} type={this.state.display} fields={this.state.cFields}/>)}
+              </Form.Item>
+            </Col>
+          )
+        }
+      } else if (item.type === 'fields') {
         fields.push(
-          <Col span={20} offset={4} key={index}>
-            <EditTable data={item.initVal} type={this.state.openType} dict={this.props.dict} ref="editTable"/>
+          <Col span={24} key={index}>
+            <Form.Item label={item.label} className="text-area">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(<FieldsTable dict={this.props.dict} onChange={this.changeField}/>)}
+            </Form.Item>
           </Col>
         )
       } else if (item.type === 'checkbox') {
@@ -517,6 +616,16 @@
             </Form.Item>
           </Col>
         )
+      } else if (item.type === 'color') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label} className="color-form-item">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(<ColorSketch allowClear={true}/>)}
+            </Form.Item>
+          </Col>
+        )
       }
     })
 
@@ -531,22 +640,63 @@
           let isvalid = true
           values.uuid = this.props.card.uuid
           // 涓嬫媺鑿滃崟鎴栬仈鍔ㄨ彍鍗�
-          if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '0') {
-            values.options = this.refs.editTable.state.dataSource
+          if (['multiselect', 'select', 'link', 'checkcard'].includes(values.type) && values.resourceType === '0') {
+            values.options = values.options || []
             values.dataSource = ''
             let emptys = []
-            if (values.type === 'multiselect' || values.type === 'select') {
+            if (['multiselect', 'select'].includes(values.type)) {
               emptys = values.options.filter(op => !(op.Value && op.Text))
-            } else {
+            } else if (values.type === 'link') {
               emptys = values.options.filter(op => !(op.Value && op.Text && op.ParentID))
             }
             if (emptys.length > 0) {
               isvalid = false
             }
-          } else if ((values.type === 'multiselect' || values.type === 'select' || values.type === 'link') && values.resourceType === '1') {
+          } else if (['multiselect', 'select', 'link', 'checkcard'].includes(values.type) && values.resourceType === '1') {
             values.options = []
           }
 
+          if (values.type === 'range') {
+            let error = ''
+            if (values.maxValue <= values.minValue) {
+              error = '鏈�澶у�煎繀椤诲ぇ浜庢渶灏忓��'
+            } else if (values.step <= 0) {
+              error = '姝ラ暱蹇呴』澶т簬0'
+            } else {
+              let s = (values.maxValue - values.minValue) / values.step
+              if (s !== parseInt(s)) {
+                error = '姝ラ暱蹇呴』琚� (max - min) 鏁撮櫎'
+              }
+            }
+
+            if (!error && values.initval) {
+              let vals = values.initval.split(',')
+              if (vals.length !== 2) {
+                error = '鍒濆鍊艰缃敊璇紒'
+              } else if (isNaN(parseFloat(vals[0])) || isNaN(parseFloat(vals[1]))) {
+                error = '鍒濆鍊艰缃敊璇紒'
+              } else {
+                let start = parseFloat(vals[0])
+                let end = parseFloat(vals[1])
+                let s = (values.maxValue - start) / values.step
+                let e = (values.maxValue - end) / values.step
+                if (start > end || start < values.minValue || end > values.maxValue) {
+                  error = '鍒濆鍊艰缃敊璇紒'
+                } else if (s !== parseInt(s) || e !== parseInt(e)) {
+                  error = '鍒濆鍊艰缃敊璇紒'
+                }
+              }
+            }
+            if (error) {
+              notification.warning({
+                top: 92,
+                message: error,
+                duration: 5
+              })
+              return
+            }
+          }
+
           if (isvalid) {
             ['linkField', 'valueField', 'valueText', 'orderBy'].forEach(item => {
               if (values[item]) {
diff --git a/src/templates/sharecomponent/searchcomponent/searchform/index.scss b/src/templates/sharecomponent/searchcomponent/searchform/index.scss
index cc9c99c..56d3f89 100644
--- a/src/templates/sharecomponent/searchcomponent/searchform/index.scss
+++ b/src/templates/sharecomponent/searchcomponent/searchform/index.scss
@@ -5,9 +5,12 @@
     padding-bottom: 20px;
   }
   .ant-form-item.text-area {
-    margin-bottom: 0px;
+    // margin-bottom: 0px;
     .ant-form-item-control-wrapper {
-      width: 100%;
+      width: 84%;
+    }
+    .ant-form-item-label {
+      width: 16%;
     }
     .CodeMirror {
       height: 150px;
@@ -29,4 +32,12 @@
       }
     }
   }
+  .color-form-item {
+    .ant-form-item-control {
+      height: 40px;
+      .color-sketch-block {
+        margin-top: 7px;
+      }
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/templates/sharecomponent/settingcalcomponent/index.jsx b/src/templates/sharecomponent/settingcalcomponent/index.jsx
index 416e27d..9aa21fa 100644
--- a/src/templates/sharecomponent/settingcalcomponent/index.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/index.jsx
@@ -44,6 +44,17 @@
 
     this.setState({loading: true})
     this.verifyRef.submitDataSource().then(res => {
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          if (res.setting.dataresource) {
+            res.setting.dataresource = res.setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+        })
+      }
 
       this.setState({loading: false, visible: false})
       this.props.updateConfig({...config, ...res})
diff --git a/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx b/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
index 065406a..8e00256 100644
--- a/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
@@ -71,10 +71,25 @@
   UNSAFE_componentWillMount() {
     const { config } = this.props
 
+    let _setting = fromJS(config.setting).toJS()
+    let _scripts = fromJS(config.scripts).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
-      setting: fromJS(config.setting).toJS(),
+      setting: _setting,
       columns: fromJS(config.columns).toJS(),
-      scripts: fromJS(config.scripts).toJS()
+      scripts: _scripts
     })
   }
 
@@ -327,6 +342,7 @@
   }
 
   render() {
+    const { config } = this.props
     const { columns, setting, scripts, colColumns, activeKey, loading } = this.state
 
     return (
@@ -350,7 +366,7 @@
               wrappedComponentRef={(inst) => this.contrastForm = inst}
             />
             <FieldsComponent
-              config={{...this.props.config, columns}}
+              config={{...config, columns}}
               type="fields"
               updatefield={this.updatefields}
             />
@@ -373,6 +389,7 @@
               dict={this.props.dict}
               setting={setting}
               scripts={scripts}
+              urlFields={config.urlFields}
               defaultSql={this.state.defaultsql}
               searches={this.props.searches}
               scriptsChange={this.scriptsChange}
diff --git a/src/templates/sharecomponent/settingcalcomponent/verifycard/settingform/index.jsx b/src/templates/sharecomponent/settingcalcomponent/verifycard/settingform/index.jsx
index da7e7b1..d2ace67 100644
--- a/src/templates/sharecomponent/settingcalcomponent/verifycard/settingform/index.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/verifycard/settingform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification } from 'antd'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, InputNumber } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -184,6 +184,10 @@
                     {
                       required: true,
                       message: this.props.dict['form.required.input'] + '琛ㄥ悕!'
+                    },
+                    {
+                      max: 50,
+                      message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
                     }
                   ]
                 })(<Input placeholder={''} autoComplete="off" />)}
@@ -308,6 +312,18 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="楂樼骇鎼滅储寮圭獥鐨勫搴︼紝娉細褰撳搴﹀�煎皬浜�100鏃惰〃绀哄崰绐楀彛鐨勭櫨鍒嗘瘮锛屽ぇ浜�100鏃惰〃绀哄搴︾殑缁濆鍊笺��">
+                  <Icon type="question-circle" />
+                  楂樼骇鎼滅储
+                </Tooltip>
+              }>
+                {getFieldDecorator('advanceWidth', {
+                  initialValue: setting.advanceWidth || 1000
+                })(<InputNumber min={10} max={3000} precision={0}/>)}
+              </Form.Item>
+            </Col>
           </Row>
         </Form>
       </div>
diff --git a/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx b/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
index da2b30d..fa3d829 100644
--- a/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
+++ b/src/templates/sharecomponent/settingcalcomponent/verifycard/utils.jsx
@@ -30,6 +30,14 @@
     if (setting.execute !== 'false') {
       _dataresource = setting.dataresource || ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
diff --git a/src/templates/sharecomponent/settingcomponent/index.jsx b/src/templates/sharecomponent/settingcomponent/index.jsx
index bad5664..dfd1ac0 100644
--- a/src/templates/sharecomponent/settingcomponent/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/index.jsx
@@ -59,7 +59,8 @@
     this.setState({
       loading: true
     })
-    this.settingRef.handleConfirm().then(res => {
+    this.settingRef.handleConfirm().then(setting => {
+      let res = this.resetSetting(setting)
       this.setState({
         visible: false,
         loading: false
@@ -83,7 +84,8 @@
     const { menu } = this.state
 
     this.settingRef.handleConfirm('func').then(setting => {
-      let _config = {...config, setting: setting}
+      let res = this.resetSetting(setting)
+      let _config = {...config, setting: res}
       let newLText = Utils.formatOptions(FuncUtils.getTableFunc(setting, menu, _config)) // 鍒涘缓瀛樺偍杩囩▼sql
       let DelText = Utils.formatOptions(FuncUtils.dropfunc(setting.innerFunc))          // 鍒犻櫎瀛樺偍杩囩▼sql
 
@@ -103,7 +105,8 @@
     const { menu } = this.state
 
     this.settingRef.handleConfirm('interface').then(setting => {
-      let _config = {...config, setting: setting}
+      let res = this.resetSetting(setting)
+      let _config = {...config, setting: res}
       let _menu = {
         type: config.Template === 'CommonTable' ? 'main' : 'subtable',
         MenuID: menu.MenuID,
@@ -115,6 +118,30 @@
     })
   }
 
+  resetSetting = (s) => {
+    let setting = fromJS(s).toJS()
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+        setting.scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        setting.preScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        setting.cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        })
+        if (setting.dataresource) {
+          setting.dataresource = setting.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+        }
+      })
+    }
+
+    return setting
+  }
+
   shouldComponentUpdate (nextProps, nextState) {
     return !is(fromJS(this.state), fromJS(nextState))
   }
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.jsx b/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.jsx
index 27b3f4d..4c4b17a 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, Select } from 'antd'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, Select, InputNumber } from 'antd'
 import moment from 'moment'
 
 import Api from '@/api'
@@ -216,6 +216,10 @@
                       required: true,
                       message: dict['form.required.input'] + '琛ㄥ悕!'
                     },
+                    {
+                      max: 50,
+                      message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
+                    }
                   ]
                 })(<Input placeholder={''} autoComplete="off" />)}
               </Form.Item>
@@ -409,7 +413,7 @@
             </Col> : null}
             {interType === 'system' || (interType === 'custom' && requestMode === 'system') ? <Col span={24} className="data-source" style={{paddingLeft: '7px'}}>
               <Form.Item help={'鏁版嵁ID锛�' + menu.MenuID} labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } label={
-                <Tooltip placement="topLeft" title={'浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� \'\'銆� @$ -> */ 鎴� \'\''}>
+                <Tooltip placement="topLeft" title={`浣跨敤绯荤粺鍑芥暟鏃讹紝闇�濉啓鏁版嵁婧愩�傛敞锛氭暟鎹潈闄愭浛鎹㈢ $@ -> /* 鎴� ''銆� @$ -> */ 鎴� ''锛涙煡璇㈡浛鎹㈢ $select@ -> /* 鎴� ''銆� @select$ -> */ 鎴� ''锛涚粺璁℃浛鎹㈢ $sum@ -> /* 鎴� ''銆� @sum$ -> */ 鎴� ''銆俙}>
                   <Icon type="question-circle" />
                   鏁版嵁婧�
                 </Tooltip>
@@ -612,6 +616,18 @@
             </Col>
             <Col span={12}>
               <Form.Item label={
+                <Tooltip placement="topLeft" title="楂樼骇鎼滅储寮圭獥鐨勫搴︼紝娉細褰撳搴﹀�煎皬浜�100鏃惰〃绀哄崰绐楀彛鐨勭櫨鍒嗘瘮锛屽ぇ浜�100鏃惰〃绀哄搴︾殑缁濆鍊笺��">
+                  <Icon type="question-circle" />
+                  楂樼骇鎼滅储
+                </Tooltip>
+              }>
+                {getFieldDecorator('advanceWidth', {
+                  initialValue: setting.advanceWidth || 1000
+                })(<InputNumber min={10} max={3000} precision={0}/>)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
                 <Tooltip placement="topLeft" title="鍙屽嚮琛ㄦ牸涓锛岃Е鍙戠殑鎸夐挳銆�">
                   <Icon type="question-circle" />
                   鍙屽嚮浜嬩欢
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.scss b/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.scss
index a6d2df7..f404309 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.scss
+++ b/src/templates/sharecomponent/settingcomponent/settingform/datasource/index.scss
@@ -17,6 +17,9 @@
       color: #c49f47;
       margin-right: 3px;
     }
+    .ant-input-number {
+      width: 100%;
+    }
   }
 
 }
\ No newline at end of file
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/index.jsx b/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
index a66ce20..f68c91e 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -97,6 +97,24 @@
       })
     }
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _preScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
       setting: _setting,
       search: _search,
@@ -129,32 +147,26 @@
         value: search.initval,
         required: search.required === 'true'
       }
+      
       if (item.type === 'group') {
-        let copy = fromJS(item).toJS()
-        copy.key = search.datefield
+        item.key = search.datefield
+        item.type = 'daterange'
+        item.match = 'between'
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
 
-        item.value = search.initval && search.initval[0] ? search.initval[0] : '@$@'
-        item.match = '='
-        
-        copy.type = 'daterange'
-        copy.match = 'between'
-        copy.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
-
-        if (search.transfer === 'true') {
-          newsearches.push(item)
-        }
-        newsearches.push(copy)
+        newsearches.push(item)
         return
       } else if (item.type === 'date') {
         item.value = moment().format('YYYY-MM-DD')
       } else if (item.type === 'datemonth') {
         item.value = moment().format('YYYY-MM')
       } else if (item.type === 'dateweek') {
-        item.value = [moment().startOf('week').format('YYYY-MM-DD'), moment().endOf('week').format('YYYY-MM-DD')]
+        item.value = moment().format('YYYY-MM-DD')
       } else if (item.type === 'daterange') {
-        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')]
-      } else if (item.type === 'multiselect') {
-        item.value = ['@$@']
+        item.value = [moment().format('YYYY-MM-DD'), moment().format('YYYY-MM-DD')].join(',')
+      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && search.multiple === 'true')) {
+        item.type = 'multi'
+        item.value = '@$@'
       } else {
         item.value = '@$@'
       }
@@ -463,6 +475,7 @@
               setting={setting}
               scripts={scripts}
               defaultSql={defaultSql}
+              urlFields={config.urlFields}
               searches={this.props.search}
               scriptsChange={this.scriptsChange}
               scriptsUpdate={this.scriptsUpdate}
@@ -480,6 +493,7 @@
               setting={setting}
               scripts={preScripts}
               regoptions={regoptions}
+              urlFields={config.urlFields}
               searches={this.props.search}
               scriptsUpdate={this.preScriptsUpdate}
               wrappedComponentRef={(inst) => this.preScriptsForm = inst}
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx b/src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
index 1096b9c..f27e974 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
@@ -20,6 +20,7 @@
     setting: PropTypes.object,      // 璁剧疆
     scripts: PropTypes.array,       // 鑷畾涔夎剼鏈垪琛�
     searches: PropTypes.array,      // 鎼滅储鏉′欢
+    urlFields: PropTypes.any,       // url鍙橀噺
     regoptions: PropTypes.any,      // 姝e垯鏇挎崲
     scriptsChange: PropTypes.func,  // 鑷畾涔夎剼鏈垏鎹㈡椂楠岃瘉
     scriptsUpdate: PropTypes.func   // 琛ㄥ崟
@@ -100,7 +101,7 @@
   }
 
   UNSAFE_componentWillMount() {
-    const { searches, scripts } = this.props
+    const { searches, scripts, urlFields } = this.props
 
     let _usefulFields = []
     let scriptsColumns = fromJS(this.state.scriptsColumns).toJS()
@@ -109,9 +110,7 @@
       searches.forEach(item => {
         if (!item.field) return
         if (item.type === 'group') {
-          if (item.transfer === 'true') {
-            _usefulFields.push(item.field)
-          }
+          _usefulFields.push(item.field)
           _usefulFields.push(item.datefield)
           _usefulFields.push(item.datefield + '1')
         } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
@@ -123,6 +122,11 @@
           _usefulFields.push(item.field)
         }
       })
+
+      if (urlFields) {
+        _usefulFields.push(...urlFields)
+      }
+      
       _usefulFields = _usefulFields.join(', ')
       scriptsColumns = scriptsColumns.filter(item => {
         if (item.dataIndex === 'sql') {
diff --git a/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx b/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
index 2801901..003b030 100644
--- a/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
+++ b/src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
@@ -26,13 +26,22 @@
     if (setting.default === 'false') {
       _dataresource = ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
-    if (_dataresource) {
-      _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
-    }
-    if (_customScript) {
-      _customScript = _customScript.replace(/@\$|\$@/ig, '')
-    }
+    _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
+    _customScript = _customScript.replace(/@\$|\$@/ig, '')
+    _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
+    _customScript = _customScript.replace(/@select\$|\$select@/ig, '')
+    _dataresource = _dataresource.replace(/@sum\$|\$sum@/ig, '')
+    _customScript = _customScript.replace(/@sum\$|\$sum@/ig, '')
+
     // 澶栬仈鏁版嵁搴撴浛鎹�
     if (window.GLOB.externalDatabase !== null) {
       _dataresource = _dataresource.replace(/@db@/ig, window.GLOB.externalDatabase)
@@ -138,6 +147,13 @@
       `
     }
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
+
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@userName@|@fullName@|@login_city@/ig, `''`)
     // 澶栬仈鏁版嵁搴撴浛鎹�
diff --git a/src/templates/sharecomponent/tablecomponent/index.jsx b/src/templates/sharecomponent/tablecomponent/index.jsx
index e52ef08..0ff4bcf 100644
--- a/src/templates/sharecomponent/tablecomponent/index.jsx
+++ b/src/templates/sharecomponent/tablecomponent/index.jsx
@@ -137,6 +137,7 @@
                 datatype: _type,
                 decimal: _decimal,
                 length: _length,
+                $datatype: item.FieldType.toLowerCase()
               }
             })
           }
diff --git a/src/templates/sharecomponent/treesettingcomponent/index.jsx b/src/templates/sharecomponent/treesettingcomponent/index.jsx
index 359d52f..db18c0b 100644
--- a/src/templates/sharecomponent/treesettingcomponent/index.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/index.jsx
@@ -45,6 +45,17 @@
       loading: true
     })
     this.settingRef.handleConfirm().then(res => {
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          res.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          if (res.dataresource) {
+            res.dataresource = res.dataresource.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          }
+        })
+      }
       this.setState({
         visible: false,
         loading: false
diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/datasource/index.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/datasource/index.jsx
index 4d1c6f3..caadc2b 100644
--- a/src/templates/sharecomponent/treesettingcomponent/settingform/datasource/index.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/settingform/datasource/index.jsx
@@ -201,8 +201,8 @@
                       message: dict['form.required.input'] + '琛ㄥ悕!'
                     },
                     {
-                      max: formRule.input.max,
-                      message: formRule.input.message
+                      max: 50,
+                      message: '琛ㄥ悕鏈�闀夸负50涓瓧绗�!'
                     }
                   ]
                 })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit}/>)}
diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
index 056813e..3f3d3a4 100644
--- a/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
@@ -35,6 +35,18 @@
     let _setting = fromJS(config.setting).toJS()
     let _scripts = _setting.scripts || []
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        if (_setting.dataresource) {
+          _setting.dataresource = _setting.dataresource.replace(reg, `$ex@${m.func_code}@ex$`)
+        }
+      })
+    }
+
     this.setState({
       setting: _setting,
       scripts: _scripts
diff --git a/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
index 721c7c9..332934c 100644
--- a/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
+++ b/src/templates/sharecomponent/treesettingcomponent/settingform/utils.jsx
@@ -26,6 +26,14 @@
     if (setting.default === 'false') {
       _dataresource = ''
     }
+
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(item => {
+        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+      })
+    }
     
     _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
     _customScript = _customScript.replace(/@\$|\$@/ig, '')
diff --git a/src/templates/subtableconfig/index.jsx b/src/templates/subtableconfig/index.jsx
index d3bda26..34bf35d 100644
--- a/src/templates/subtableconfig/index.jsx
+++ b/src/templates/subtableconfig/index.jsx
@@ -26,6 +26,7 @@
 const { Panel } = Collapse
 const { confirm } = Modal
 
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
 const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -1008,6 +1009,7 @@
               </div>
             } bordered={false} extra={
               <div>
+                <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
                 <EditComponent dict={this.state.dict} options={['search', 'action', 'columns']} config={config} MenuID={config.uuid} thawButtons={this.state.thawButtons} refresh={this.updateConfig}/>
                 <Switch className="big" checkedChildren="鍚�" unCheckedChildren="鍋�" checked={config.enabled} onChange={this.onEnabledChange} />
                 <Button type="primary" onClick={this.submitConfig} loading={this.state.menuloading}>{this.state.dict['model.save']}</Button>
diff --git a/src/templates/subtableconfig/source.jsx b/src/templates/subtableconfig/source.jsx
index 4c69050..4ccd3bf 100644
--- a/src/templates/subtableconfig/source.jsx
+++ b/src/templates/subtableconfig/source.jsx
@@ -206,6 +206,12 @@
     },
     {
       type: 'search',
+      label: '閫夐」鍗�',
+      subType: 'checkcard',
+      url: ''
+    },
+    {
+      type: 'search',
       label: CommonDict['model.form.dateday'],
       subType: 'date',
       url: ''
@@ -329,6 +335,12 @@
       label: CommonDict['model.form.colspan'],
       subType: 'colspan',
       url: ''
+    },
+    {
+      type: 'columns',
+      label: '搴忓彿',
+      subType: 'index',
+      url: ''
     }
   ]
 }
diff --git a/src/templates/treepageconfig/index.jsx b/src/templates/treepageconfig/index.jsx
index 8a4b4dd..d1aa9bd 100644
--- a/src/templates/treepageconfig/index.jsx
+++ b/src/templates/treepageconfig/index.jsx
@@ -501,6 +501,7 @@
       }
 
       let submenu = menu.fstMenuList.filter(item => item.MenuID === config.fstMenuId)[0]
+
       let _Menu = {
         ...menu,
         LongParam: config,
@@ -509,7 +510,7 @@
         MenuNo: config.MenuNo,
         ParentId: config.ParentId,
         fstMenuId: config.fstMenuId,
-        supMenuList: submenu ? submenu.options : []
+        supMenuList: submenu ? submenu.children : []
       }
 
       _Menu.activeKey = activeKey       // 淇濆瓨褰撳墠鎵撳紑椤电
diff --git a/src/templates/zshare/basetransferform/index.jsx b/src/templates/zshare/basetransferform/index.jsx
index 8dd7462..c3e3233 100644
--- a/src/templates/zshare/basetransferform/index.jsx
+++ b/src/templates/zshare/basetransferform/index.jsx
@@ -6,7 +6,8 @@
 
 class TransferForm extends Component {
   static propTypes = {
-    menulist: PropTypes.array
+    menulist: PropTypes.array,
+    onChange: PropTypes.func
   }
 
   state = {
@@ -16,6 +17,7 @@
 
   handleChange = (nextTargetKeys, direction, moveKeys) => {
     this.setState({ targetKeys: nextTargetKeys })
+    this.props.onChange(nextTargetKeys)
   }
 
   handleSelectChange = (sourceSelectedKeys, targetSelectedKeys) => {
diff --git a/src/templates/zshare/customscript/index.jsx b/src/templates/zshare/customscript/index.jsx
index a69270f..e2db585 100644
--- a/src/templates/zshare/customscript/index.jsx
+++ b/src/templates/zshare/customscript/index.jsx
@@ -19,6 +19,7 @@
     setting: PropTypes.object,      // 璁剧疆
     scripts: PropTypes.array,       // 鑷畾涔夎剼鏈垪琛�
     searches: PropTypes.array,      // 鎼滅储鏉′欢
+    urlFields: PropTypes.any,       // url鍙橀噺
     defaultSql: PropTypes.string,   // 榛樿sql
     scriptsChange: PropTypes.func,  // 鑷畾涔夎剼鏈垏鎹㈡椂楠岃瘉
     scriptsUpdate: PropTypes.func   // 琛ㄥ崟
@@ -87,15 +88,13 @@
   }
 
   UNSAFE_componentWillMount() {
-    const { searches, scripts } = this.props
+    const { searches, scripts, urlFields } = this.props
 
     let _usefulFields = []
     searches.forEach(item => {
       if (!item.field) return
       if (item.type === 'group') {
-        if (item.transfer === 'true') {
-          _usefulFields.push(item.field)
-        }
+        _usefulFields.push(item.field)
         _usefulFields.push(item.datefield)
         _usefulFields.push(item.datefield + '1')
       } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
@@ -108,6 +107,10 @@
       }
     })
 
+    if (urlFields) {
+      _usefulFields.push(...urlFields)
+    }
+
     this.setState({
       usefulFields: _usefulFields.join(', '),
       scripts: fromJS(scripts).toJS()
diff --git a/src/templates/zshare/editTable/index.jsx b/src/templates/zshare/editTable/index.jsx
index 9f96d5f..5e1d00b 100644
--- a/src/templates/zshare/editTable/index.jsx
+++ b/src/templates/zshare/editTable/index.jsx
@@ -2,7 +2,7 @@
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
 import { DndProvider, DragSource, DropTarget } from 'react-dnd'
-import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification, message, Modal } from 'antd'
+import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification, message, Modal, Typography } from 'antd'
 
 import Utils from '@/utils/utils.js'
 import ColorSketch from '@/mob/colorsketch'
@@ -15,6 +15,7 @@
 let eTDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
 const EditableContext = React.createContext()
 let dragingIndex = -1
+const { Paragraph } = Typography
 
 class BodyRow extends React.Component {
   render() {
@@ -170,6 +171,7 @@
   UNSAFE_componentWillMount () {
     const { data, actions } = this.props
     let columns = fromJS(this.props.columns).toJS()
+    let operation = null
 
     if (actions && (actions.includes('edit') || actions.includes('copy') || actions.includes('del'))) {
       let _operation = null
@@ -180,7 +182,7 @@
         return item.dataIndex !== 'operation'
       })
 
-      let operation = {
+      operation = {
         title: (<div>
           {eTDict['model.operation']}
           {actions.includes('copy') ? (
@@ -232,7 +234,7 @@
 
     this.setState({
       data: data || [],
-      oricolumns: fromJS(this.props.columns).toJS(),
+      operation,
       columns
     })
   }
@@ -240,19 +242,26 @@
   UNSAFE_componentWillReceiveProps (nextProps) {
     if (!is(fromJS(this.state.data), fromJS(nextProps.data))) {
       this.setState({data: nextProps.data, editingKey: ''})
-    } else if (!is(fromJS(this.state.oricolumns), fromJS(nextProps.columns))) {
-      let cols = {}
-      nextProps.columns.forEach(col => {cols[col.dataIndex] = col})
-
-      this.setState({
-        oricolumns: fromJS(nextProps.columns).toJS(),
-        columns: this.state.columns.map(col => {
-          if (cols[col.dataIndex]) {
-            return cols[col.dataIndex]
-          }
-          return col
+    } else if (!is(fromJS(this.props.columns), fromJS(nextProps.columns))) {
+      if (nextProps.columns.length === this.props.columns.length) {
+        let cols = {}
+        nextProps.columns.forEach(col => {cols[col.dataIndex] = col})
+  
+        this.setState({
+          columns: this.state.columns.map(col => {
+            if (cols[col.dataIndex]) {
+              return cols[col.dataIndex]
+            }
+            return col
+          })
         })
-      })
+      } else {
+        let columns = fromJS(nextProps.columns).toJS()
+        if (this.state.operation) {
+          columns.push(this.state.operation)
+        }
+        this.setState({columns})
+      }
     }
   }
 
@@ -353,7 +362,7 @@
   
           if (!unique) return
   
-          data.unshift(cell)
+          data.push(cell)
         })
 
         this.setState({ data, editingKey: '', visible: false }, () => {
@@ -493,7 +502,10 @@
       moveprops.moveRow = this.moveRow
     }
     
-    const columns = this.state.columns.map(col => {
+    let  columns = this.state.columns.map(col => {
+      if (col.copy) {
+        col.render = (text) => (<Paragraph copyable>{text}</Paragraph>)
+      }
       if (!col.editable) return col
       return {
         ...col,
@@ -513,6 +525,19 @@
       }
     })
 
+    columns.unshift({
+      title: '搴忓彿',
+      dataIndex: '$index',
+      className: 'mk-index',
+      width: '60px',
+    })
+
+    const data = this.state.data.map((item, index) => {
+      item.$index = index + 1
+
+      return item
+    })
+
     return (
       <EditableContext.Provider value={this.props.form}>
         <div className="modal-edit-table">
@@ -521,7 +546,7 @@
               bordered
               rowKey="uuid"
               components={components}
-              dataSource={this.state.data}
+              dataSource={data}
               columns={columns}
               rowClassName="editable-row"
               pagination={false}
diff --git a/src/templates/zshare/editTable/index.scss b/src/templates/zshare/editTable/index.scss
index 5943f34..8713c7f 100644
--- a/src/templates/zshare/editTable/index.scss
+++ b/src/templates/zshare/editTable/index.scss
@@ -20,6 +20,10 @@
       padding: 0px;
     }
   }
+  .mk-index {
+    text-align: center;
+    white-space: nowrap;
+  }
 
   thead tr th:last-child {
     text-align: center;
diff --git a/src/templates/zshare/editcomponent/index.jsx b/src/templates/zshare/editcomponent/index.jsx
index 80f2599..6fd72b8 100644
--- a/src/templates/zshare/editcomponent/index.jsx
+++ b/src/templates/zshare/editcomponent/index.jsx
@@ -1,7 +1,7 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { fromJS } from 'immutable'
-import { Menu, Dropdown, Icon, Modal, Spin, notification } from 'antd'
+import { Modal, Spin, notification, Button } from 'antd'
 
 import Api from '@/api'
 import Utils from '@/utils/utils.js'
@@ -25,14 +25,7 @@
     thawVisible: false,
     thawbtnlist: null,
     pasteVisible: false,
-  }
-
-  handleMenuClick = e => {
-    if (e.key === 'thaw') {
-      this.handleThaw()
-    } else if (e.key === 'paste') {
-      this.setState({pasteVisible: true})
-    }
+    targetKeys: []
   }
 
   /**
@@ -42,7 +35,8 @@
     const { MenuID } = this.props
 
     this.setState({
-      thawVisible: true
+      thawVisible: true,
+      targetKeys: []
     })
 
     Api.getSystemConfig({
@@ -92,32 +86,31 @@
    */
   thawBtnSubmit = () => {
     const { thawButtons } = this.props
-    const { thawbtnlist, dict } = this.state
+    const { thawbtnlist, dict, targetKeys } = this.state
     let config = fromJS(this.props.config).toJS()
 
-    // 涓夌骇鑿滃崟瑙i櫎鍐荤粨
-    if (this.refs.trawmenu.state.targetKeys.length === 0) {
+    if (targetKeys.length === 0) {
       notification.warning({
         top: 92,
         message: dict['form.required.select'] + dict['header.form.thawbutton'],
         duration: 5
       })
     } else {
-
       thawbtnlist.forEach(item => {
-        if (this.refs.trawmenu.state.targetKeys.includes(item.key)) {
+        if (targetKeys.includes(item.key)) {
           config.action.push(item.btnParam)
         }
       })
 
       this.props.refresh({
         type: 'thaw',
-        thawButtons: [...thawButtons, ...this.refs.trawmenu.state.targetKeys],
+        thawButtons: [...thawButtons, ...targetKeys],
         config: config
       })
 
       this.setState({
-        thawVisible: false
+        thawVisible: false,
+        targetKeys: []
       })
     }
   }
@@ -141,26 +134,10 @@
             config: _config
           })
         })
-      } else if (options.includes('search') && (res.copyType === 'search' || res.copyType === 'form')) {
+      } else if (options.includes('search') && res.copyType === 'search') {
         res.uuid = Utils.getuuid()
         _config.search = _config.search.filter(item => !item.origin)
         let keys = _config.search.map(item => item.field.toLowerCase())
-
-        // search锛� text select multiselect link date dateweek datemonth daterange group
-        // form锛� text number select multiselect link switch checkbox radio checkcard
-        //       fileupload date datemonth datetime textarea hint color funcvar
-        if (res.copyType === 'form') {
-          if (['number', 'switch', 'textarea', 'checkcard', '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'
-          }
-        }
-        res.copyType = 'search'
 
         _config.search.push(res)
 
@@ -206,20 +183,10 @@
             config: _config
           })
         })
-      } else if (options.includes('form') && (res.copyType === 'form' || res.copyType === 'search')) {
+      } else if (options.includes('form') && res.copyType === 'form') {
         let fields = []
         let labels = []
         res.uuid = Utils.getuuid()
-
-        // search锛� text select multiselect link date dateweek datemonth daterange group
-        // form锛� text number select multiselect link switch checkbox radio checkcard
-        //       fileupload date datemonth datetime textarea hint color funcvar
-        if (res.copyType === 'search') {
-          if (res.type === 'dateweek' || res.type === 'daterange' || res.type === 'group') {
-            res.type = 'date'
-          }
-        }
-        res.copyType = 'form'
 
         _config.fields.forEach(item => {
           item.field && fields.push(item.field.toLowerCase())
@@ -262,33 +229,32 @@
     })
   }
 
+  handleMenuClick = e => {
+    if (e.key === 'thaw') {
+      this.handleThaw()
+    } else if (e.key === 'paste') {
+      this.setState({pasteVisible: true})
+    }
+  }
+
   render() {
     const { MenuID } = this.props
     const { dict } = this.state
-    const menu = (
-      <Menu onClick={this.handleMenuClick}>
-        {MenuID ? <Menu.Item key="thaw"><Icon type="unlock" />{dict['header.form.thawbutton']}</Menu.Item> : null}
-        <Menu.Item key="paste"><Icon type="snippets" />{dict['header.form.paste']}</Menu.Item>
-      </Menu>
-    )
 
     return (
       <div style={{display: 'inline-block'}}>
-        <Dropdown overlay={menu} overlayClassName="edit-component-box">
-          <span style={{color: '#1890ff', display: 'inline-block', height: 25}}>
-            {dict['model.edit']} <Icon type="down" />
-          </span>
-        </Dropdown>
+        {MenuID ? <Button className="mk-border-green" onClick={this.handleThaw} icon="unlock">{dict['header.form.thawbutton']}</Button> : null}
+        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={() => this.setState({pasteVisible: true})} icon="snippets">{dict['header.form.paste']}</Button>
         {/* 瑙e喕鎸夐挳妯℃�佹 */}
         <Modal
           title={dict['header.form.thawbutton']}
           visible={this.state.thawVisible}
           onOk={this.thawBtnSubmit}
-          onCancel={() => {this.setState({thawVisible: false, thawbtnlist: null})}}
+          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 ref="trawmenu" menulist={this.state.thawbtnlist}/>}
+          {this.state.thawbtnlist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawbtnlist}/>}
         </Modal>
         {/* 鎸夐挳閰嶇疆淇℃伅绮樿创澶嶅埗 */}
         <Modal
diff --git a/src/templates/zshare/formconfig.jsx b/src/templates/zshare/formconfig.jsx
index 759648c..2b1c010 100644
--- a/src/templates/zshare/formconfig.jsx
+++ b/src/templates/zshare/formconfig.jsx
@@ -288,6 +288,7 @@
  */
 export function getSearchForm (card, linkableFields) {
   let roleList = sessionStorage.getItem('sysRoles')
+  let appType = sessionStorage.getItem('appType')
   if (roleList) {
     try {
       roleList = JSON.parse(roleList)
@@ -296,6 +297,71 @@
     }
   } else {
     roleList = []
+  }
+
+  let typeOptions = []
+
+  if (appType === 'mob') {
+    typeOptions = [{
+      value: 'range',
+      text: '鏁板�硷紙鍖洪棿锛�'
+    }, {
+      value: 'checkcard',
+      text: '閫夐」鍗�'
+    }, {
+      value: 'date',
+      text: Formdict['model.form.dateday']
+    }, {
+      value: 'datemonth',
+      text: Formdict['model.form.datemonth']
+    }, {
+      value: 'daterange',
+      text: Formdict['model.form.daterange']
+    }]
+  } else {
+    typeOptions = [{
+      value: 'text',
+      text: Formdict['model.form.text']
+    }, {
+      value: 'select',
+      text: Formdict['model.form.select']
+    }, {
+      value: 'multiselect',
+      text: Formdict['model.form.multiselect']
+    }, {
+      value: 'link',
+      text: Formdict['model.form.link']
+    }, {
+      value: 'checkcard',
+      text: '閫夐」鍗�'
+    }, {
+      value: 'date',
+      text: Formdict['model.form.dateday']
+    }, {
+      value: 'dateweek',
+      text: Formdict['model.form.dateweek']
+    }, {
+      value: 'datemonth',
+      text: Formdict['model.form.datemonth']
+    }, {
+      value: 'daterange',
+      text: Formdict['model.form.daterange']
+    }, {
+      value: 'group',
+      text: Formdict['model.form.dategroup']
+    }]
+  }
+
+  if (card.focus) {
+    if (['text', 'multiselect'].includes(card.type)) {
+      card.match = 'like'
+    } else if (['select', 'link', 'checkcard'].includes(card.type)) {
+      card.match = '='
+    } else if (card.type === 'date') {
+      card.match = '>='
+    } else if (['datemonth', 'dateweek', 'daterange', 'range'].includes(card.type)) {
+      card.match = 'between'
+    }
   }
 
   return [
@@ -322,34 +388,7 @@
       label: Formdict['model.form.type'],
       initVal: card.type,
       required: true,
-      options: [{
-        value: 'text',
-        text: Formdict['model.form.text']
-      }, {
-        value: 'select',
-        text: Formdict['model.form.select']
-      }, {
-        value: 'multiselect',
-        text: Formdict['model.form.multiselect']
-      }, {
-        value: 'link',
-        text: Formdict['model.form.link']
-      }, {
-        value: 'date',
-        text: Formdict['model.form.dateday']
-      }, {
-        value: 'dateweek',
-        text: Formdict['model.form.dateweek']
-      }, {
-        value: 'datemonth',
-        text: Formdict['model.form.datemonth']
-      }, {
-        value: 'daterange',
-        text: Formdict['model.form.daterange']
-      }, {
-        value: 'group',
-        text: Formdict['model.form.dategroup']
-      }]
+      options: typeOptions
     },
     {
       type: 'text',
@@ -363,7 +402,7 @@
       type: 'text',
       key: 'initval',
       label: Formdict['header.form.initval'],
-      tooltip: '绫诲瀷涓轰笅鎷夎彍鍗曟椂锛屽垵濮嬪�煎簲涓烘暟鎹殑Value鍊硷紙浣跨敤鏁版嵁婧愭椂锛屽簲涓恒�婂�悸峰瓧娈点�嬬殑鍊硷級',
+      tooltip: '绫诲瀷涓轰笅鎷夎彍鍗曟椂锛屽垵濮嬪�煎簲涓烘暟鎹殑Value鍊硷紙浣跨敤鏁版嵁婧愭椂锛屽簲涓恒�婂�悸峰瓧娈点�嬬殑鍊硷級;绫诲瀷涓烘暟鍊硷紙鍖洪棿锛夋椂锛屽垵濮嬪�间娇鐢ㄩ�楀彿鎷兼帴锛屼緥濡� 3,10',
       initVal: card.initval,
       required: false
     },
@@ -395,6 +434,75 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'display',
+      label: '鏄剧ず',
+      initVal: card.display || 'text',
+      required: true,
+      options: [{
+        value: 'text',
+        text: '鏂囨湰'
+      }, {
+        value: 'picture',
+        text: '鍥剧墖'
+      }]
+    },
+    {
+      type: 'number',
+      key: 'width',
+      min: 1,
+      max: 24,
+      precision: 0,
+      label: '鍏冪礌瀹藉害',
+      initVal: card.width || 4,
+      tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
+      required: true
+    },
+    {
+      type: 'text',
+      key: 'cardValField',
+      label: Formdict['header.form.valueField'],
+      initVal: card.cardValField || 'Value',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'text',
+      key: 'urlField',
+      label: '鍦板潃瀛楁',
+      initVal: card.urlField || '',
+      required: true,
+      readonly: false
+    },
+    {
+      type: 'radio',
+      key: 'picratio',
+      label: '鍥剧墖姣斾緥',
+      initVal: card.picratio || '1:1',
+      required: true,
+      options: [{
+        value: '1:1',
+        text: '1:1'
+      }, {
+        value: '3:2',
+        text: '3:2'
+      }, {
+        value: '4:3',
+        text: '4:3'
+      }, {
+        value: '16:9',
+        text: '16:9'
+      }]
+    },
+    {
+      type: 'fields',
+      key: 'fields',
+      label: '瀛楁闆�',
+      initVal: card.fields || [],
+      required: true,
+      readonly: false
+    },
+    {
       type: 'textarea',
       key: 'dataSource',
       label: Formdict['header.form.datasource'],
@@ -405,7 +513,7 @@
     {
       type: 'options',
       key: 'options',
-      label: '',
+      label: '閫夐」',
       initVal: card.options || [],
       required: true,
       readonly: false
@@ -506,20 +614,6 @@
         text: '>='
       }]
     },
-    // {
-    //   type: 'select',
-    //   key: 'display',
-    //   label: Formdict['header.form.display'],
-    //   initVal: card.display || 'dropdown',
-    //   required: true,
-    //   options: [{
-    //     value: 'dropdown',
-    //     text: Formdict['header.form.dropdown']
-    //   // }, {
-    //   //   value: 'button',
-    //   //   text: Formdict['header.form.button']
-    //   }]
-    // },
     {
       type: 'radio',
       key: 'database',
@@ -540,8 +634,23 @@
       max: 24,
       label: Formdict['header.form.ratio'],
       tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
-      initVal: card.ratio,
+      initVal: card.ratio || 6,
+      forbid: appType === 'mob',
       required: false
+    },
+    {
+      type: 'radio',
+      key: 'multiple',
+      label: '鍙閫�',
+      initVal: card.multiple || 'false',
+      required: true,
+      options: [{
+        value: 'true',
+        text: '鏄�'
+      }, {
+        value: 'false',
+        text: '鍚�'
+      }]
     },
     {
       type: 'radio',
@@ -569,19 +678,44 @@
         text: Formdict['model.false']
       }]
     },
+    // {
+    //   type: 'radio',
+    //   key: 'transfer',
+    //   label: '浼犻��',
+    //   initVal: card.transfer || 'false',
+    //   tooltip: '鏁版嵁鏌ヨ鏃讹紝绫诲瀷瀛楁鏄惁浣滀负鍙傛暟浼犻�掞紝绫诲瀷瀛楁瀵瑰簲鍊间负 {"鏃�": "day", "鍛�": "week", "鏈�": "month", "瀛�": "quarter", "骞�": "year", "鑷畾涔�": "customized"}銆�',
+    //   options: [{
+    //     value: 'true',
+    //     text: Formdict['model.true']
+    //   }, {
+    //     value: 'false',
+    //     text: Formdict['model.false']
+    //   }]
+    // },
     {
-      type: 'radio',
-      key: 'transfer',
-      label: '浼犻��',
-      initVal: card.transfer || 'false',
-      tooltip: '鏁版嵁鏌ヨ鏃讹紝绫诲瀷瀛楁鏄惁浣滀负鍙傛暟浼犻�掞紝绫诲瀷瀛楁瀵瑰簲鍊间负 {"鏃�": "day", "鍛�": "week", "鏈�": "month", "瀛�": "quarter", "骞�": "year", "鑷畾涔�": "customized"}銆�',
-      options: [{
-        value: 'true',
-        text: Formdict['model.true']
-      }, {
-        value: 'false',
-        text: Formdict['model.false']
-      }]
+      type: 'number',
+      key: 'maxValue',
+      label: '鏈�澶у��',
+      initVal: card.maxValue,
+      forbid: appType !== 'mob',
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'minValue',
+      label: '鏈�灏忓��',
+      initVal: card.minValue,
+      forbid: appType !== 'mob',
+      required: true
+    },
+    {
+      type: 'number',
+      key: 'step',
+      label: '姝ラ暱',
+      initVal: card.step,
+      tooltip: '姝ラ暱鍙栧�煎繀椤诲ぇ浜� 0锛屽苟涓斿彲琚� (max - min) 鏁撮櫎',
+      forbid: appType !== 'mob',
+      required: true
     },
     {
       type: 'radio',
@@ -595,6 +729,50 @@
         value: 'false',
         text: Formdict['model.false']
       }]
+    },
+    {
+      type: 'radio',
+      key: 'advanced',
+      label: '楂樼骇鎼滅储',
+      initVal: card.advanced || 'false',
+      forbid: appType === 'mob',
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'inputType',
+      label: '杈撳叆鏍峰紡',
+      initVal: card.inputType || 'input',
+      required: false,
+      forbid: appType === null,
+      options: [{
+        value: 'input',
+        text: '杈撳叆妗�'
+      }, {
+        value: 'search',
+        text: '鎼滅储妗�'
+      }]
+    },
+    {
+      type: 'color',
+      key: 'backgroundColor',
+      label: '鑳屾櫙鑹�',
+      initVal: card.backgroundColor || '',
+      tooltip: '璁剧疆鑳屾櫙鑹插悗锛岄�変腑鏁堟灉鐢辫儗鏅鑹叉帶鍒躲��',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'borderColor',
+      label: '杈规棰滆壊',
+      initVal: card.borderColor || '',
+      required: false
     },
     {
       type: 'multiselect',
@@ -616,6 +794,8 @@
  * @param {*} type           鎸夐挳绫诲瀷锛岀敤浜庡尯鍒嗗彲閫夌殑鎵撳紑鏂瑰紡
  */
 export function getActionForm (card, functip, config, usefulFields, type, menulist = [], printTemps = []) {
+  let columns = (config.columns || []).filter(col => col.field)
+
   let opentypes = [
     {
       value: 'pop',
@@ -1126,6 +1306,23 @@
         value: 'false',
         text: '闈炲繀濉�'
       }]
+    },
+    {
+      type: 'select',
+      key: 'controlField',
+      label: '鎺у埗瀛楁',
+      tooltip: '绂佺敤鎺у埗瀛楁锛屽彲鏍规嵁鏁版嵁鎺у埗鎸夐挳鏄惁绂佺敤銆�',
+      initVal: card.controlField || '',
+      required: false,
+      options: [{label: '鏃�', field: ''}, ...columns]
+    },
+    {
+      type: 'text',
+      key: 'controlVal',
+      label: '鎺у埗鍊�',
+      tooltip: '褰撻�夋嫨鎺у埗瀛楁锛屼笖瀛楁鍊间笌鎺у埗鍊肩浉绛夋椂锛屾寜閽細绂佺敤锛屽涓�肩敤閫楀彿鍒嗛殧銆�',
+      initVal: card.controlVal || '',
+      required: false
     }
   ]
 }
@@ -1188,6 +1385,9 @@
       }, {
         value: 'textarea',
         text: Formdict['model.form.textarea']
+      }, {
+        value: 'index',
+        text: '搴忓彿'
       }]
     },
     {
@@ -1906,6 +2106,7 @@
  * @param {*} subtable        // 鏄惁涓哄瓙琛ㄨ〃鍗�
  */
 export function getModalForm (card, inputfields = [], tabfields = [], linkableFields, linksupFields, subtable = false) {
+  let appType = sessionStorage.getItem('appType')
   let roleList = sessionStorage.getItem('sysRoles')
   if (roleList) {
     try {
@@ -1924,10 +2125,118 @@
     roleList = []
   }
   
-  let _openType = []
+  let _openType = [{
+    value: 'text',
+    text: Formdict['model.form.text']
+  }, {
+    value: 'number',
+    text: Formdict['model.form.number']
+  }, {
+    value: 'select',
+    text: Formdict['model.form.select']
+  }, {
+    value: 'multiselect',
+    text: Formdict['model.form.multiselect']
+  }, {
+    value: 'link',
+    text: Formdict['model.form.link']
+  }, {
+    value: 'switch',
+    text: '寮�鍏�'
+  }, {
+    value: 'checkbox',
+    text: '澶氶�夋'
+  }, {
+    value: 'radio',
+    text: '鍗曢�夋'
+  }, {
+    value: 'checkcard',
+    text: '閫夐」鍗�'
+  }, {
+    value: 'fileupload',
+    text: Formdict['header.form.fileupload']
+  }, {
+    value: 'date',
+    text: Formdict['model.form.dateday']
+  }, {
+    value: 'datemonth',
+    text: Formdict['model.form.datemonth']
+  }, {
+    value: 'datetime',
+    text: Formdict['model.form.datetime']
+  }, {
+    value: 'textarea',
+    text: Formdict['model.form.textarea']
+  }, {
+    value: 'color',
+    text: Formdict['model.form.color']
+  }, {
+    value: 'brafteditor',
+    text: '瀵屾枃鏈�'
+  }, {
+    value: 'funcvar',
+    text: Formdict['header.form.funcvar']
+  }, {
+    value: 'hint',
+    text: '鎻愮ず'
+  }, {
+    value: 'split',
+    text: '鍒嗛殧绾�'
+  }]
+
   let _fieldlength = 50
 
-  if (subtable) {
+  if (appType === 'mob') {
+    _openType = [{
+      value: 'text',
+      text: Formdict['model.form.text']
+    }, {
+      value: 'number',
+      text: Formdict['model.form.number']
+    }, {
+      value: 'select',
+      text: '閫夋嫨鍣�'
+    }, {
+      value: 'link',
+      text: Formdict['model.form.link']
+    }, {
+      value: 'switch',
+      text: '寮�鍏�'
+    }, {
+      value: 'checkbox',
+      text: '澶氶�夋'
+    }, {
+      value: 'radio',
+      text: '鍗曢�夋'
+    }, {
+      value: 'checkcard',
+      text: '閫夐」鍗�'
+    }, {
+      value: 'fileupload',
+      text: Formdict['header.form.fileupload']
+    }, {
+      value: 'date',
+      text: Formdict['model.form.dateday']
+    }, {
+      value: 'datemonth',
+      text: Formdict['model.form.datemonth']
+    }, {
+      value: 'datetime',
+      text: Formdict['model.form.datetime']
+    }, {
+      value: 'textarea',
+      text: Formdict['model.form.textarea']
+    }, {
+      value: 'funcvar',
+      text: Formdict['header.form.funcvar']
+    }, {
+      value: 'hint',
+      text: '鎻愮ず'
+    }, {
+      value: 'split',
+      text: '鍒嗛殧绾�'
+    }]
+  } else if (subtable) {
     _openType.push({
       value: 'linkMain',
       text: Formdict['header.form.linkMain']
@@ -1963,65 +2272,7 @@
       label: Formdict['model.form.type'],
       initVal: card.type,
       required: true,
-      options: [{
-        value: 'text',
-        text: Formdict['model.form.text']
-      }, {
-        value: 'number',
-        text: Formdict['model.form.number']
-      }, {
-        value: 'select',
-        text: Formdict['model.form.select']
-      }, {
-        value: 'multiselect',
-        text: Formdict['model.form.multiselect']
-      }, {
-        value: 'link',
-        text: Formdict['model.form.link']
-      }, {
-        value: 'switch',
-        text: '寮�鍏�'
-      }, {
-        value: 'checkbox',
-        text: '澶氶�夋'
-      }, {
-        value: 'radio',
-        text: '鍗曢�夋'
-      }, {
-        value: 'checkcard',
-        text: '閫夐」鍗�'
-      }, {
-        value: 'fileupload',
-        text: Formdict['header.form.fileupload']
-      }, {
-        value: 'date',
-        text: Formdict['model.form.dateday']
-      }, {
-        value: 'datemonth',
-        text: Formdict['model.form.datemonth']
-      }, {
-        value: 'datetime',
-        text: Formdict['model.form.datetime']
-      }, {
-        value: 'textarea',
-        text: Formdict['model.form.textarea']
-      }, {
-        value: 'color',
-        text: Formdict['model.form.color']
-      }, {
-        value: 'brafteditor',
-        text: '瀵屾枃鏈�'
-      }, {
-        value: 'funcvar',
-        text: Formdict['header.form.funcvar']
-      }, {
-        value: 'hint',
-        text: '鎻愮ず'
-      }, {
-        value: 'split',
-        text: '鍒嗛殧绾�'
-      },
-      ..._openType]
+      options: _openType
     },
     {
       type: 'text',
@@ -2058,14 +2309,16 @@
       key: 'openText',
       label: '寮�鍚彁绀�',
       initVal: card.openText || '',
-      required: false
+      required: false,
+      forbid: appType === 'mob'
     },
     {
       type: 'text',
       key: 'closeText',
       label: '鍏抽棴鎻愮ず',
       initVal: card.closeText || '',
-      required: false
+      required: false,
+      forbid: appType === 'mob'
     },
     {
       type: 'radio',
@@ -2101,7 +2354,7 @@
       min: 1,
       max: 24,
       precision: 0,
-      label: '鍗$墖瀹藉害',
+      label: '鍏冪礌瀹藉害',
       initVal: card.width || 4,
       tooltip: '鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��',
       required: true
@@ -2277,11 +2530,12 @@
     {
       type: 'number',
       key: 'maxRows',
-      min: 2,
+      min: 1,
       max: 100,
       precision: 0,
-      label: Formdict['header.form.maxRows'],
-      initVal: card.maxRows || 6,
+      label: appType === 'mob' ? '琛屾暟' : Formdict['header.form.maxRows'],
+      tooltip: appType === 'mob' ? '琛屾暟涓虹┖鏃讹紝楂樺害鑷�傚簲' : '',
+      initVal: card.maxRows || (appType === 'mob' ? '' : 6),
       required: false
     },
     {
@@ -2307,40 +2561,28 @@
       type: 'select',
       key: 'fileType',
       label: '鏄剧ず鏂瑰紡',
-      initVal: card.fileType || 'text',
+      initVal: card.fileType || (appType === 'mob' ? 'picture-card' : 'text'),
       options: [{
+        value: 'text',
+        text: '鏂囦欢'
+      }, {
         value: 'picture',
         text: '鍥炬枃淇℃伅'
       }, {
         value: 'picture-card',
         text: '鍥剧墖鍗�'
-      }, {
-        value: 'text',
-        text: '鏂囦欢'
       }]
     },
     {
       type: 'number',
       key: 'maxfile',
-      min: 1,
-      max: 1000000,
+      min: 0,
+      max: 1000,
       precision: 0,
       label: '鏈�澶ф枃浠舵暟',
       initVal: card.maxfile || '',
+      tooltip: '绛変簬0鏃朵笉鍋氶檺鍒躲��',
       required: false
-    },
-    {
-      type: 'radio',
-      key: 'hidelabel',
-      label: '闅愯棌鍚嶇О',
-      initVal: card.hidelabel || 'false',
-      options: [{
-        value: 'true',
-        text: Formdict['model.true']
-      }, {
-        value: 'false',
-        text: Formdict['model.false']
-      }]
     },
     {
       type: 'radio',
@@ -2396,6 +2638,37 @@
     },
     {
       type: 'radio',
+      key: 'cursor',
+      label: '鍏夋爣',
+      initVal: card.cursor || 'left',
+      options: [{
+        value: 'right',
+        text: '鍙冲榻�'
+      }, {
+        value: 'left',
+        text: '宸﹀榻�'
+      }],
+      forbid: appType !== 'mob'
+    },
+    {
+      type: 'radio',
+      key: 'scan',
+      label: '鎵爜',
+      initVal: card.scan || 'false',
+      options: [{
+        value: 'false',
+        text: '绂佺敤'
+      }, {
+        value: 'simple',
+        text: '鍗曟'
+      }, {
+        value: 'multi',
+        text: '杩炵画'
+      }],
+      forbid: appType !== 'mob'
+    },
+    {
+      type: 'radio',
       key: 'readin',
       label: Formdict['header.form.readin'],
       tooltip: Formdict['header.form.readin.tooltip'],
@@ -2423,6 +2696,76 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'hidelabel',
+      label: '闅愯棌鍚嶇О',
+      initVal: card.hidelabel || 'false',
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'arrange',
+      label: '鍏冪礌鎺掑垪',
+      initVal: card.arrange || 'adaptive',
+      forbid: appType !== 'mob',
+      options: [{
+        value: 'line',
+        text: '鏁磋'
+      }, {
+        value: 'adaptive',
+        text: '鑷�傚簲'
+      }]
+    },
+    {
+      type: 'color',
+      key: 'backgroundColor',
+      label: '鑳屾櫙鑹�',
+      initVal: card.backgroundColor || '',
+      tooltip: '璁剧疆鑳屾櫙鑹插悗锛岄�変腑鏁堟灉鐢辫儗鏅鑹叉帶鍒躲��',
+      required: false
+    },
+    {
+      type: 'color',
+      key: 'borderColor',
+      label: '杈规棰滆壊',
+      initVal: card.borderColor || '',
+      required: false
+    },
+    {
+      type: 'radio',
+      key: 'declareType',
+      label: '鏁版嵁绫诲瀷',
+      tooltip: '澹版槑鍙橀噺鏃剁殑绫诲瀷锛屾椂闂存牸寮廳atetime鎴栨枃鏈牸寮弉varchar(50)銆�',
+      initVal: card.declareType || 'datetime',
+      options: [{
+        value: 'datetime',
+        text: 'datetime'
+      }, {
+        value: 'nvarchar(50)',
+        text: 'nvarchar(50)'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'mode',
+      label: '妯″紡',
+      initVal: card.mode || 'picker',
+      options: [{
+        value: 'picker',
+        text: '閫夋嫨鍣�'
+      }, {
+        value: 'calendar',
+        text: '鏃ュ巻'
+      }],
+      forbid: appType !== 'mob'
+    },
+    {
       type: 'number',
       key: 'span',
       min: 1,
@@ -2431,7 +2774,8 @@
       label: '琛ㄥ崟瀹藉害',
       initVal: card.span || (['textarea', 'hint', 'checkcard', 'brafteditor'].includes(card.type) ? 24 : 12),
       tooltip: '鏍呮牸甯冨眬鏁磋24绛夊垎銆�',
-      required: true
+      required: true,
+      forbid: appType === 'mob'
     },
     {
       type: 'number',
@@ -2442,7 +2786,53 @@
       label: '鍚嶇О瀹藉害',
       initVal: card.labelwidth || 33.3,
       tooltip: '鍚嶇О鍗犳嵁琛ㄥ崟瀹藉害鐨勭櫨鍒嗘瘮銆傛敞锛氬瓨鍦ㄥ鍒楄〃鍗曟椂锛屽綋鍓嶈〃鍗曞鏋滄兂瑕佸崰鎹暣琛屽彲鍙傜収浠ヤ笅姣斾緥锛屼袱鍒楋紙16.2锛夈�佷笁鍒楋紙10.5锛夈�佸洓鍒楋紙7.7锛�',
+      required: true,
+      forbid: appType === 'mob'
+    },
+    {
+      type: 'radio',
+      key: 'compress',
+      label: '鍘嬬缉',
+      initVal: card.compress || 'false',
+      tooltip: '鏂囦欢鍘嬬缉蹇呴』涓哄浘鐗囷紝鍥剧墖鏍煎紡涓簀pg銆乸ng銆乬if 鎴� jpeg',
+      options: [{
+        value: 'true',
+        text: Formdict['model.true']
+      }, {
+        value: 'false',
+        text: Formdict['model.false']
+      }]
+    },
+    {
+      type: 'number',
+      key: 'limit',
+      min: 0.01,
+      max: 1000,
+      precision: 2,
+      label: '璧风偣锛圡锛�',
+      initVal: card.limit || 2,
+      tooltip: '鍘嬬缉璧风偣锛屽皬浜庤捣鐐瑰�肩殑鏂囦欢涓嶈繘琛屽帇缂┿��',
       required: true
+    },
+    {
+      type: 'textarea',
+      key: 'rduri',
+      label: '杞瓨鎺ュ彛',
+      rows: 1,
+      initVal: card.rduri || '',
+      tooltip: '鍥剧墖杞瓨鍦ㄥ悓涓�鍗曠偣鏈嶅姟鍣ㄤ笅鐨勫叾浠栦笟鍔$郴缁熴��',
+      required: false,
+      readonly: false
+    },
+    {
+      type: 'textarea',
+      key: 'proRduri',
+      label: '姝e紡鎺ュ彛',
+      rows: 1,
+      initVal: card.proRduri || '',
+      tooltip: '姝e紡绯荤粺杞瓨鎺ュ彛锛屽浘鐗囪浆瀛樺湪鍚屼竴鍗曠偣鏈嶅姟鍣ㄤ笅鐨勫叾浠栦笟鍔$郴缁熴��',
+      required: false,
+      readonly: false
     },
     {
       type: 'text',
@@ -2481,6 +2871,35 @@
       }]
     },
     {
+      type: 'radio',
+      key: 'splitline',
+      label: '鍒嗗壊绾�',
+      initVal: card.splitline || 'true',
+      forbid: appType !== 'mob',
+      options: [{
+        value: 'true',
+        text: '鏄剧ず'
+      }, {
+        value: 'false',
+        text: '闅愯棌'
+      }]
+    },
+    {
+      type: 'radio',
+      key: 'count',
+      label: '璁℃暟鍔熻兘',
+      initVal: card.count || 'false',
+      tooltip: '鏄剧ず杈撳叆鐨勫瓧绗︽暟锛岃缃鏁版椂鐢熸晥锛屾敞锛氬姞瀵嗕紶杈撴椂鏈�澶у�间笌瀛楁闀垮害涓嶇瓑銆�',
+      options: [{
+        value: 'true',
+        text: '寮�鍚�'
+      }, {
+        value: 'false',
+        text: '鍏抽棴'
+      }],
+      forbid: appType !== 'mob'
+    },
+    {
       type: 'select',
       key: 'supField',
       label: '涓婄骇琛ㄥ崟',
@@ -2494,7 +2913,7 @@
       type: 'text',
       key: 'supvalue',
       label: '鏄剧ず鍊�',
-      tooltip: '璇峰~鍐欐樉绀哄�硷紝鍙湁涓婄骇琛ㄥ崟鍊间笌鏄剧ず鍊肩浉鍚屾椂锛岃琛ㄥ崟鎵嶄細鏄剧ず锛屾敞锛氬涓�肩敤閫楀彿鍒嗛殧銆�',
+      tooltip: '璇峰~鍐欐樉绀哄�硷紝鍙湁涓婄骇琛ㄥ崟鍊间笌鏄剧ず鍊肩浉鍚屾椂锛岃琛ㄥ崟鎵嶄細鏄剧ず锛屾敞锛�1銆佸涓�肩敤閫楀彿鍒嗛殧锛�2銆佷笂绾ц〃鍗曞垵濮嬪�间负$first鏃舵殏鏈鐞嗐��',
       initVal: card.supvalue || '',
       required: true,
       readonly: false
@@ -2505,7 +2924,8 @@
       label: '鎮诞鎻愮ず',
       tooltip: '榧犳爣鎮诞浜庢彁绀烘枃瀛椾笂鏂规椂锛屾樉绀烘彁绀轰俊鎭��',
       initVal: card.tooltip || '',
-      required: false
+      required: false,
+      forbid: appType === 'mob'
     },
     {
       type: 'text',
@@ -2513,7 +2933,8 @@
       label: '搴曢儴鎻愮ず',
       tooltip: '鏄剧ず浜庤〃鍗曞簳閮ㄣ��',
       initVal: card.extra || '',
-      required: false
+      required: false,
+      forbid: appType === 'mob'
     },
     {
       type: 'text',
@@ -2552,7 +2973,7 @@
       type: 'multiselect',
       key: 'linkSubField',
       label: Formdict['model.form.linkform'],
-      tooltip: '鍦ㄥ垏鎹㈤�夐」鏃朵細鎶婁俊鎭嚜鍔ㄥ~鍏ュ叧鑱旂殑琛ㄥ崟锛堟枃鏈垨鏁板瓧琛ㄥ崟锛変腑銆�',
+      tooltip: '鍦ㄥ垏鎹㈤�夐」鏃朵細鎶婁俊鎭嚜鍔ㄥ~鍏ュ叧鑱旂殑琛ㄥ崟锛堟枃鏈垨鏁板瓧琛ㄥ崟锛変腑銆傛敞锛氫娇鐢ㄩ�夐」鍗′笖璁句负鍙閫夋椂鏃犳晥銆�',
       initVal: card.linkSubField || [],
       options: inputfields
     },
diff --git a/src/templates/zshare/modalform/datatable/index.jsx b/src/templates/zshare/modalform/datatable/index.jsx
index 50e0cc6..21ae904 100644
--- a/src/templates/zshare/modalform/datatable/index.jsx
+++ b/src/templates/zshare/modalform/datatable/index.jsx
@@ -70,9 +70,14 @@
 
 class EditableCell extends Component {
   getInput = (form) => {
-    const { inputType } = this.props
+    const { inputType, record } = this.props
     if (inputType === 'file') {
-      return <FileUpload maxFile={1} fileType="picture-card"/>
+      return <FileUpload config={{
+        initval: record ? (record.$url || '') : '',
+        suffix: '',
+        maxfile: 1,
+        fileType: 'picture-card'
+      }}/>
     } else {
       return <Input onPressEnter={() => this.getValue(form)} />
     }
@@ -85,15 +90,6 @@
         return
       }
 
-      if (row.$url && Array.isArray(row.$url)) {
-        if (!row.$url[0]) {
-          row.$url = ''
-        } else if (row.$url[0].origin) {
-          row.$url = row.$url[0].url || ''
-        } else if (!row.$url[0].origin && row.$url[0].status === 'done' && row.$url[0].response) {
-          row.$url = row.$url[0].response
-        }
-      }
       this.props.onSave({...record, ...row})
     })
   }
@@ -116,18 +112,6 @@
 
     if (record && dataIndex) {
       _val = record[dataIndex]
-    }
-
-    if (dataIndex === '$url' && _val) {
-      _val = [{
-        uid: `10086`,
-        name: _val.slice(_val.lastIndexOf('/') + 1),
-        status: 'done',
-        url: _val,
-        origin: true
-      }]
-    } else if (dataIndex === '$url') {
-      _val = []
     }
 
     return (
@@ -291,16 +275,6 @@
         return;
       }
 
-      if (row.$url && Array.isArray(row.$url)) {
-        if (!row.$url[0]) {
-          row.$url = ''
-        } else if (row.$url[0].origin) {
-          row.$url = row.$url[0].url || ''
-        } else if (!row.$url[0].origin && row.$url[0].status === 'done' && row.$url[0].response) {
-          row.$url = row.$url[0].response
-        }
-      }
-
       const newData = [...this.state.data]
       const index = newData.findIndex(item => key === item.key)
       if (index > -1) {
@@ -323,10 +297,10 @@
 
   handleAdd = () => {
     const { fields, type } = this.props
-    if (this.state.data.length >= 20) {
+    if (this.state.data.length >= 100) {
       notification.warning({
         top: 92,
-        message: '鏈�澶氬彲娣诲姞20椤癸紒',
+        message: '鏈�澶氬彲娣诲姞100椤癸紒',
         duration: 5
       })
       return
diff --git a/src/templates/zshare/modalform/datatable/index.scss b/src/templates/zshare/modalform/datatable/index.scss
index e80b7bf..6d5ee71 100644
--- a/src/templates/zshare/modalform/datatable/index.scss
+++ b/src/templates/zshare/modalform/datatable/index.scss
@@ -21,17 +21,11 @@
       padding: 16px 10px;
     }
     .fileupload-form-container .ant-upload-list-picture-card .ant-upload-list-item {
-      width: 70px;
-      height: 70px;
       margin: 0;
       padding: 2px;
       .ant-upload-list-item-info > span {
         height: 100%;
       }
-    }
-    .fileupload-form-container .ant-upload.ant-upload-select-picture-card {
-      width: 70px;
-      height: 70px;
     }
   }
   .operation-btn {
diff --git a/src/templates/zshare/modalform/index.jsx b/src/templates/zshare/modalform/index.jsx
index dd53a73..a8bb337 100644
--- a/src/templates/zshare/modalform/index.jsx
+++ b/src/templates/zshare/modalform/index.jsx
@@ -6,33 +6,35 @@
 import { dateOptions } from '@/utils/option.js'
 import Utils from '@/utils/utils.js'
 import EditTable from './modaleditable'
-import DataTable from './datatable'
-import FieldsTable from './fieldtable'
+import asyncComponent from '@/utils/asyncComponent'
 import CodeMirror from '@/templates/zshare/codemirror'
 import './index.scss'
 
 const { TextArea } = Input
+const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
+const FieldsTable = asyncComponent(() => import('./fieldtable'))
+const DataTable = asyncComponent(() => import('./datatable'))
 
 const modalTypeOptions = {
-  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'tooltip', 'extra', 'enter'],
-  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter'],
-  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter'],
-  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'tooltip', 'extra'],
-  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText'],
-  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'fieldlength', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple'],
+  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline'],
+  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline'],
+  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
+  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'arrange'],
+  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline', 'arrange'],
+  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'linkSubField', 'fieldlength', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'borderColor', 'splitline'],
   multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra'],
-  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter'],
-  fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'suffix'],
-  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
-  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
-  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
-  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
-  textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra'],
+  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'setAll', 'linkField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline'],
+  fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'splitline'],
+  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline'],
+  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline'],
+  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'splitline'],
+  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline'],
+  textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra', 'count'],
   color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra'],
-  hint: ['label', 'type', 'blacklist', 'message', 'span', 'labelwidth'],
+  hint: ['label', 'type', 'blacklist', 'message', 'span', 'labelwidth', 'splitline'],
   split: ['label', 'type'],
   brafteditor: ['required', 'hidelabel', 'hidden', 'readin', 'fieldlength', 'readonly', 'span', 'labelwidth', 'tooltip', 'extra', 'encryption'],
-  funcvar: ['span', 'labelwidth'],
+  funcvar: ['span', 'labelwidth', 'splitline'],
   linkMain: ['readonly', 'required', 'hidden', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra']
 }
 
@@ -49,6 +51,7 @@
     openType: null,
     resourceType: null,
     supField: '',
+    compress: 'false',
     display: 'text',
     enter: '',
     cFields: [],
@@ -62,6 +65,7 @@
     let resourceType = ''
     let supField = ''
     let display = ''
+    let compress = 'false'
     let enter = ''
     let cFields = []
     let linkSubFields = []
@@ -69,6 +73,8 @@
     formlist.forEach(cell => {
       if (cell.key === 'type') {
         type = cell.initVal
+      } else if (cell.key === 'compress') {
+        compress = cell.initVal
       } else if (cell.key === 'display') {
         display = cell.initVal
       } else if (cell.key === 'enter') {
@@ -92,10 +98,11 @@
       }
     })
     
-    let _options = this.getOptions(type, resourceType, supField, display, enter)
+    let _options = this.getOptions(type, resourceType, supField, display, enter, compress)
 
     this.setState({
       enter: enter,
+      compress: compress,
       openType: type,
       supField: supField,
       display: display,
@@ -143,7 +150,7 @@
     }
   }
 
-  getOptions = (type, resourceType, supField, display, enter) => {
+  getOptions = (type, resourceType, supField, display, enter, compress) => {
     let _options = ['label', 'field', 'type', 'blacklist', 'writein', ...fromJS(modalTypeOptions[type]).toJS()]
 
     if (type === 'hint') {
@@ -165,10 +172,20 @@
         }
       } else {
         if (resourceType === '0') {        // 鑷畾涔夎祫婧�
-          _options.push('options', 'fields')
+          _options.push('options', 'fields', 'backgroundColor')
         } else if (resourceType === '1') { // 鏁版嵁婧�
-          _options.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database')
+          _options.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database', 'backgroundColor')
         }
+      }
+
+      if (sessionStorage.getItem('appType') === 'mob') {
+        _options.push('hidelabel')
+      }
+    } else if (type === 'fileupload') {
+      if (compress === 'true') {
+        _options.push('limit', 'rduri', 'proRduri')
+      } else {
+        _options.push('suffix')
       }
     }
 
@@ -201,8 +218,7 @@
         fieldValue.enter = 'false'
       }
 
-      let _options = this.getOptions(value, this.state.resourceType, this.state.supField, this.state.display, enter)
-      
+      let _options = this.getOptions(value, this.state.resourceType, this.state.supField, this.state.display, enter, this.state.compress)
       
       this.setState({
         openType: value,
@@ -265,6 +281,10 @@
             if (value === 'brafteditor') {
               fieldValue.encryption = 'true'
             }
+          } else if (form.key === 'hidden') {
+            if (value === 'linkMain') {
+              fieldValue.hidden = 'true'
+            }
           }
 
           return form
@@ -311,10 +331,10 @@
   }
 
   onChange = (e, key) => {
-    const { openType } = this.state
+    const { openType, compress } = this.state
     let value = e.target.value
     if (key === 'resourceType') {
-      let _options = this.getOptions(openType, value, this.state.supField, this.state.display, this.state.enter)
+      let _options = this.getOptions(openType, value, this.state.supField, this.state.display, this.state.enter, compress)
       
       this.setState({
         resourceType: value,
@@ -324,7 +344,7 @@
         })
       })
     } else if (key === 'display') {
-      let _options = this.getOptions(openType, this.state.resourceType, this.state.supField, value, this.state.enter)
+      let _options = this.getOptions(openType, this.state.resourceType, this.state.supField, value, this.state.enter, compress)
       
       this.setState({
         display: value,
@@ -333,8 +353,18 @@
           return form
         })
       })
+    } else if (key === 'compress') {
+      let _options = this.getOptions(openType, this.state.resourceType, this.state.supField, this.state.display, this.state.enter, value)
+      
+      this.setState({
+        compress: value,
+        formlist: this.state.formlist.map(form => {
+          form.show = _options.includes(form.key)
+          return form
+        })
+      })
     } else if (key === 'enter') {
-      let _options = this.getOptions(openType, this.state.resourceType, this.state.supField, this.state.display, value)
+      let _options = this.getOptions(openType, this.state.resourceType, this.state.supField, this.state.display, value, compress)
       
       this.setState({
         enter: value,
@@ -422,7 +452,7 @@
     const fields = []
 
     this.state.formlist.forEach((item, index) => {
-      if (!item.show) return
+      if (!item.show || item.forbid) return null
 
       if (item.type === 'text') { // 鏂囨湰鎼滅储
         let rules = []
@@ -617,7 +647,12 @@
       } else if (item.type === 'textarea') {
         fields.push(
           <Col span={24} key={index}>
-            <Form.Item className="text-msg" label={item.label}>
+            <Form.Item className="text-msg" label={item.tooltip ?
+              <Tooltip placement="topLeft" overlayClassName={item.tooltipClass} title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
               {getFieldDecorator(item.key, {
                 initialValue: item.initVal,
                 rules: [
@@ -626,7 +661,7 @@
                     message: this.props.dict['form.required.input'] + item.label + '!'
                   }
                 ]
-              })(<TextArea rows={4} />)}
+              })(<TextArea rows={item.rows || 4} />)}
             </Form.Item>
           </Col>
         )
@@ -662,6 +697,16 @@
             </Form.Item>
           </Col>
         )
+      } else if (item.type === 'color') {
+        fields.push(
+          <Col span={12} key={index}>
+            <Form.Item label={item.label} className="color-form-item">
+              {getFieldDecorator(item.key, {
+                initialValue: item.initVal
+              })(<ColorSketch allowClear={true}/>)}
+            </Form.Item>
+          </Col>
+        )
       }
     })
 
diff --git a/src/templates/zshare/modalform/index.scss b/src/templates/zshare/modalform/index.scss
index 75706c5..672e7e4 100644
--- a/src/templates/zshare/modalform/index.scss
+++ b/src/templates/zshare/modalform/index.scss
@@ -33,4 +33,12 @@
   .ant-input-number {
     width: 100%;
   }
+  .color-form-item {
+    .ant-form-item-control {
+      height: 40px;
+      .color-sketch-block {
+        margin-top: 7px;
+      }
+    }
+  }
 }
\ 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 314fe78..5b5a0a2 100644
--- a/src/templates/zshare/modalform/modaleditable/index.jsx
+++ b/src/templates/zshare/modalform/modaleditable/index.jsx
@@ -300,7 +300,8 @@
     })
   }
 
-  handleAdd = () => {
+  handleAdd = (e) => {
+    e.stopPropagation()
     const { type, count, dataSource } = this.state
     const newData = {
       key: Utils.getuuid(),
@@ -388,7 +389,7 @@
                 title={this.props.dict['model.query.delete']}
                 onConfirm={() => this.handleDelete(record.key)
               }>
-                <span style={{color: '#1890ff', cursor: 'pointer'}}><Icon type="delete" /></span>
+                <span style={{color: '#ff4d4f', cursor: 'pointer'}}><Icon type="delete" /></span>
               </Popconfirm>
             </div>
           ) : null,
diff --git a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
index 5d9f5e7..bed203c 100644
--- a/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
+++ b/src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -127,6 +127,13 @@
           LText: this.props.initsql +  _prevCustomScript + _backCustomScript + tail
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/zshare/verifycard/customform/index.jsx b/src/templates/zshare/verifycard/customform/index.jsx
index c9be94d..d203f25 100644
--- a/src/templates/zshare/verifycard/customform/index.jsx
+++ b/src/templates/zshare/verifycard/customform/index.jsx
@@ -101,6 +101,13 @@
           LText: this.props.initsql + values.sql
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+        
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
 
diff --git a/src/templates/zshare/verifycard/customscript/index.jsx b/src/templates/zshare/verifycard/customscript/index.jsx
index f7f1d2e..a5a1162 100644
--- a/src/templates/zshare/verifycard/customscript/index.jsx
+++ b/src/templates/zshare/verifycard/customscript/index.jsx
@@ -139,6 +139,13 @@
           LText: this.props.initsql + _initCustomScript + _prevCustomScript + _backCustomScript + tail
         }
 
+        if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+          window.GLOB.funcs.forEach(item => {
+            let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
+            param.LText = param.LText.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
+          })
+        }
+
         // 鏁版嵁鏉冮檺
         param.LText = param.LText.replace(/@\$|\$@/ig, '')
         // check
diff --git a/src/templates/zshare/verifycard/index.jsx b/src/templates/zshare/verifycard/index.jsx
index a3a388e..5e448f2 100644
--- a/src/templates/zshare/verifycard/index.jsx
+++ b/src/templates/zshare/verifycard/index.jsx
@@ -556,6 +556,21 @@
     _verify.scripts = _verify.scripts || []
     _verify.cbScripts = _verify.cbScripts || []
 
+    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+      window.GLOB.funcs.forEach(m => {
+        let reg = new RegExp(`\\/\\*\\$ex@${m.func_code}-begin\\*\\/[\\s\\S]+\\/\\*@ex\\$-end\\*\\/`, 'ig')
+        _verify.customverifys.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _verify.scripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+        _verify.cbScripts.forEach(item => {
+          item.sql = item.sql.replace(reg, `$ex@${m.func_code}@ex$`)
+        })
+      })
+    }
+
     this.setState({
       verify: _verify
     })
@@ -860,7 +875,7 @@
         _columns = fromJS(columns).toJS()
         let hasbid = false
         _columns = _columns.filter(col => {
-          if (col.field.toLowerCase() === 'bid') {
+          if (col.field && col.field.toLowerCase() === 'bid') {
             hasbid = true
           }
 
@@ -926,8 +941,8 @@
       },
       {
         obj_name: 'noteCodes',
-        arr_field: 'templatecode,describe',
-        LText: window.btoa(window.encodeURIComponent(`select templatecode,'['+SignName+']'+describe as describe from (select * from bd_msn_sms_temp where  deleted=0 and TypeDesc='QX' and status=20 ) t inner join (select openid from susers where uid=@userid@) u on t.openid =t.openid`))
+        arr_field: 'templatecode,describe,id',
+        LText: window.btoa(window.encodeURIComponent(`select t.id,templatecode,'['+SignName+']'+describe as describe from (select * from bd_msn_sms_temp where  deleted=0 and TypeDesc='QX' and status=20 ) t inner join (select openid from susers where uid=@userid@) u on t.openid =t.openid`))
       },
       {
         obj_name: 'scripts',
@@ -967,7 +982,8 @@
           notes: res.noteCodes.map(item => {
             return {
               name: item.describe,
-              value: item.templatecode
+              value: item.templatecode,
+              id: item.id
             }
           }),
           systemScripts: res.scripts.map(item => {
@@ -1092,11 +1108,11 @@
     this.setState({ verify })
   }
 
-  onNoteCodeChange = (val) => {
+  onNoteCodeChange = (val, option) => {
     const { verify } = this.state
 
     this.setState({
-      verify: {...verify, noteCode: val}
+      verify: {...verify, noteCode: val, noteId: option.props.id}
     })
   }
 
@@ -1301,7 +1317,7 @@
     
     // 琛ㄥ崟鎻愪氦鏃舵鏌ヨ緭鍏ュ�兼槸鍚︽纭�
     return new Promise((resolve, reject) => {
-      if (card.sqlType !== 'custom' && verify.default === 'false' && verify.scripts.length === 0) {
+      if ((card.sqlType === 'custom' || verify.default === 'false') && verify.scripts.length === 0) {
         notification.warning({
           top: 92,
           message: '涓嶆墽琛岄粯璁ql鏃讹紝蹇呴』璁剧疆鑷畾涔夎剼鏈紒',
@@ -1334,6 +1350,21 @@
         verify.noteEnable = 'false'
       } else if (verify.noteEnable !== 'true' && verify.noteCode) {
         verify.noteCode = ''
+      }
+
+      if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
+        window.GLOB.funcs.forEach(m => {
+          let reg = new RegExp('\\$ex@' + m.func_code + '@ex\\$', 'ig')
+          verify.customverifys.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          verify.scripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+          verify.cbScripts.forEach(item => {
+            item.sql = item.sql.replace(reg, `/*$ex@${m.func_code}-begin*/\n${m.key_sql}\n/*@ex$-end*/`)
+          })
+        })
       }
 
       if (msg) {
@@ -1452,7 +1483,7 @@
                   <Form.Item label="鐭俊妯℃澘">
                     <Select value={verify.noteCode} onSelect={this.onNoteCodeChange}>
                       {notes.map(option =>
-                        <Select.Option key={option.value} value={option.value}>
+                        <Select.Option key={option.value} id={option.id} value={option.value}>
                           {option.name}
                         </Select.Option>
                       )}
diff --git a/src/utils/option.js b/src/utils/option.js
index 75fca24..4306074 100644
--- a/src/utils/option.js
+++ b/src/utils/option.js
@@ -87,18 +87,18 @@
     isSystem: true
   },
   {
-    title: '瑙掕壊鏉冮檺鍒嗛厤',
-    type: 'RolePermission',
-    url: rolemanage,
-    isSystem: true,
-    hidden: true
-  },
-  {
     title: '澶栭儴椤甸潰',
     type: 'NewPage',
     url: customImg,
     baseconfig: '',
     isSystem: true
+  },
+  {
+    title: '瑙掕壊鏉冮檺鍒嗛厤',
+    type: 'RolePermission',
+    url: rolemanage,
+    isSystem: true,
+    hidden: true
   }
 ]
 
@@ -210,9 +210,6 @@
 
 // 鎸夐挳鍥炬爣闆�
 export const btnIcons = [{
-  value: '',
-  text: '鏃�'
-}, {
   value: 'plus',
   text: 'plus'
 }, {
@@ -284,6 +281,9 @@
 }, {
   value: 'double-left',
   text: 'double-left'
+}, {
+  value: 'search',
+  text: 'search'
 }]
 
 // 鎸夐挳棰滆壊闆�
@@ -681,19 +681,8 @@
     'step-forward',
     'fast-backward',
     'fast-forward',
-    'shrink',
-    'arrows-alt',
-    'up-circle',
-    'down-circle',
-    'left-circle',
-    'right-circle',
     'double-right',
     'double-left',
-    'vertical-left',
-    'vertical-right',
-    'vertical-align-top',
-    'vertical-align-middle',
-    'vertical-align-bottom',
     'forward',
     'backward',
     'rollback',
@@ -703,56 +692,31 @@
     'swap-left',
     'swap-right',
     'play-circle',
-    'up-square',
-    'down-square',
-    'left-square',
-    'right-square',
     'login',
     'logout',
-    'menu-fold',
-    'menu-unfold',
-    'border-bottom',
-    'border-horizontal',
-    'border-inner',
-    'border-outer',
-    'border-left',
-    'border-right',
-    'border-top',
-    'border-verticle',
-    'pic-center',
-    'pic-left',
-    'pic-right',
-    'radius-bottomleft',
-    'radius-bottomright',
-    'radius-upleft',
-    'radius-upright',
+    'search',
     'fullscreen',
-    'fullscreen-exit'
+    'fullscreen-exit',
+    'download',
+    'upload'
   ],
   hint: [
     'question',
     'question-circle',
     'plus',
     'plus-circle',
-    'pause',
     'pause-circle',
     'minus',
     'minus-circle',
-    'plus-square',
-    'minus-square',
-    'info',
     'info-circle',
-    'exclamation',
     'exclamation-circle',
     'close',
     'close-circle',
-    'close-square',
     'check',
     'check-circle',
     'check-square',
     'clock-circle',
     'warning',
-    'issues-close',
     'stop'
   ],
   edit: [
@@ -762,33 +726,14 @@
     'scissor',
     'delete',
     'snippets',
-    'diff',
     'highlight',
-    'align-center',
-    'align-left',
-    'align-right',
-    'bg-colors',
-    'bold',
-    'italic',
-    'underline',
-    'strikethrough',
     'redo',
     'undo',
     'zoom-in',
     'zoom-out',
-    'font-colors',
-    'font-size',
-    'line-height',
     'dash',
-    'small-dash',
     'sort-ascending',
-    'sort-descending',
-    'drag',
-    'ordered-list',
-    'unordered-list',
-    'radius-setting',
-    'column-width',
-    'column-height'
+    'sort-descending'
   ],
   data: [
     'area-chart',
@@ -797,66 +742,26 @@
     'dot-chart',
     'line-chart',
     'radar-chart',
-    'heat-map',
     'fall',
     'rise',
     'stock',
-    'box-plot',
-    'fund',
-    'sliders'
   ],
   trademark: [
     'android',
     'apple',
-    'windows',
-    'ie',
     'chrome',
-    'github',
     'aliwangwang',
     'dingding',
-    'weibo-square',
-    'weibo-circle',
-    'taobao-circle',
-    'html5',
     'weibo',
     'twitter',
     'wechat',
-    'youtube',
     'alipay-circle',
     'taobao',
-    'skype',
     'qq',
-    'medium-workmark',
-    'gitlab',
-    'medium',
-    'linkedin',
-    'google-plus',
-    'dropbox',
-    'facebook',
-    'codepen',
-    'code-sandbox',
-    'amazon',
-    'google',
-    'codepen-circle',
     'alipay',
-    'ant-design',
-    'ant-cloud',
-    'aliyun',
-    'zhihu',
-    'slack',
-    'slack-square',
-    'behance',
-    'behance-square',
-    'dribbble',
-    'dribbble-square',
-    'instagram',
-    'yuque',
-    'alibaba',
-    'yahoo',
-    'reddit',
-    'sketch'
   ],
   normal: [
+    'user',
     'account-book',
     'alert',
     'api',
@@ -864,42 +769,19 @@
     'audio',
     'bank',
     'bell',
-    'book',
     'bug',
-    'bulb',
-    'calculator',
-    'build',
     'calendar',
     'camera',
-    'car',
-    'carry-out',
     'cloud',
-    'code',
     'compass',
-    'contacts',
-    'container',
-    'control',
     'credit-card',
-    'crown',
     'customer-service',
     'dashboard',
     'database',
     'dislike',
     'environment',
-    'experiment',
     'eye-invisible',
     'eye',
-    'file-add',
-    'file-excel',
-    'file-exclamation',
-    'file-image',
-    'file-markdown',
-    'file-pdf',
-    'file-ppt',
-    'file-text',
-    'file-unknown',
-    'file-word',
-    'file-zip',
     'file',
     'filter',
     'fire',
@@ -907,22 +789,13 @@
     'folder-add',
     'folder',
     'folder-open',
-    'frown',
-    'funnel-plot',
-    'gift',
-    'hdd',
     'heart',
     'home',
     'hourglass',
     'idcard',
-    'insurance',
-    'interaction',
-    'layout',
     'like',
     'lock',
     'mail',
-    'medicine-box',
-    'meh',
     'message',
     'mobile',
     'phone',
@@ -931,16 +804,15 @@
     'smile',
     'star',
     'thunderbolt',
-    'trophy',
     'unlock',
     'barcode',
     'key',
     'man',
     'woman',
+    'team',
     'poweroff',
-    'search',
     'shopping-cart',
-    'link'
+    'link',
   ]
 }
 
diff --git a/src/utils/utils-custom.js b/src/utils/utils-custom.js
index e991da4..058d369 100644
--- a/src/utils/utils-custom.js
+++ b/src/utils/utils-custom.js
@@ -166,11 +166,89 @@
   }
 
   /**
+   * @description 鑾峰彇鍙叧鑱旀ā鍧�
+   */
+  static getLinkModules (components) {
+    let modules = components.map(item => {
+      if ((item.type === 'card' && item.subtype === 'datacard') || (item.type === 'table' && item.subtype === 'normaltable')) {
+        return {
+          value: item.uuid,
+          label: item.name
+        }
+      } else if (item.type === 'tabs') {
+        let _item = {
+          value: item.uuid,
+          label: item.name,
+          children: item.subtabs.map(f_tab => {
+            let subItem = {
+              value: f_tab.uuid,
+              label: f_tab.label,
+              children: this.getLinkModules(f_tab.components)
+            }
+
+            if (!subItem.children || subItem.children.length === 0) {
+              return {children: null}
+            }
+            return subItem
+          })
+        }
+
+        _item.children = _item.children.filter(t => t.children !== null)
+
+        if (_item.children.length === 0) {
+          return {children: null}
+        }
+
+        return _item
+      } else if (item.type === 'group') {
+        let _item = {
+          value: item.uuid,
+          label: item.name,
+          children: item.components.map(f_tab => {
+            if ((f_tab.type === 'card' && f_tab.subtype === 'datacard') || (f_tab.type === 'table' && f_tab.subtype === 'normaltable')) {
+              return {
+                value: f_tab.uuid,
+                label: f_tab.name
+              }
+            }
+            return {
+              children: null
+            }
+          })
+        }
+
+        _item.children = _item.children.filter(t => t.children !== null)
+
+        if (_item.children.length === 0) {
+          return {children: null}
+        }
+
+        return _item
+      } else {
+        return {
+          children: null
+        }
+      }
+    })
+
+    modules = modules.filter(mod => mod.children !== null)
+
+    if (modules.length === 0) {
+      return null
+    }
+    return modules
+  }
+
+  /**
    * @description 鑾峰彇鍒犻櫎鎸夐挳Id
    * @return {String}  name
    */
   static getDelButtonIds (card) {
+    let appType = sessionStorage.getItem('appType')
     let uuids = []
+
+    if (appType === 'mob') return uuids
+
     const getUuids = (item) => {
       if (item.type === 'tabs') {
         item.subtabs.forEach(tab => {
@@ -183,48 +261,41 @@
           getUuids(c)
         })
       } else {
-        if (item.action && item.action.length > 0) {
-          item.action.forEach(act => {
-            if (!act.origin) {
-              uuids.push(act.uuid)
-            }
-          })
-        }
-        if (item.type === 'card') {
-          item.subcards.forEach(_card => {
+        item.action && item.action.forEach(act => {
+          if (act.origin || (appType === 'pc' && act.OpenType !== 'popview')) return
+
+          uuids.push(act.uuid)
+        })
+
+        if (card.type === 'card' || item.type === 'carousel' || (card.type === 'table' && card.subtype === 'tablecard')) {
+          card.subcards.forEach(_card => {
             _card.elements && _card.elements.forEach(cell => {
-              if (cell.eleType === 'button') {
-                uuids.push(cell.uuid)
-              }
-            })
-            _card.backElements && _card.backElements.forEach(cell => {
-              if (cell.eleType === 'button') {
-                uuids.push(cell.uuid)
-              }
-            })
-          })
-        } else if (item.type === 'carousel') {
-          item.subcards.forEach(_card => {
-            _card.elements && _card.elements.forEach(cell => {
-              if (cell.eleType === 'button') {
-                uuids.push(cell.uuid)
-              }
-            })
-          })
-        } else if (item.type === 'table' && item.subtype === 'tablecard') {
-          item.subcards.forEach(_card => {
-            _card.elements && _card.elements.forEach(cell => {
-              if (cell.eleType === 'button') {
-                uuids.push(cell.uuid)
-              }
-            })
-          })
-        } else if (item.type === 'table' && item.subtype === 'normaltable') {
-          item.cols && item.cols.forEach(col => {
-            if (col.type !== 'action') return
-            col.elements && col.elements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              if (appType === 'pc' && cell.OpenType !== 'popview') return
+  
               uuids.push(cell.uuid)
             })
+            _card.backElements && _card.backElements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              if (appType === 'pc' && cell.OpenType !== 'popview') return
+  
+              uuids.push(cell.uuid)
+            })
+          })
+        } else if (card.type === 'table' && card.subtype === 'normaltable') {
+          card.cols && card.cols.forEach(col => {
+            if (col.type !== 'action') return
+            col.elements && col.elements.forEach(cell => {
+              if (appType === 'pc' && cell.OpenType !== 'popview') return
+  
+              uuids.push(cell.uuid)
+            })
+          })
+        } else if (card.type === 'balcony') {
+          card.elements && card.elements.forEach(cell => {
+            if (appType === 'pc' && cell.OpenType !== 'popview') return
+
+            uuids.push(cell.uuid)
           })
         }
       }
@@ -280,6 +351,11 @@
           return cell
         })
         item.components = this.resetConfig(item.components)
+      } else if (item.type === 'menubar') {
+        item.subMenus = item.subMenus.map(cell => {
+          cell.uuid = this.getuuid()
+          return cell
+        })
       } else if (item.type === 'card' || item.type === 'carousel' || (item.type === 'table' && item.subtype === 'tablecard')) {
         item.subcards.forEach(card => {
           card.uuid = this.getuuid()
@@ -366,4 +442,27 @@
       return item
     })
   }
+}
+
+/**
+ * @description 閲嶇疆绉诲姩绔痵tyle
+ * @return {Object}  style
+ */
+export function resetStyle (style) {
+  if (!style) return {}
+  if (sessionStorage.getItem('appType') === 'mob') {
+    let _style = JSON.stringify(style)
+
+    // scaleview
+    _style = _style.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'
+    })
+
+    return JSON.parse(_style)
+  }
+  return JSON.parse(JSON.stringify(style))
 }
\ No newline at end of file
diff --git a/src/utils/utils-datamanage.js b/src/utils/utils-datamanage.js
index f684846..2584cd9 100644
--- a/src/utils/utils-datamanage.js
+++ b/src/utils/utils-datamanage.js
@@ -1,3 +1,4 @@
+import md5 from 'md5'
 import moment from 'moment'
 import options from '@/store/options.js'
 import Utils from './utils.js'
@@ -65,7 +66,7 @@
         if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
           param.rduri = window.GLOB.mainSystemApi
         } else if (setting.sysInterface !== 'true') {
-          param.rduri = setting.interface
+          param.rduri = window.GLOB.systemType === 'production' ? (setting.proInterface || setting.interface) : setting.interface
         }
       }
 
@@ -108,6 +109,13 @@
       `
     }
 
+    _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
+    _customScript = _customScript.replace(/@select\$|\$select@/ig, '')
+    _dataresource = _dataresource.replace(/\$sum@/ig, '/*')
+    _dataresource = _dataresource.replace(/@sum\$/ig, '*/')
+    _customScript = _customScript.replace(/\$sum@/ig, '/*')
+    _customScript = _customScript.replace(/@sum\$/ig, '*/')
+
     let regoptions = null
     if (setting.queryType === 'statistics' || _customScript) {
       let allSearch = Utils.getAllSearchOptions(search)
@@ -118,15 +126,6 @@
         }
       })
       regoptions.push({
-        reg: new RegExp('@login_city@', 'ig'),
-        value: `'${city}'`
-      }, {
-        reg: new RegExp('@userName@', 'ig'),
-        value: `'${userName}'`
-      }, {
-        reg: new RegExp('@fullName@', 'ig'),
-        value: `'${fullName}'`
-      }, {
         reg: new RegExp('@orderBy@', 'ig'),
         value: orderBy
       }, {
@@ -190,8 +189,8 @@
 
     // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
     if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
-      _customScript &&  console.info(`${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
-      LText &&  console.info(LText)
+      _customScript &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鑷畾涔夎剼鏈�*/\n` : ''}${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
+      LText &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鏁版嵁婧�*/\n` : ''}` + LText)
     }
 
     param.custom_script = Utils.formatOptions(_customScript)
@@ -240,6 +239,13 @@
       `
     }
 
+    _dataresource = _dataresource.replace(/@sum\$|\$sum@/ig, '')
+    _customScript = _customScript.replace(/@sum\$|\$sum@/ig, '')
+    _dataresource = _dataresource.replace(/\$select@/ig, '/*')
+    _dataresource = _dataresource.replace(/@select\$/ig, '*/')
+    _customScript = _customScript.replace(/\$select@/ig, '/*')
+    _customScript = _customScript.replace(/@select\$/ig, '*/')
+
     let regoptions = null
     if (setting.queryType === 'statistics' || _customScript) {
       let allSearch = Utils.getAllSearchOptions(search)
@@ -251,15 +257,6 @@
         }
       })
       regoptions.push({
-        reg: new RegExp('@login_city@', 'ig'),
-        value: `'${city}'`
-      }, {
-        reg: new RegExp('@userName@', 'ig'),
-        value: `'${userName}'`
-      }, {
-        reg: new RegExp('@fullName@', 'ig'),
-        value: `'${fullName}'`
-      }, {
         reg: new RegExp('@orderBy@', 'ig'),
         value: orderBy
       }, {
@@ -280,6 +277,7 @@
       regoptions.forEach(item => {
         _dataresource = _dataresource.replace(item.reg, item.value)
       })
+      _search = ''
     }
 
     if (_customScript) {
@@ -300,8 +298,8 @@
 
     // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
     if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
-      _customScript &&  console.info(`${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
-      LText &&  console.info(LText)
+      _customScript &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鑷畾涔夎剼鏈� 缁熻鏌ヨ*/\n` : ''}${LText ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
+      LText &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鏁版嵁婧� 缁熻鏌ヨ*/\n` : ''}` + LText)
     }
     
     param.custom_script = Utils.formatOptions(_customScript)
@@ -357,7 +355,7 @@
   }
 
   /**
-   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
+   * @description 鑾峰彇绯荤粺鍓嶇疆鑴氭湰
    */
   static getDefaultPrevQueryParam (setting, search, menuType) {
     let param = {
@@ -441,7 +439,7 @@
   }
 
   /**
-   * @description 鑾峰彇绯荤粺瀛樺偍杩囩▼ sPC_Get_TableData 鐨勫弬鏁�
+   * @description 鑾峰彇绯荤粺鍥炶皟鑴氭湰
    */
   static getCallBackQueryParams (setting, sql, errSql) {
     let param = {
@@ -540,6 +538,9 @@
             subObjs.push(val)
           }
         } else {
+          if (typeof(val) === 'string') {
+            val = val.replace(/'/ig, '"')
+          }
           keys.push(key)
           vals.push(`'${val}'`)
         }
@@ -575,4 +576,132 @@
 
     return [...lineMap.values()]
   }
+}
+
+/**
+ * @description 鐢熸垚鍗曚釜缁勪欢sPC_Get_structured_data璇锋眰鍙傛暟
+ */
+export function getStructDefaultParam (component, searchlist) {
+  const { columns, setting, dataName, format } = component
+
+  let arr_field = columns.map(col => col.field)
+  let _dataresource = setting.dataresource
+  let _customScript = setting.customScript
+  
+  if (setting.queryType === 'statistics' || _customScript) {
+    let allSearch = Utils.getAllSearchOptions(searchlist)
+    let regoptions = allSearch.map(item => {
+      return {
+        reg: new RegExp('@' + item.key + '@', 'ig'),
+        value: `'${item.value}'`
+      }
+    })
+
+    regoptions.forEach(item => {
+      if (_dataresource && setting.queryType === 'statistics') {
+        _dataresource = _dataresource.replace(item.reg, item.value)
+      }
+      _customScript = _customScript.replace(item.reg, item.value)
+    })
+  }
+
+  _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
+  _customScript = _customScript.replace(/@select\$|\$select@/ig, '')
+  _dataresource = _dataresource.replace(/\$sum@/ig, '/*')
+  _dataresource = _dataresource.replace(/@sum\$/ig, '*/')
+  _customScript = _customScript.replace(/\$sum@/ig, '/*')
+  _customScript = _customScript.replace(/@sum\$/ig, '*/')
+
+  let _search = ''
+  if (setting.queryType !== 'statistics' && _dataresource) {
+    _search = Utils.joinMainSearchkey(searchlist)
+    _search = _search ? 'where ' + _search : ''
+  }
+
+  if (setting.order && _dataresource) {
+    _dataresource = `select top 1000 ${arr_field.join(',')} from (select ${arr_field.join(',')} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
+  } else if (_dataresource) {
+    _dataresource = `select top 1000 ${arr_field.join(',')} from ${_dataresource} ${_search} `
+  }
+
+  // 娴嬭瘯绯荤粺鎵撳嵃鏌ヨ璇彞
+  if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
+    _customScript &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鑷畾涔夎剼鏈�*/\n` : ''}${_dataresource ? '' : '/*涓嶆墽琛岄粯璁ql*/\n'}${_customScript}`)
+    _dataresource &&  console.info(`${setting.$name ? `/*缁勪欢-${setting.$name} 鏁版嵁婧�*/\n` : ''}` + _dataresource)
+  }
+
+  return {
+    name: dataName,
+    columns: columns,
+    par_tablename: '',
+    type: format === 'array' ? format : '',
+    primaryKey: setting.primaryKey || '',
+    foreign_key: '',
+    sql: _dataresource,
+    script: _customScript
+  }
+}
+
+/**
+ * @description 鐢熸垚sPC_Get_structured_data璇锋眰鍙傛暟
+ * 1銆佹妸澶ф帴鍙PC_Get_structured_data鐨刲text鎷嗘垚涓変唤锛岀涓�娈碉細@LText1锛岀浜屾@LText锛岀涓夋@LText2
+ */
+export function getStructuredParams (params, config, BID = '') {
+  let LText_field = []
+  let diffUser = false
+  let userName = sessionStorage.getItem('User_Name') || ''
+  let fullName = sessionStorage.getItem('Full_Name') || ''
+  let city = sessionStorage.getItem('city') || ''
+
+  if (sessionStorage.getItem('isEditState') === 'true') {
+    userName = sessionStorage.getItem('CloudUserName') || ''
+    fullName = sessionStorage.getItem('CloudFullName') || ''
+  }
+  
+  let _LText = params.map((item, index) => {
+    let _script = item.script
+
+    if (index === 0) {
+      _script = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@login_city nvarchar(50)
+        select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @login_city='${city}'
+        ${_script}
+      `
+    }
+    if (!diffUser && (/@userid@/ig.test(item.sql) || /@userid@/ig.test(_script))) {
+      diffUser = true
+    }
+
+    item.columns.forEach(cell => {
+      LText_field.push(`Select '${item.name}' as tablename,'${cell.field}' as fieldname,'${cell.datatype}' as field_type`)
+    })
+    return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(item.sql))}' as LText,'${window.btoa(window.encodeURIComponent(_script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
+  })
+
+  let param = {
+    func: 'sPC_Get_structured_data',
+    LText: _LText.join(' union all '),
+    LText_field: LText_field.join(' union all '),
+    BID: BID
+  }
+
+  let { LText, LText1, LText2 } = Utils.sPCInUpDeFormatOptions(param.LText)
+
+  param.LText1 = LText1
+  param.LText = LText
+  param.LText2 = LText2
+  param.LText_field = Utils.formatOptions(param.LText_field)
+
+  if (config.cacheUseful === 'true') {
+    param.time_type = config.timeUnit
+    param.time_limit = config.cacheTime
+    if (diffUser) {
+      param.userid = sessionStorage.getItem('UserID')
+    }
+    param.data_md5 = md5(JSON.stringify(param))
+  }
+
+  param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+  param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+  return param
 }
\ No newline at end of file
diff --git a/src/utils/utils.js b/src/utils/utils.js
index d0a9b07..93d0120 100644
--- a/src/utils/utils.js
+++ b/src/utils/utils.js
@@ -236,54 +236,55 @@
   }
 
   /**
-   * @description 鍒濆鍖栨悳绱㈡潯浠�
+   * @description 鍒濆鍖栨悳绱㈡潯浠跺垵濮嬪��
    * @param {Array}   searches     鎼滅储鏉′欢
-   * @return {String}  searches    鏍煎紡鍖栧悗缁撴灉
    */
-  static initMainSearch (searches) {
-    if (!searches || searches.length === 0) return []
+  static initSearchVal (searches) {
+    if (!searches) return []
 
-    let newsearches = []
-    searches.forEach(search => {
-      let item = {
-        key: search.field,
-        match: search.match,
-        type: search.type,
-        label: search.label,
-        value: search.initval,
-        required: search.required === 'true'
-      }
+    let roleId = sessionStorage.getItem('role_id') || ''
 
-      if (item.type === 'group') {
-        let copy = JSON.parse(JSON.stringify(item))
-        copy.key = search.datefield
+    return searches.map(item => {
+      item.hidden = item.Hide === 'true'
+      item.required = !item.hidden && item.required === 'true'
+      item.advanced = item.advanced === 'true'
 
-        item.value = search.initval && search.initval[0] ? search.initval[0] : ''
-        item.match = '='
-        item.forbid = true
-        
-        copy.type = 'daterange'
-        copy.match = 'between'
-        copy.value = ''
-
-        if (search.initval && search.initval.length > 0) {
-          let _type = search.initval[0]
-          let _val = search.initval[1]
-
+      if (item.type === 'date') { // 鏃堕棿鎼滅储
+        item.initval = item.initval ? moment().subtract(item.initval, 'days').format('YYYY-MM-DD') : ''
+      } else if (item.type === 'datemonth') {
+        item.initval = item.initval ? moment().subtract(item.initval, 'month').format('YYYY-MM') : ''
+      } else if (item.type === 'dateweek') {
+        item.initval = item.initval ? moment().subtract(item.initval * 7, 'days').format('YYYY-MM-DD') : ''
+      } else if (item.type === 'daterange') {
+        if (item.initval) {
+          try {
+            let _initval = JSON.parse(item.initval)
+            let _vals = [moment().subtract(_initval[0], 'days').format('YYYY-MM-DD'), moment().subtract(_initval[1], 'days').format('YYYY-MM-DD')]
+            item.initval = _vals.join(',')
+          } catch {
+            item.initval = ''
+          }
+        }
+      } else if (item.type === 'group') {
+        if (item.initval && item.initval[0]) {
+          let _type = item.initval[0]
+          let _val = item.initval[1]
+          let _dateRange = ''
+    
           if (_type === 'day') {
-            copy.value = [moment().subtract(_val, 'days').format('YYYY-MM-DD'),
+            _dateRange = [moment().subtract(_val, 'days').format('YYYY-MM-DD'),
               moment().subtract(_val, 'days').format('YYYY-MM-DD')]
           } else if (_type === 'week') {
-            copy.value = [moment().subtract(_val * 7, 'days').startOf('week').format('YYYY-MM-DD'),
+            _dateRange = [moment().subtract(_val * 7, 'days').startOf('week').format('YYYY-MM-DD'),
               moment().subtract(_val * 7, 'days').endOf('week').format('YYYY-MM-DD')]
           } else if (_type === 'month') {
-            copy.value = [moment().subtract(_val, 'month').startOf('month').format('YYYY-MM-DD'),
+            _dateRange = [moment().subtract(_val, 'month').startOf('month').format('YYYY-MM-DD'),
               moment().subtract(_val, 'month').endOf('month').format('YYYY-MM-DD')]
           } else if (_type === 'quarter') {
             let _differ = parseInt(moment().format('MM')) % 3
             let _pdiffer = 0
             let _ndiffer = 0
-
+    
             // 宸�艰绠�
             switch(_differ) {
               case 0:
@@ -300,82 +301,108 @@
                 break
               default:
             }
-
-            copy.value = [moment().subtract(_pdiffer + _val * 3, 'month').startOf('month').format('YYYY-MM-DD'),
+            _dateRange = [moment().subtract(_pdiffer + _val * 3, 'month').startOf('month').format('YYYY-MM-DD'),
               moment().subtract(_ndiffer + _val * 3, 'month').endOf('month').format('YYYY-MM-DD')]
           } else if (_type === 'year') {
             let _year = parseInt(moment().format('YYYY')) - _val
-            copy.value = [_year + '-01-01', _year + '-12-31']
+            _dateRange = [_year + '-01-01', _year + '-12-31']
           } else if (_type === 'customized') {
             try {
               _val = JSON.parse(_val)
             } catch {
               _val = [0, 0]
             }
-            copy.value = [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
+            _dateRange = [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
               moment().subtract(_val[1], 'days').format('YYYY-MM-DD')]
           }
-        }
 
-        if (search.transfer === 'true') {
-          newsearches.push(item)
+          item.initval = _dateRange.join(',')
+          item.initType = _type
+        } else {
+          item.initval = ''
+          item.initType = ''
         }
-        newsearches.push(copy)
-        return
-      } else if (item.type === 'date') {
-        item.value = item.value ? moment().subtract(item.value, 'days').format('YYYY-MM-DD') : ''
-      } else if (item.type === 'datemonth') {
-        item.value = item.value ? moment().subtract(item.value, 'month').format('YYYY-MM') : ''
-      } else if (item.type === 'dateweek') {
-        item.value = item.value ? [moment().subtract(item.value * 7, 'days').startOf('week').format('YYYY-MM-DD'),
-          moment().subtract(item.value * 7, 'days').endOf('week').format('YYYY-MM-DD')] : ''
-      } else if (item.type === 'daterange') {
-        let _val = item.value
-        if (_val) {
-          try {
-            _val = JSON.parse(_val)
-          } catch {
-            _val = ''
-          }
-        }
-        item.value = _val ? [moment().subtract(_val[0], 'days').format('YYYY-MM-DD'),
-          moment().subtract(_val[1], 'days').format('YYYY-MM-DD')] : ''
-      } else if (item.type === 'multiselect') {
-        item.value = item.value ? item.value.split(',').filter(Boolean) : []
       }
-      newsearches.push(item)
+      
+      item.oriInitval = item.initval
+
+      if (item.blacklist && item.blacklist.length > 0 && !item.hidden) {
+        if (item.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
+          item.hidden = true
+          item.required = false
+        }
+      }
+
+      return item
     })
-    
-    return newsearches
   }
 
   /**
    * @description 鍒濆鍖栨悳绱㈡潯浠�
    * @param {Array}   searches     鎼滅储鏉′欢
-   * @return {String}  searches    鏍煎紡鍖栧悗缁撴灉
+   */
+  static initMainSearch (searches) {
+    if (!searches) return []
+
+    let values = []
+    searches.forEach(cell => {
+      let item = {
+        key: cell.field,
+        match: cell.match,
+        type: cell.type,
+        label: cell.label,
+        value: cell.initval,
+        required: cell.required
+      }
+      
+      if (cell.type === 'multiselect' || (cell.type === 'checkcard' && cell.multiple === 'true')) {
+        item.type = 'multi'
+      } else if (item.type === 'group') {
+        item.key = cell.datefield
+        item.type = 'daterange'
+        item.match = 'between'
+
+        values.push({
+          type: 'group',
+          key: cell.field,
+          value: cell.initType,
+          label: cell.label,
+          match: '=',
+          forbid: true,
+          required: cell.required
+        })
+      }
+
+      values.push(item)
+    })
+    
+    return values
+  }
+
+  /**
+   * @description 鍒濆鍖栬嚜瀹氫箟鍑芥暟鎼滅储鏉′欢
+   * @param {Array}   searches     鎼滅储鏉′欢
    */
   static formatCustomMainSearch (searches) {
-    if (!searches || searches.length === 0) return {}
+    if (!searches) return {}
 
     let newsearches = {}
     searches.forEach(item => {
       if (item.type === 'date') {
-        let timetail = ''
-        let _val = item.value
+        let _val = item.value || ''
 
-        if (item.match === '<' || item.match === '<=') {
-          timetail = ' 00:00:00.000'
-          if (_val) {
-            _val = moment(_val, 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+        if (_val) {
+          if (item.match === '<' || item.match === '<=') {
+            _val = moment(_val, 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+          } else if (item.match === '>' || item.match === '>=') {
+            _val = _val + ' 00:00:00.000'
           }
-        } else if (item.match === '>' || item.match === '>=') {
-          timetail = ' 00:00:00.000'
         }
 
         if (newsearches[item.key]) {
-          newsearches[item.key + '1'] = _val ? _val + timetail : ''
+          newsearches[item.key + '1'] = _val
         } else {
-          newsearches[item.key] = _val ? _val + timetail : ''
+          newsearches[item.key] = _val
         }
       } else if (item.type === 'datemonth') {
         // 鏈�-杩囨护鏉′欢锛屼粠鏈堝紑濮嬭嚦缁撴潫
@@ -390,35 +417,32 @@
         newsearches[item.key] = _startval
         newsearches[item.key + '1'] = _endval
       } else if (item.type === 'dateweek') {
+        let _startval = ''
         let _endval = ''
         if (item.value) {
-          _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+          _startval = moment(item.value, 'YYYY-MM-DD' ).startOf('week').format('YYYY-MM-DD') + ' 00:00:00.000'
+          _endval = moment(item.value, 'YYYY-MM-DD').endOf('week').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
         }
 
-        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : ''
-        newsearches[item.key + '1'] = item.value ? _endval + ' 00:00:00.000' : ''
+        newsearches[item.key] = _startval
+        newsearches[item.key + '1'] = _endval
       } else if (item.type === 'daterange') {
+        let _startval = ''
         let _endval = ''
         if (item.value) {
-          _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD')
+          let val = item.value.split(',')
+          _startval = val[0] + ' 00:00:00.000'
+          _endval = moment(val[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
         }
 
-        newsearches[item.key] = item.value ? item.value[0] + ' 00:00:00.000' : ''
-        newsearches[item.key + '1'] = item.value ? _endval + ' 00:00:00.000' : ''
+        newsearches[item.key] = _startval
+        newsearches[item.key + '1'] = _endval
       } else if (item.type === 'text' || item.type === 'select') {
         item.key.split(',').forEach(field => { // 缁煎悎鎼滅储锛屾墍瀛楁鎷兼帴
           newsearches[field] = item.value
         })
-      } else if (item.type === 'multiselect') {
-        newsearches[item.key] = item.value.join(',')
       } else {
         newsearches[item.key] = item.value
-      }
-    })
-
-    Object.keys(newsearches).forEach(key => {
-      if (!newsearches[key]) {
-        delete newsearches[key]
       }
     })
     
@@ -435,7 +459,7 @@
 
     let searchText = ''
     searches.forEach(item => {
-      if (item.forbid || !item.value || (item.type === 'multiselect' && item.value.length === 0)) return
+      if (item.forbid || !item.value) return
       
       searchText += (searchText !== '' ? ' AND ' : '')
       if (item.type === 'text' || item.type === 'select') { // 缁煎悎鎼滅储锛屾枃鏈垨涓嬫媺锛屾墍鏈夊瓧娈垫嫾鎺�
@@ -445,9 +469,8 @@
         })
 
         searchText += '(' + fields.join(' OR ') + ')'
-      } else if (item.type === 'multiselect') {
-
-        searchText += `'${item.value}' ` + item.match + ' \'%\'+' + item.key + '+\'%\''
+      } else if (item.type === 'multi') {
+        searchText += `'${item.value}' ${item.match} '%'+${item.key}+'%'`
       } else if (item.type === 'date') {
         let _val = item.value
         let timetail = ' 00:00:00.000'
@@ -467,15 +490,20 @@
 
         searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
       } else if (item.type === 'dateweek') { // 鍛�-杩囨护鏉′欢
-        let _startval = item.value[0] + ' 00:00:00.000'
-        let _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+        let _startval = moment(item.value, 'YYYY-MM-DD' ).startOf('week').format('YYYY-MM-DD') + ' 00:00:00.000'
+        let _endval = moment(item.value, 'YYYY-MM-DD').endOf('week').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
 
         searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
       } else if (item.type === 'daterange') {
-        let _startval = item.value[0] + ' 00:00:00.000'
-        let _endval = moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+        let val = item.value.split(',')
+        let _startval = val[0] + ' 00:00:00.000'
+        let _endval = moment(val[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
 
         searchText += '(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')'
+      } else if (item.type === 'range') {
+        let val = item.value.split(',')
+
+        searchText += '(' + item.key + ' >= \'' + val[0] + '\' AND ' + item.key + ' < \'' + val[1] + '\')'
       } else {
         searchText += '(' + item.key + ' ' + item.match + ' \'' + item.value + '\')'
       }
@@ -529,8 +557,8 @@
         options.push(item)
         options.push(copy)
       } else if (item.type === 'dateweek') {
-        let _startval = item.value && item.value[0] ? moment(item.value[0], 'YYYY-MM-DD').format('YYYY-MM-DD') + ' 00:00:00.000' : '1970-01-01 00:00:00.000'
-        let _endval = item.value && item.value[1] ? moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000' : '2050-01-01 00:00:00.000'
+        let _startval = item.value ? moment(item.value, 'YYYY-MM-DD').startOf('week').format('YYYY-MM-DD') + ' 00:00:00.000' : '1970-01-01 00:00:00.000'
+        let _endval = item.value ? moment(item.value, 'YYYY-MM-DD').endOf('week').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000' : '2050-01-01 00:00:00.000'
 
         let copy = JSON.parse(JSON.stringify(item))
         copy.key = copy.key + '1'
@@ -541,8 +569,14 @@
         options.push(item)
         options.push(copy)
       } else if (item.type === 'daterange') {
-        let _startval = item.value && item.value[0] ? item.value[0] + ' 00:00:00.000' : '1970-01-01 00:00:00.000'
-        let _endval = item.value && item.value[1] ? moment(item.value[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000' : '2050-01-01 00:00:00.000'
+        let _startval = '1970-01-01 00:00:00.000'
+        let _endval = '2050-01-01 00:00:00.000'
+        
+        if (item.value) {
+          let val = item.value.split(',')
+          _startval = val[0] + ' 00:00:00.000'
+          _endval = moment(val[1], 'YYYY-MM-DD').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
+        }
 
         let copy = JSON.parse(JSON.stringify(item))
         copy.key = copy.key + '1'
@@ -552,10 +586,6 @@
 
         options.push(item)
         options.push(copy)
-      } else if (item.type === 'multiselect') {
-        item.value = item.value ? item.value.join(',') : item.value
-
-        options.push(item)
       } else if (item.type === 'text' || item.type === 'select') {
         item.key.split(',').forEach(field => { // 缁煎悎鎼滅储锛屾墍瀛楁鎷兼帴
           let cell = JSON.parse(JSON.stringify(item))
@@ -595,6 +625,10 @@
 
       if (search.type === 'group') {
         options.push({
+          key: search.field,
+          value: '0'
+        })
+        options.push({
           key: search.datefield,
           value: '0'
         })
@@ -602,9 +636,7 @@
           key: search.datefield + '1',
           value: '0'
         })
-        if (search.transfer === 'true') {
-          options.push(item)
-        }
+        options.push(item)
       } else if (['datemonth', 'dateweek', 'daterange'].includes(search.type)) {
         options.push(item)
         options.push({
@@ -624,33 +656,6 @@
     })
 
     return options
-  }
-
-  /**
-   * @description 鎷兼帴鎼滅储鏉′欢datamanage
-   * @param {Array}   searches     鎼滅储鏉′欢
-   * @return {String}  searchText  鎷兼帴缁撴灉
-   */
-  static jointsearchkey (searches) {
-    if (!searches || searches.length === 0) return ''
-    let searchText = ''
-    searches.forEach(item => {
-      if (!item.value) return
-      searchText += (searchText !== '' ? ' AND ' : '')
-      if (item.type === 'text') {
-        let options = item.key.split(',').map(op => {
-          // equal鏃朵笉娣诲姞%
-          let str = item.op === 'equal' ? '' : '%'
-          return op + ' ' + item.op + ' \'' + str + item.value + str + '\''
-        })
-        searchText += '(' + options.join(' OR ') + ')'
-      } else if (item.type === 'date') {
-        searchText += '(' + item.key + ' ' + item.op + ' \'' + item.value + '\')'
-      } else {
-        searchText += '(' + item.key + ' ' + item.op + ' \'' + item.value + '\')'
-      }
-    })
-    return searchText
   }
 
   /**
@@ -702,7 +707,10 @@
       arrfield.push(...item.linkSubField)
     } else if (item.type === 'checkcard') {
       arrfield = item.fields.map(f => f.field)
-      arrfield.push(item.valueField)
+      arrfield.push(item.cardValField)
+      if (item.urlField) {
+        arrfield.push(item.urlField)
+      }
     }
 
     arrfield = Array.from(new Set(arrfield))
@@ -758,14 +766,21 @@
   let userName = sessionStorage.getItem('User_Name') || ''
   let fullName = sessionStorage.getItem('Full_Name') || ''
   let city = sessionStorage.getItem('city') || ''
+  let _sheet = item.sheet
 
   if (sessionStorage.getItem('isEditState') === 'true') {
     userName = sessionStorage.getItem('CloudUserName') || ''
     fullName = sessionStorage.getItem('CloudFullName') || ''
   }
 
-  let database = item.sheet.match(/(.*)\.(.*)\./ig) || ''
-  let sheet = item.sheet.replace(/(.*)\.(.*)\./ig, '')
+  if (window.GLOB.externalDatabase !== null) {
+    _sheet = _sheet.replace(/@db@/ig, window.GLOB.externalDatabase)
+  }
+
+  let database = _sheet.match(/(.*)\.(.*)\./ig)
+  let sheet = _sheet.replace(/(.*)\.(.*)\./ig, '')
+  
+  database = database ? (database[0] || '') : ''
 
   let getuuid = () => {
     let uuid = []
@@ -811,6 +826,11 @@
 
   // 鎺у埗鍙版墦鍗版暟鎹�
   let conLtext = []
+  let cols = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
+  for (let i = 0; i < 26; i++) {
+    cols.push('A' + cols[i])
+  }
+
   let _Ltext = data.map((item, lindex) => {
     let vals = []
     let convals = []
@@ -818,14 +838,15 @@
       if (col.import === 'false') return
 
       let val = item[col.Column] !== undefined ? item[col.Column] : ''
-      let _position = (_topline + lindex + 1) + dict['main.excel.line'] + ' ' + (cindex + 1) + dict['main.excel.column']  + ' '
+      let _colindex = cols[cindex] || (cindex + 1)
+      let _position = (_topline + lindex + 1) + dict['main.excel.line'] + ' ' + _colindex + dict['main.excel.column']  + ' '
 
       if (/^Nvarchar/ig.test(col.type)) {
         if (typeof(val) === 'number') {
           val = val.toString()
         }
 
-        val = val.replace(/(^\s*$)|\t*|\v*/ig, '')
+        val = val.replace(/(^\s*$)|\t*|\v*|'*/ig, '')
 
         if (!val && col.required === 'true') {            // 蹇呭~鏍¢獙
           errors.push(_position + dict['main.excel.content.emptyerror'])
@@ -1057,13 +1078,14 @@
  * @return {Object}  tab       鏍囩淇℃伅
  * @return {Boolean} retmsg    鏄惁闇�瑕佹暟鎹繑鍥�
  */
-export function getSysDefaultSql (btn, setting, formdata, param, data, columns, tab, retmsg = false) {
+export function getSysDefaultSql (btn, setting, formdata, param, data, columns, tab, retmsg = false, moduleParams, getOptions) {
   let primaryId = param.ID
   let BID = param.BID
   let verify = btn.verify || {}
   let datavars = {}                 // 澹版槑鐨勫彉閲忥紝琛ㄥ崟鍙婃樉绀哄垪
   let _actionType = null
   let _callbacksql = ''
+  let foreignKey = tab && tab.foreignKey ? tab.foreignKey.toLowerCase() : ''
 
   if (verify.default !== 'false') { // 鍒ゆ柇鏄惁浣跨敤榛樿sql
     _actionType = btn.sqlType
@@ -1156,7 +1178,7 @@
   }
 
   // 娣诲姞鏁版嵁涓瓧娈碉紝琛ㄥ崟鍊间紭鍏�(鎸夐挳涓嶉�夎鎴栧琛屾嫾鎺ユ椂璺宠繃)
-  if (data && btn.Ot !== 'notRequired' && btn.Ot !== 'requiredOnce') {
+  if (data && !btn.$forbid && btn.Ot !== 'notRequired' && btn.Ot !== 'requiredOnce') {
     datavars = {...data, ...datavars}
 
     const setField = (col) => {
@@ -1290,14 +1312,53 @@
   // 澶辨晥楠岃瘉锛屾坊鍔犳暟鎹椂涓嶇敤
   if (btn.sqlType !== 'insert' && btn.Ot !== 'notRequired' && verify.invalid === 'true' && setting.dataresource) {
     let datasource = setting.dataresource
+    let customScript = setting.customScript || ''
+    let search = moduleParams ? moduleParams.search : null
+    let orderBy = moduleParams ? moduleParams.orderBy : setting.order
+
     if (/\s/.test(datasource) && !/tb$/.test(datasource)) { // 鎷兼帴鍒悕
       datasource = '(' + datasource + ') tb'
     }
 
-    if (setting.customScript) {
+    if (getOptions && (setting.queryType === 'statistics' || customScript)) {
+      let allSearch = getOptions(search)
+
+      let regoptions = allSearch.map(item => {
+        return {
+          reg: new RegExp('@' + item.key + '@', 'ig'),
+          value: `'${item.value}'`
+        }
+      })
+      regoptions.push({
+        reg: new RegExp('@login_city@', 'ig'),
+        value: `'${city}'`
+      }, {
+        reg: new RegExp('@userName@', 'ig'),
+        value: `'${userName}'`
+      }, {
+        reg: new RegExp('@fullName@', 'ig'),
+        value: `'${fullName}'`
+      }, {
+        reg: new RegExp('@orderBy@', 'ig'),
+        value: orderBy
+      }, {
+        reg: new RegExp('@pageSize@', 'ig'),
+        value: 999999
+      }, {
+        reg: new RegExp('@pageIndex@', 'ig'),
+        value: 1
+      })
+
+      regoptions.forEach(item => {
+        datasource = datasource.replace(item.reg, item.value)
+        customScript = customScript.replace(item.reg, item.value)
+      })
+    }
+
+    if (customScript) {
       _sql += `
       /* 鏁版嵁婧愯嚜瀹氫箟鑴氭湰锛岃娉ㄦ剰鍙橀噺瀹氫箟鏄惁閲嶅 */
-      ${setting.customScript}
+      ${customScript}
       `
     }
 
@@ -1435,9 +1496,9 @@
         if (_key === 'bid' && !datavars.bid) { // 琛ㄥ崟涓病鏈塨id鍒欎娇鐢ㄧ郴缁焍id鍙橀噺
           _fval = '@BID@'
         }
-        if (_key === 'bid' && tab && tab.foreignKey) {
-          arr.push(tab.foreignKey.toLowerCase())
-          _fieldValue.push(`${tab.foreignKey}=${_fval}`)
+        if (_key === 'bid' && foreignKey) {
+          arr.push(foreignKey)
+          _fieldValue.push(`${foreignKey}=${_fval}`)
         } else {
           arr.push(_key)
           _fieldValue.push(`${_key}=${_fval}`)
@@ -1558,14 +1619,14 @@
       values.push('@fullname')
     }
     if (!keys.includes('bid')) {
-      if (tab && tab.foreignKey && !keys.includes(tab.foreignKey.toLowerCase())) {
-        keys.push(tab.foreignKey.toLowerCase())
+      if (foreignKey && !keys.includes(foreignKey)) {
+        keys.push(foreignKey)
       } else {
         keys.push('bid')
       }
       values.push('@BID@')
-    } else if (tab && tab.foreignKey && !keys.includes(tab.foreignKey.toLowerCase())) {
-      keys.push(tab.foreignKey.toLowerCase())
+    } else if (foreignKey && !keys.includes(foreignKey)) {
+      keys.push(foreignKey)
       values.push('@BID@')
     }
 
@@ -1714,6 +1775,45 @@
 }
 
 /**
+ * @description 鐢熸垚鏇挎崲鍑芥暟鍒楄〃
+ */
+export function setGLOBFuncs () {
+  window.GLOB.funcs = []
+  if (!window.GLOB.WebSql && !window.GLOB.IndexDB) {
+    return
+  }
+
+  if (window.GLOB.WebSql) {
+    window.GLOB.WebSql.transaction(tx => {
+      tx.executeSql("SELECT * FROM FUNCS", [], (tx, results) => {
+        let rows = results.rows
+        if (!rows || rows.length === 0) return
+        for (let i = 0; i < rows.length; i++) {
+          window.GLOB.funcs.push({
+            func_code: rows[i].func_code,
+            key_sql: window.decodeURIComponent(window.atob(rows[i].key_sql))
+          })
+        }
+      })
+    })
+  } else {
+    let objectStore = window.GLOB.IndexDB.transaction('funcs').objectStore('funcs')
+
+    objectStore.openCursor().onsuccess = (event) => {
+      let cursor = event.target.result
+
+      if (cursor) {
+        window.GLOB.funcs.push({
+          func_code: cursor.value.func_code,
+          key_sql: window.decodeURIComponent(window.atob(cursor.value.key_sql))
+        })
+        cursor.continue()
+      }
+    }
+  }
+}
+
+/**
  * @description 鍒涘缓瀛樺偍杩囩▼绫�
  */
 export class FuncUtils {
diff --git a/src/views/appmanage/header/index.jsx b/src/views/appmanage/header/index.jsx
new file mode 100644
index 0000000..96bba6d
--- /dev/null
+++ b/src/views/appmanage/header/index.jsx
@@ -0,0 +1,31 @@
+import React, {Component} from 'react'
+
+import avatar from '@/assets/img/avatar.jpg'
+import MainLogo from '@/assets/img/main-logo.png'
+import './index.scss'
+
+class AppManageHeader extends Component {
+  state = {
+    avatar: sessionStorage.getItem('CloudAvatar') || avatar,
+    userName: sessionStorage.getItem('CloudUserName')
+  }
+
+  render () {
+    return (
+      <header className="app-manage-header-container">
+        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="title">
+          搴旂敤绠$悊
+        </div>
+        <div className="header-user">
+          <img src={this.state.avatar} alt=""/>
+          <span>
+            <span className="username">{this.state.userName}</span>
+          </span>
+        </div>
+      </header>
+    )
+  }
+}
+
+export default AppManageHeader
\ No newline at end of file
diff --git a/src/views/appmanage/header/index.scss b/src/views/appmanage/header/index.scss
new file mode 100644
index 0000000..fd7bb98
--- /dev/null
+++ b/src/views/appmanage/header/index.scss
@@ -0,0 +1,57 @@
+.app-manage-header-container {
+  width: 100%;
+  height: 48px;
+  color: rgba(255, 255, 255, 0.65);
+  position: fixed;
+  top: 0px;
+  z-index: 10;
+  padding-right: 0px;
+  left: 0;
+  
+  background: #001529;
+  border-bottom: 1px solid #000;
+
+  .header-logo {
+    float: left;
+    width: 180px;
+    line-height: 48px;
+    text-align: center;
+    padding-left: 5px;
+    box-sizing: border-box;
+    opacity: 1;
+    img {
+      max-width: 100%;
+      max-height: 40px;
+    }
+  }
+  .header-user {
+    float: right;
+    line-height: 48px;
+    margin-right: 10px;
+    img {
+      width: 29px;
+      height: 29px;
+      border-radius: 30px;
+      margin-right: 7px;
+    }
+    span {
+      color: #ffffff;
+      font-size: 0.95rem;
+      .username {
+        display: inline-block;
+        height: 30px;
+        max-width: 95px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+  }
+  .title {
+    position: absolute;
+    left: calc(50% - 36px);
+    top: 10px;
+    color: #ffffff;
+    font-size: 18px;
+  }
+}
\ No newline at end of file
diff --git a/src/views/appmanage/index.jsx b/src/views/appmanage/index.jsx
index 3efc3ba..c238f65 100644
--- a/src/views/appmanage/index.jsx
+++ b/src/views/appmanage/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import { fromJS } from 'immutable'
-import { Spin, notification, Button, Table, Modal, ConfigProvider } from 'antd'
+import { Spin, notification, Input, Button, Table, Modal, ConfigProvider, Typography, Row, Col, Tooltip, Icon } from 'antd'
 import moment from 'moment'
 import md5 from 'md5'
 import enUS from 'antd/es/locale/en_US'
@@ -12,114 +12,115 @@
 import './index.scss'
 
 const { confirm } = Modal
+const { Paragraph } = Typography
+const { Search } = Input
 
 const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
-const Header = asyncComponent(() => import('@/mob/header'))
+const Header = asyncComponent(() => import('./header'))
 const MutilForm = asyncComponent(() => import('./mutilform'))
+const TransForm = asyncComponent(() => import('./transform'))
+const ScriptForm = asyncComponent(() => import('./scriptform'))
 const SubMutilForm = asyncComponent(() => import('./submutilform'))
+
+let base_url = ''
+if (process.env.NODE_ENV === 'production') {
+  base_url = document.location.origin + '/' + window.GLOB.service
+} else {
+  base_url = window.GLOB.location + '/' + window.GLOB.service
+}
+
+sessionStorage.setItem('isEditState', 'true')
+
+const skinStyle = {
+  bg_black_style_blue: {name: '钃濊壊', color: '#1890ff'},
+  bg_black_style_red: {name: '绾㈣壊', color: '#f5222d'},
+  bg_black_style_orange_red: {name: '姗欑孩鑹�', color: '#fa541c'},
+  bg_black_style_orange: {name: '姗欒壊', color: '#fa8c16'},
+  bg_black_style_orange_yellow: {name: '姗欓粍鑹�', color: '#faad14'},
+  bg_black_style_yellow: {name: '榛勮壊', color: '#fadb14'},
+  bg_black_style_yellow_green: {name: '榛勭豢鑹�', color: '#a0d911'},
+  bg_black_style_green: {name: '缁胯壊', color: '#52c41a'},
+  bg_black_style_cyan: {name: '闈掕壊', color: '#13c2c2'},
+  bg_black_style_blue_purple: {name: '钃濈传鑹�', color: '#2f54eb'},
+  bg_black_style_purple: {name: '绱壊', color: '#722ed1'},
+  bg_black_style_magenta: {name: '娲嬬孩鑹�', color: '#eb2f96'},
+  bg_black_style_grass_green: {name: '鑽夌豢鑹�', color: '#aeb303'},
+  bg_black_style_deep_red: {name: '娣辩孩鑹�', color: '#c32539'}
+}
 
 class AppManage extends Component {
   state = {
     loading: false,
     applist: [],
     columns: [
-      { title: '搴旂敤鍚嶇О', dataIndex: 'remark', key: 'remark', align: 'center' },
-      { title: '搴旂敤缂栫爜', dataIndex: 'kei_no', key: 'kei_no', align: 'center' },
+      { title: '搴旂敤鍚嶇О', dataIndex: 'remark', key: 'remark', align: 'center', width: '30%' },
+      { title: '搴旂敤缂栫爜', dataIndex: 'kei_no', key: 'kei_no', align: 'center', width: '30%' },
       {
         title: '鎿嶄綔',
         key: 'action',
         align: 'center',
-        render: (text, record) => (<Button type="link" onClick={() => this.deleteApp(record)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>),
-      },
-    ],
-    subcolumns: [
-      {
-        title: '搴旂敤绫诲瀷', dataIndex: 'typename', key: 'typename', align: 'center'
-      },
-      {
-        title: '璇█', dataIndex: 'lang', key: 'lang', align: 'center',
-        render: (text, record) => text === 'en-US' ? '鑻辨枃' : '涓枃'
-      },
-      {
-        title: '鐧诲綍', dataIndex: 'login_types', key: 'login_types', align: 'center',
-        render: (text, record) => text === 'false' ? '涓嶉渶瑕�' : '闇�瑕�'
-      },
-      {
-        title: '鏉冮檺绠$悊', dataIndex: 'role_type', key: 'role_type', align: 'center',
-        render: (text, record) => text === 'false' ? '涓嶅惎鐢�' : '鍚敤'
-      },
-      {
-        title: '鐭繛鎺�', dataIndex: 'link_type', key: 'link_type', align: 'center',
-        render: (text, record) => text === 'false' ? '涓嶅惎鐢�' : '鍚敤'
-      },
-      {
-        title: '鐨偆', dataIndex: 'css', key: 'css', align: 'center',
-        render: (text, record) => {
-          const style = {
-            bg_black_style_blue: '钃濋粦鑹茬郴',
-            bg_white_style_blue: '钃濈櫧鑹茬郴',
-            bg_black_style_red: '绾㈤粦鑹茬郴',
-            bg_white_style_red: '绾㈢櫧鑹茬郴',
-            bg_black_style_orange_red: '姗欑孩榛戣壊绯�',
-            bg_white_style_orange_red: '姗欑孩鐧借壊绯�',
-            bg_black_style_orange: '姗欓粦鑹茬郴',
-            bg_white_style_orange: '姗欑櫧鑹茬郴',
-            bg_black_style_orange_yellow: '姗欓粍榛戣壊绯�',
-            bg_white_style_orange_yellow: '姗欓粍鐧借壊绯�',
-            bg_black_style_yellow: '榛勯粦鑹茬郴',
-            bg_white_style_yellow: '榛勭櫧鑹茬郴',
-            bg_black_style_yellow_green: '榛勭豢榛戣壊绯�',
-            bg_white_style_yellow_green: '榛勭豢鐧借壊绯�',
-            bg_black_style_green: '缁块粦鑹茬郴',
-            bg_white_style_green: '缁跨櫧鑹茬郴',
-            bg_black_style_cyan: '闈掗粦鑹茬郴',
-            bg_white_style_cyan: '闈掔櫧鑹茬郴',
-            bg_black_style_blue_purple: '钃濈传榛戣壊绯�',
-            bg_white_style_blue_purple: '钃濈传鐧借壊绯�',
-            bg_black_style_purple: '绱粦鑹茬郴',
-            bg_white_style_purple: '绱櫧鑹茬郴',
-            bg_black_style_magenta: '娲嬬孩榛戣壊绯�',
-            bg_white_style_magenta: '娲嬬孩鐧借壊绯�',
-            bg_black_style_grass_green: '鑽夌豢榛戣壊绯�',
-            bg_white_style_grass_green: '鑽夌豢鐧借壊绯�',
-            bg_black_style_deep_red: '娣辩孩榛戣壊绯�',
-            bg_white_style_deep_red: '娣辩孩鐧借壊绯�'
-          }
-
-          return style[text] || '钃濋粦鑹茬郴'
-        }
-      },
-      {
-        title: '鏍囬', dataIndex: 'title', key: 'title', align: 'center', width: '170px'
-      },
-      {
-        title: '鍥炬爣', dataIndex: 'favicon', key: 'favicon', align: 'center', width: '120px',
-        render: (text, record) => (text ? <img style={{width: '32px', height: '32px'}} src={text} alt="" /> : null)
-      },
-      {
-        title: '鎿嶄綔',
-        key: 'action',
-        align: 'center',
-        width: '190px',
+        width: '40%',
         render: (text, record) => (
           <div>
-            <Button type="link" onClick={() => this.deleteSubApp(record)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>
-            <Button type="link" onClick={() => this.jumpApp(record)}>缂栬緫搴旂敤</Button>
+            <Button type="link" onClick={() => this.setState({ selectApp: record, visible: 'edit' })} style={{color: '#8E44AD'}}>淇敼</Button>
+            <Button type="link" onClick={() => this.deleteApp(record)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>
+            <Button type="link" onClick={() => this.setState({ selectSubApp: record, subVisible: 'plus' })} style={{color: '#26C281'}}>娣诲姞瀛愬簲鐢�</Button>
           </div>
-        )
+        ),
       },
     ],
     selectApp: null,
     selectSubApp: null,
-    selectedRowKeys: [],
-    selectedSubRowKeys: [],
     visible: false,
-    subVisible: false
+    subVisible: false,
+    transcolumns: [
+      { title: '浼犺緭鍙�', dataIndex: 'VersionName', key: 'VersionName', align: 'left', render: (text, record) => (
+        <Paragraph copyable={{text}}>{text}</Paragraph>
+      )},
+      { title: '璇存槑', dataIndex: 'ProgramName', key: 'ProgramName', align: 'left' },
+      { title: '鐘舵��', dataIndex: 'StatusName', key: 'StatusName', align: 'left' },
+      { title: '鍒涘缓鏃堕棿', dataIndex: 'CreateDate', key: 'CreateDate', align: 'left' },
+      {
+        title: '鎿嶄綔',
+        key: 'action',
+        align: 'center',
+        width: '230px',
+        render: (text, record) => (
+          <div onClick={() => this.forbid = true}>
+            <Button type="link" onClick={() => this.setState({ editTran: record, transVisible: 'edit' })} style={{color: '#8E44AD'}}>淇敼</Button>
+            <Button type="link" onClick={() => this.deleteTran(record)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>
+            <Button type="link" onClick={() => this.enableTran(record)} style={{color: '#26C281'}}>鍚敤</Button>
+          </div>
+        ),
+      },
+    ],
+    transVisible: false,
+    translist: [],
+    tranSearchKey: '',
+    selectTran: null,
+    editTran: null,
+    transIndex: 1,
+    transTotal: 0,
+    scriptcolumns: [
+      { title: '鍏抽敭瀛�', dataIndex: 'KeyWords', key: 'KeyWords', align: 'left' },
+      { title: '鎻忚堪', dataIndex: 'Remark', key: 'Remark', align: 'left' },
+      { title: '绫诲瀷', dataIndex: 'TypeName', key: 'TypeName', align: 'left' },
+      { title: '鎺掑簭', dataIndex: 'Sort', key: 'Sort', align: 'left' },
+    ],
+    scriptVisible: false,
+    scriptlist: [],
+    scriptSearchKey: '',
+    scriptIndex: 1,
+    scriptTotal: 0,
   }
+
+  forbid = false
 
   UNSAFE_componentWillMount() {
     document.body.className = ''
     this.getAppList()
+    this.getSmStemp()
+    this.getTransList()
   }
 
   /**
@@ -131,10 +132,322 @@
     }
   }
 
+  getTransList = () => {
+    const { tranSearchKey, transIndex } = this.state
+
+    let param = {
+      func: 's_get_sVersion',
+      dataM: 'Y',
+      PageSize: 10,
+      PageIndex: transIndex,
+      OrderCol: 'ID desc'
+    }
+
+    if (tranSearchKey) {
+      param.VersionName = tranSearchKey
+      param.ProgramName = tranSearchKey
+    }
+
+    this.setState({
+      loading: true
+    })
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        this.setState({
+          loading: false,
+          translist: result.data,
+          selectTran: null,
+          scriptlist: [],
+          transTotal: result.total
+        })
+      } else {
+        this.setState({
+          loading: false
+        })
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  getScriptList = () => {
+    const { scriptSearchKey, scriptIndex, selectTran } = this.state
+
+    if (!selectTran || !selectTran.ID) {
+      notification.warning({
+        top: 92,
+        message: '缂哄皯浼犺緭鍙稩D!',
+        duration: 3
+      })
+      return
+    }
+
+    let param = {
+      func: 's_get_sVersionDetail',
+      dataM: 'Y',
+      PageSize: 10,
+      PageIndex: scriptIndex,
+      OrderCol: 'Sort desc',
+      BID: selectTran.ID,
+    }
+
+    if (scriptSearchKey) {
+      param.TypeName = scriptSearchKey
+      param.KeyWords = scriptSearchKey
+      param.Remark = scriptSearchKey
+    }
+
+    this.setState({
+      loading: true
+    })
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        this.setState({
+          loading: false,
+          scriptlist: result.data,
+          scriptTotal: result.total,
+          selectScriptKeys: []
+        })
+      } else {
+        this.setState({
+          loading: false
+        })
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  scriptSearch = (value) => {
+    this.setState({scriptSearchKey: value, scriptIndex: 1}, () => {
+      this.getScriptList()
+    })
+  }
+
+  changeScriptTable = (pagination) => {
+    this.setState({
+      scriptIndex: pagination.current
+    }, () => {
+      this.getScriptList()
+    })
+  }
+
+  changeTable = (pagination) => {
+    this.setState({
+      transIndex: pagination.current
+    }, () => {
+      this.getTransList()
+    })
+  }
+
+  tranSearch = (value) => {
+    this.setState({tranSearchKey: value, transIndex: 1}, () => {
+      this.getTransList()
+    })
+  }
+
+  submitTrans = () => {
+    const { transVisible, editTran } = this.state
+
+    this.transRef.handleConfirm().then(res => {
+      this.setState({
+        confirmloading: true
+      })
+
+      let param = {}
+
+      if (transVisible === 'plus') {
+        param.func = 's_sVersion_add'
+        param.VersionName = res.VersionName
+        param.ProgramName = res.ProgramName
+      } else {
+        param.func = 's_sVersion_upt'
+        param.ProgramName = res.ProgramName
+        param.ID = editTran.ID
+      }
+
+      Api.getCloudConfig(param).then(result => {
+        if (result.status) {
+          notification.success({
+            top: 92,
+            message: '鎿嶄綔鎴愬姛锛�',
+            duration: 3
+          })
+          this.setState({
+            confirmloading: false,
+            transVisible: false
+          })
+          this.getTransList()
+        } else {
+          this.setState({
+            confirmloading: false
+          })
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        }
+      }, () => {
+        this.setState({
+          confirmloading: false
+        })
+      })
+    })
+  }
+
+  submitScript = () => {
+    const { selectTran } = this.state
+
+    this.scriptRef.handleConfirm().then(res => {
+      this.setState({
+        confirmloading: true
+      })
+
+      let kei_no = res.appId.split(',')[1]
+      let lang = res.subAppId.split(',')[1]
+      let kei_no_detail = res.subAppId.split(',')[2]
+      
+      let param = {
+        func: 's_sVersionDetail_CloudAdd',
+        kei_no: kei_no,
+        kei_no_detail: kei_no_detail,
+        lang: lang,
+        BID: selectTran.ID
+      }
+
+      if (res.VType === 'subapp') {
+        param.VType = 'mob_menu'
+        param.TrdMenuID = ''
+        param.upid = md5(window.GLOB.appkey + kei_no + kei_no_detail + lang)
+      } else if (res.VType === 'view') {
+        param.VType = 'mob_menu'
+        param.TrdMenuID = res.viewId
+      } else if (res.VType === 'role') {
+        param.VType = 'mob_roletree'
+        param.upid = md5(window.GLOB.appkey + kei_no + kei_no_detail + lang)
+      }
+
+      Api.getCloudConfig(param).then(result => {
+        if (result.status) {
+          notification.success({
+            top: 92,
+            message: '鎿嶄綔鎴愬姛锛�',
+            duration: 3
+          })
+          this.setState({
+            scriptIndex: 1,
+            confirmloading: false,
+            scriptVisible: false
+          }, () => {
+            this.getScriptList()
+          })
+        } else {
+          this.setState({
+            confirmloading: false
+          })
+          notification.warning({
+            top: 92,
+            message: result.message,
+            duration: 5
+          })
+        }
+      }, () => {
+        this.setState({
+          confirmloading: false
+        })
+      })
+    })
+  }
+
+  deleteTran = (record) => {
+    const _this = this
+
+    let param = {
+      func: 's_sVersion_del',
+      ID: record.ID
+    }
+    
+    confirm({
+      content: '纭畾鍒犻櫎璇ヤ紶杈撳彿鍚楋紵',
+      onOk() {
+        return new Promise(resolve => {
+          Api.getCloudConfig(param).then(result => {
+            if (result.status) {
+              notification.success({
+                top: 92,
+                message: '鎿嶄綔鎴愬姛锛�',
+                duration: 3
+              })
+              _this.getTransList()
+            } else {
+              notification.warning({
+                top: 92,
+                message: result.message,
+                duration: 5
+              })
+            }
+            resolve()
+          }, () => {
+            resolve()
+          })
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  enableTran = (record) => {
+    const _this = this
+
+    let param = {
+      func: 's_sVersion_sub',
+      ID: record.ID
+    }
+    
+    confirm({
+      content: '纭畾鍚敤璇ヤ紶杈撳彿鍚楋紵',
+      onOk() {
+        return new Promise(resolve => {
+          Api.getCloudConfig(param).then(result => {
+            if (result.status) {
+              notification.success({
+                top: 92,
+                message: '鎿嶄綔鎴愬姛锛�',
+                duration: 3
+              })
+              _this.getTransList()
+            } else {
+              Modal.error({
+                title: result.message,
+              })
+            }
+            resolve()
+          }, () => {
+            resolve()
+          })
+        })
+      },
+      onCancel() {}
+    })
+  }
+
   getAppList = () => {
     let param = {
       func: 's_get_kei'
     }
+
+    this.setState({
+      loading: true
+    })
 
     Api.getCloudConfig(param).then(result => {
       if (result.status) {
@@ -153,6 +466,10 @@
           return item
         })
 
+        if (!selectApp && applist[0]) {
+          selectApp = applist[0]
+        }
+        
         this.setState({
           loading: false,
           applist: applist,
@@ -169,6 +486,39 @@
           duration: 5
         })
       }
+    })
+  }
+
+  getSmStemp = () => {
+    let _sql = `select ID,TemplateCode,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))
     })
   }
 
@@ -194,8 +544,6 @@
               })
 
               _this.setState({
-                selectedRowKeys: [],
-                selectedSubRowKeys: [],
                 selectApp: null,
                 selectSubApp: null,
                 loading: true
@@ -237,7 +585,8 @@
     let sublist = fromJS(selectApp.sublist).toJS()
     sublist = sublist.filter(item => item.ID !== record.ID)
 
-    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}'`)
+    // param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}'`)
+    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 || ''}','${item.sms_id || ''}'`)
     param.LText = param.LText.join(' union all ')
     param.LText = Utils.formatOptions(param.LText)
     
@@ -254,7 +603,6 @@
               })
       
               _this.setState({
-                selectedSubRowKeys: [],
                 selectSubApp: null,
                 loading: true
               })
@@ -287,74 +635,134 @@
     window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, type: 'app'})))}`))
   }
 
-  /**
-   * 
-   */
+  jumpMenu = (item) => {
+    const { selectApp } = this.state
+
+    window.open(window.location.href.replace(/#.+/ig, `#/role/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, type: 'app'})))}`))
+  }
+
   onSelectChange = selectedRowKeys => {
     const { applist } = this.state
     let selectApp = applist.filter(item => item.ID === selectedRowKeys[0])[0]
 
-    this.setState({ selectedRowKeys, selectApp })
+    this.setState({ selectApp })
   }
 
-  /**
-   * 
-   */
-  onSubChange = selectedSubRowKeys => {
-    this.setState({ selectedSubRowKeys })
+  onScriptChange = selectedRowKeys => {
+    this.setState({ selectScriptKeys: selectedRowKeys })
+  }
+
+  onScriptSelect = (record) => {
+    const { selectScriptKeys } = this.state
+
+    if (selectScriptKeys.includes(record.ID)) {
+      this.setState({ selectScriptKeys: selectScriptKeys.filter(key => key !== record.ID) })
+    } else {
+      this.setState({ selectScriptKeys: [...selectScriptKeys, record.ID]})
+    }
+  }
+
+  deleteScripts = () => {
+    const { selectScriptKeys, selectTran } = this.state
+
+    if (selectScriptKeys.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨瑕佸垹闄ょ殑鑴氭湰锛�',
+        duration: 3
+      })
+      return
+    }
+
+    let params = selectScriptKeys.map(key => {
+      return {
+        func: 's_sVersionDetail_del',
+        BID: selectTran.ID,
+        ID: key
+      }
+    })
+
+    const _this = this
+
+    confirm({
+      content: '纭畾瑕佹墽琛屽悧锛�',
+      onOk() {
+        return new Promise(resolve => {
+          let deffers = params.map((param, i) => {
+            return new Promise(resolve => {
+              setTimeout(() => {
+                Api.getCloudConfig(param).then(res => {
+                  resolve(res)
+                }, () => {
+                  resolve({status: false, message: '鍒犻櫎澶辫触锛�'})
+                })
+              }, i * 150)
+            })
+          })
+          Promise.all(deffers).then(result => {
+            let errorMsg = ''
+            result.forEach(res => {
+              if (!res.status) {
+                errorMsg = res.message
+              }
+            })
+            if (errorMsg) {
+              notification.warning({
+                top: 92,
+                message: errorMsg,
+                duration: 3
+              })
+            } else {
+              notification.success({
+                top: 92,
+                message: '鎵ц鎴愬姛銆�',
+                duration: 3
+              })
+              _this.setState({
+                scriptIndex: 1
+              }, () => {
+                _this.getScriptList()
+              })
+            }
+            resolve()
+          })
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  onTransChange = selectedRowKeys => {
+    const { translist, selectTran } = this.state
+    let _selectTran = translist.filter(item => item.ID === selectedRowKeys[0])[0]
+
+    this.setState({ selectTran: _selectTran })
+
+    if (!selectTran || selectTran.ID !== _selectTran.ID) {
+      this.setState({ scriptIndex: 1 }, () => {
+        this.getScriptList()
+      })
+    }
+  }
+
+  onTransSelect = (record) => {
+    const { selectTran } = this.state
+
+    this.setState({ selectTran: record })
+
+    if (!selectTran || selectTran.ID !== record.ID) {
+      this.setState({ scriptIndex: 1 }, () => {
+        this.getScriptList()
+      })
+    }
   }
 
   /**
    * @description 鐐瑰嚮鏁磋锛岃Е鍙戝垏鎹紝 鍒ゆ柇鏄惁鍙�夛紝鍗曢�夋垨澶氶�夛紝杩涜瀵瑰簲鎿嶄綔
    */
   changeRow = (record) => {
-    this.setState({ selectedRowKeys: [record.ID], selectApp: record })
+    this.setState({ selectApp: record })
   }
-
-  /**
-   * @description 鐐瑰嚮鏁磋锛岃Е鍙戝垏鎹紝 鍒ゆ柇鏄惁鍙�夛紝鍗曢�夋垨澶氶�夛紝杩涜瀵瑰簲鎿嶄綔
-   */
-  changeSubRow = (record) => {
-    this.setState({ selectedSubRowKeys: [record.ID], selectSubApp: record })
-  }
-
-  trigerApp = (type) => {
-    if (type === 'edit' && !this.state.selectApp) {
-      notification.warning({
-        top: 92,
-        message: '璇烽�夋嫨闇�瑕佺紪杈戠殑搴旂敤锛�',
-        duration: 5
-      })
-      return
-    }
-
-    this.setState({
-      visible: type
-    })
-  }
-
-  trigerSubApp = (type) => {
-    if (type === 'edit' && !this.state.selectSubApp) {
-      notification.warning({
-        top: 92,
-        message: '璇烽�夋嫨闇�瑕佺紪杈戠殑瀛愬簲鐢紒',
-        duration: 5
-      })
-      return
-    } else if (!this.state.selectApp) {
-      notification.warning({
-        top: 92,
-        message: '璇烽�夋嫨搴旂敤锛�',
-        duration: 5
-      })
-      return
-    }
-
-    this.setState({
-      subVisible: type
-    })
-  }
-
   
   submitCard = () => {
     const { selectApp, visible } = this.state
@@ -384,7 +792,8 @@
       param.secretkey = Utils.encrypt('', param.timestamp)
 
       if (visible === 'edit') {
-        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
+        // param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
+        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 || ''}','${item.sms_id || ''}'`)
         param.LText = param.LText.join(' union all ')
         param.LText = Utils.formatOptions(param.LText)
       }
@@ -398,8 +807,6 @@
           })
 
           this.setState({
-            selectedRowKeys: [],
-            selectedSubRowKeys: [],
             selectApp: null,
             selectSubApp: null,
             confirmloading: false,
@@ -470,7 +877,8 @@
         })
       }
 
-      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
+      // param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','${item.login_types || 'true'}','${item.link_type || 'true'}','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}'`)
+      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 || ''}','${item.sms_id || ''}'`)
       param.LText = param.LText.join(' union all ')
       param.LText = Utils.formatOptions(param.LText)
 
@@ -483,7 +891,6 @@
           })
 
           this.setState({
-            selectedSubRowKeys: [],
             selectSubApp: null,
             confirmloading: false,
             subVisible: false,
@@ -509,7 +916,7 @@
   }
 
   render () {
-    const { loading, visible, subVisible, columns, applist, selectedRowKeys, selectedSubRowKeys, subcolumns, selectApp, selectSubApp } = this.state
+    const { loading, visible, subVisible, columns, transcolumns, applist, translist, transVisible, selectApp, selectTran, selectSubApp, scriptVisible, scriptlist, scriptcolumns, selectScriptKeys } = this.state
 
     return (
       <div className="mk-app-manage">
@@ -517,45 +924,161 @@
           <Header view="manage" />
           {loading ?
             <div className="loading-mask">
-              <div className="ant-spin-blur"></div>
-              <Spin />
+              <Spin size="large" />
             </div> : null
           }
-          <div className="app-table">
-            <div className="app-action">
-              <Button className="mk-green" onClick={() => this.trigerApp('plus')}>娣诲姞</Button>
-              <Button className="mk-purple" onClick={() => this.trigerApp('edit')}>淇敼</Button>
+          <div className="view-wrap">
+            <div className="left-view">
+              <div className="app-table">
+                <div className="app-action">
+                  <Button className="mk-green" onClick={() => this.setState({ visible: 'plus' })}>娣诲姞搴旂敤</Button>
+                </div>
+                <Table
+                  rowKey="ID"
+                  columns={columns}
+                  dataSource={applist}
+                  pagination={false}
+                  rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
+                  onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
+                />
+              </div>
+              <div className={'trans-table' + (this.state.transTotal <= 10 ? ' no-footer' : '')}>
+                <div className="app-action">
+                  <Button className="mk-green" onClick={() => this.setState({ transVisible: 'plus' })}>娣诲姞浼犺緭鍙�</Button>
+                  <Search placeholder="缁煎悎鎼滅储" onSearch={value => this.tranSearch(value)} enterButton />
+                </div>
+                <Table
+                  rowKey="ID"
+                  columns={transcolumns}
+                  dataSource={translist}
+                  pagination={{
+                    current: this.state.transIndex,
+                    pageSize: 10,
+                    total: this.state.transTotal || 0,
+                    showTotal: (total, range) => `${range[0]}-${range[1]} 鍏� ${total} 鏉
+                  }}
+                  rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }}
+                  onRow={(record) => ({ onClick: () => {
+                    if (this.forbid) {
+                      this.forbid = false
+                      return
+                    }
+                    this.onTransSelect(record)
+                  }})}
+                  onChange={this.changeTable}
+                />
+              </div>
+              {selectTran ? <div className="script-table">
+                <div className="app-action">
+                  <Button className="mk-green" onClick={() => this.setState({ scriptVisible: true })}>娣诲姞鑴氭湰</Button>
+                  <Button className="mk-danger" onClick={this.deleteScripts} style={{marginLeft: '15px'}}>鍒犻櫎</Button>
+                  <Search placeholder="缁煎悎鎼滅储" defaultValue={this.state.scriptSearchKey} onSearch={value => this.scriptSearch(value)} enterButton />
+                </div>
+                <Table
+                  rowKey="ID"
+                  columns={scriptcolumns}
+                  dataSource={scriptlist}
+                  pagination={{
+                    current: this.state.scriptIndex,
+                    pageSize: 10,
+                    total: this.state.scriptTotal || 0,
+                    showTotal: (total, range) => `${range[0]}-${range[1]} 鍏� ${total} 鏉
+                  }}
+                  rowSelection={{ type: 'checkbox', selectedRowKeys: selectScriptKeys, onChange: this.onScriptChange }}
+                  onRow={(record) => ({ onClick: () => this.onScriptSelect(record)})}
+                  onChange={this.changeScriptTable}
+                />
+              </div> : null}
             </div>
-            <Table
-              rowKey="ID"
-              columns={columns}
-              dataSource={applist}
-              pagination={false}
-              rowSelection={{ type: 'radio', selectedRowKeys, onChange: this.onSelectChange }}
-              onRow={(record) => ({ onClick: () => {this.changeRow(record)} })}
-            />
-          </div>
-          <div className="app-table">
-            <div className="sub-app-title"><span>瀛愬簲鐢�</span></div>
-            <div className="app-action">
-              <Button className="mk-green" onClick={() => this.trigerSubApp('plus')}>娣诲姞</Button>
-              <Button className="mk-purple" onClick={() => this.trigerSubApp('edit')}>淇敼</Button>
+            <div className="right-view">
+              {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
+              {selectApp && selectApp.sublist.map((item, index) => {
+                let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
+                let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
+                let binding = ''
+                if (item.user_binding) {
+                  if (item.user_binding.indexOf('uname_pwd') > -1) {
+                    binding = '鐢ㄦ埛鍚�'
+                  }
+                  if (item.user_binding.indexOf('sms_vcode') > -1) {
+                    binding = binding ? binding + '锛屾墜鏈哄彿' : '鎵嬫満鍙�'
+                  }
+                }
+                return (
+                  <div className="sub-app" key={index} style={{borderColor: color}}>
+                    <Row>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">搴旂敤绫诲瀷:</div>
+                          <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">璇█:</div>
+                          <div className="content" style={{textDecoration: 'underline'}}>{item.lang === 'en-US' ? '鑻辨枃' : '涓枃'}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">鏉冮檺绠$悊:</div>
+                          <div className="content">{item.role_type === 'false' ? '涓嶅惎鐢�' : '鍚敤'}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          {/* <div className="label">鐧诲綍:</div>
+                          <div className="content">{item.login_types === 'false' ? '涓嶉渶瑕�' : '闇�瑕�'}</div> */}
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">鐨偆:</div>
+                          <div className="content" style={{color: color}}>{css}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          {binding ? <div className="label">
+                            <Tooltip placement="topLeft" title="寰俊鍏紬鍙风櫥褰曟椂锛岀郴缁熺敤鎴蜂笌寰俊鐢ㄦ埛鐨勭粦瀹氭柟寮忋��">
+                              <Icon type="question-circle" />
+                              鐢ㄦ埛缁戝畾:
+                            </Tooltip>
+                          </div> : null}
+                          <div className="content">{binding}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">鏍囬:</div>
+                          <div className="content">{item.title || '鏃�'}</div>
+                        </div>
+                      </Col>
+                      <Col span={12}>
+                        <div className="app-item">
+                          <div className="label">缃戠珯鍥炬爣:</div>
+                          <div className="content">{item.favicon ? <img style={{width: '30px', height: '30px'}} src={item.favicon} alt="" /> : '鏃�'}</div>
+                        </div>
+                      </Col>
+                    </Row>
+                    <div className="action">
+                      <Button type="link" onClick={() => this.jumpMenu(item)} style={{color: 'rgba(30, 228, 224, 1)'}}>鑿滃崟&鏉冮檺</Button>
+                      <Button type="link" onClick={() => this.setState({ selectSubApp: item, subVisible: 'edit' })} style={{color: '#8E44AD'}}>淇敼</Button>
+                      <Button type="link" onClick={() => this.deleteSubApp(item)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>
+                      <Button type="link" onClick={() => this.jumpApp(item)}>缂栬緫搴旂敤</Button>
+                      <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${base_url}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
+                    </div>
+                  </div>
+                )
+              })}
             </div>
-            <Table
-              rowKey="ID"
-              columns={subcolumns}
-              dataSource={selectApp ? selectApp.sublist : []}
-              pagination={false}
-              rowSelection={{ type: 'radio', selectedRowKeys: selectedSubRowKeys, onChange: this.onSubChange }}
-              onRow={(record) => ({ onClick: () => {this.changeSubRow(record)} })}
-            />
           </div>
           <Modal
             title={'缂栬緫搴旂敤'}
             width={'600px'}
             maskClosable={false}
-            visible={!!visible}
-            onCancel={() => this.setState({visible: false})}
+            visible={visible !== false}
+            onCancel={() => this.setState({visible: false, confirmloading: false})}
             confirmLoading={this.state.confirmloading}
             onOk={this.submitCard}
             cancelText="鍙栨秷"
@@ -565,11 +1088,39 @@
             <MutilForm type={visible} card={visible === 'edit' ? selectApp : ''} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
           </Modal>
           <Modal
-            title={'缂栬緫瀛愬簲鐢�'}
-            width={'750px'}
+            title={transVisible === 'plus' ? '娣诲姞浼犺緭鍙�' : '缂栬緫浼犺緭鍙�'}
+            width={'600px'}
             maskClosable={false}
-            visible={!!subVisible}
-            onCancel={() => this.setState({subVisible: false})}
+            visible={transVisible !== false}
+            onCancel={() => this.setState({transVisible: false, confirmloading: false})}
+            confirmLoading={this.state.confirmloading}
+            onOk={this.submitTrans}
+            cancelText="鍙栨秷"
+            okText="纭畾"
+            destroyOnClose
+          >
+            <TransForm type={transVisible} card={transVisible === 'edit' ? this.state.editTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} />
+          </Modal>
+          <Modal
+            title={'娣诲姞鑴氭湰'}
+            width={750}
+            maskClosable={false}
+            visible={scriptVisible}
+            onCancel={() => this.setState({scriptVisible: false, confirmloading: false})}
+            confirmLoading={this.state.confirmloading}
+            onOk={this.submitScript}
+            cancelText="鍙栨秷"
+            okText="纭畾"
+            destroyOnClose
+          >
+            <ScriptForm applist={applist} wrappedComponentRef={(inst) => this.scriptRef = inst} inputSubmit={this.submitScript} />
+          </Modal>
+          <Modal
+            title={'缂栬緫瀛愬簲鐢�'}
+            width={'850px'}
+            maskClosable={false}
+            visible={subVisible !== false}
+            onCancel={() => this.setState({subVisible: false, confirmloading: false})}
             confirmLoading={this.state.confirmloading}
             onOk={this.submitSubCard}
             cancelText="鍙栨秷"
diff --git a/src/views/appmanage/index.scss b/src/views/appmanage/index.scss
index b1aa6a4..5f9cb3b 100644
--- a/src/views/appmanage/index.scss
+++ b/src/views/appmanage/index.scss
@@ -1,41 +1,121 @@
 .mk-app-manage {
   background: #fff;
   min-height: 100vh;
-  padding-bottom: 70px;
+  padding: 70px 30px;
 
-  .mob-header-container {
-    padding-right: 0px;
-    position: relative;
-    z-index: 10;
+  .loading-mask {
+    position: fixed;
+    top: 0px;
+    bottom: 0px;
+    left: 0px;
+    right: 0px;
+    z-index: 2;
+    background: rgba(255, 255, 255, 0.35);
+
+    .ant-spin {
+      position: absolute;
+      left: 50%;
+      top: 50%;
+    }
   }
-  .app-table {
-    max-width: 1440px;
-    margin: 0 auto;
-    padding: 40px 30px 20px;
-    .sub-app-title {
-      margin-bottom: 15px;
-      border-bottom: 1px solid #e8e8e8;
-      span {
-        position: relative;
-        top: 1px;
-        display: inline-block;
-        color: #1890ff;
-        padding: 10px 15px 5px;
-        border-bottom: 2px solid #1890ff;
+  .view-wrap {
+    width: 100%;
+    position: relative;
+    display: flex;
+
+    .left-view {
+      flex: 1;
+      width: 60%;
+      padding-right: 5px;
+      .trans-table, .script-table {
+        margin-top: 40px;
+        .ant-input-search {
+          width: 250px;
+          float: right;
+        }
+        .ant-typography, .ant-typography p {
+          margin-bottom: 0;
+        }
+      }
+      .trans-table.no-footer {
+        .ant-pagination {
+          display: none;
+        }
+      }
+    }
+    .right-view {
+      width: 40%;
+      padding-left: 20px;
+
+      .app-title {
+        font-size: 16px;
+        font-weight: 500;
+        height: 30px;
+        line-height: 30px;
+        border-bottom: 1px solid #d8d8d8;
+        margin-bottom: 17px;
+      }
+      .sub-app {
+        margin: 10px 10px 25px;
+        border: 1px solid #e8e8e8;
+        height: 180px;
+        border-radius: 4px;
+        padding-top: 10px;
+
+        .app-item {
+          height: 30px;
+          line-height: 30px;
+          div {
+            display: inline-block;
+            white-space: nowrap;
+            overflow: hidden;
+            white-space: nowrap;
+            text-overflow: ellipsis;
+            line-height: 30px;
+          }
+          .label {
+            width: 40%;
+            text-align: right;
+            color: rgba(0, 0, 0, 0.65);
+            .anticon-question-circle {
+              color: #c49f47;
+              margin-right: 3px;
+            }
+          }
+          .content {
+            width: 60%;
+            padding-left: 10px;
+            color: rgba(0, 0, 0, 0.85);
+          }
+        }
+        .action {
+          text-align: right;
+          padding: 5px 20px;
+          margin-top: 5px;
+          border-top: 1px solid #e8e8e8;
+
+          .ant-typography-copy {
+            color: #26C281;
+          }
+        }
       }
     }
   }
   .ant-table-wrapper {
-    border: 1px solid #e8e8e8;
-    border-bottom: 0;
-    border-radius: 4px;
-    .ant-table-tbody > tr.ant-table-row-selected td {
-      background: #bae7ff;
+    .ant-table-body {
+      border: 1px solid #e8e8e8;
+      border-bottom: 0;
+      border-radius: 4px;
+    }
+    .ant-table-tbody {
+      > tr.ant-table-row-selected td {
+        background: #bae7ff;
+      }
     }
   }
   .app-action {
-    button {
-      margin: 0px 15px 15px 0px;
+    >button {
+      margin-bottom: 10px;
     }
   }
 }
diff --git a/src/views/appmanage/scriptform/index.jsx b/src/views/appmanage/scriptform/index.jsx
new file mode 100644
index 0000000..999599d
--- /dev/null
+++ b/src/views/appmanage/scriptform/index.jsx
@@ -0,0 +1,242 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input, Select, notification } from 'antd'
+import moment from 'moment'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const { TextArea } = Input
+
+class ScriptForm extends Component {
+  static propTpyes = {
+    applist: PropTypes.array,
+    inputSubmit: PropTypes.func
+  }
+
+  state = {
+    type: 'subapp',
+    sublist: [],
+    views: [],
+    appId: '',
+    subAppId: ''
+  }
+
+  viewList = {}
+
+  UNSAFE_componentWillMount() {
+    const { applist } = this.props
+
+    let sublist = []
+    let appId = ''
+    let subAppId = ''
+    if (applist[0]) {
+      sublist = applist[0].sublist || []
+      appId = applist[0].ID + ',' + applist[0].kei_no
+
+      if (sublist[0]) {
+        subAppId = sublist[0].ID + ',' + sublist[0].lang + ',' + sublist[0].typename
+      }
+    }
+
+    this.viewList = {}
+
+    this.setState({sublist, appId, subAppId})
+  }
+
+  /**
+   * @description 鑾峰彇琛ㄥ崟鍊�
+   */
+  handleConfirm = () => {
+    return new Promise(resolve => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        }
+      })
+    })
+  }
+
+  changeType = (val) => {
+    this.setState({type: val}, () => {
+      this.getViews()
+    })
+  }
+
+  changeApp = (val) => {
+    const { applist } = this.props
+
+    let app = applist.filter(item => `${item.ID},${item.kei_no}` === val)[0]
+
+    let appId = ''
+    let subAppId = ''
+    let sublist = []
+    if (app) {
+      sublist = app.sublist || []
+      appId = app.ID + ',' + app.kei_no
+
+      if (sublist[0]) {
+        subAppId = sublist[0].ID + ',' + sublist[0].lang + ',' + sublist[0].typename
+      }
+    }
+
+    this.setState({sublist, subAppId, appId}, () => {
+      this.getViews()
+    })
+    this.props.form.setFieldsValue({subAppId})
+  }
+
+  changeSubApp = (val) => {
+    this.setState({subAppId: val}, () => {
+      this.getViews()
+    })
+  }
+
+  getViews = () => {
+    const { type, appId, subAppId } = this.state
+
+    if (type !== 'view' || !appId || !subAppId) return
+
+    this.setState({views: []})
+    this.props.form.setFieldsValue({viewId: ''})
+
+    let kei = appId.split(',')[1]
+    let m = subAppId.split(',')
+
+    let _param = {
+      func: 's_get_app_menus',
+      TypeCharOne: kei,
+      typename: m[2],
+      lang: m[1],
+      LText: `select '${window.GLOB.appkey}'`,
+      timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
+    }
+
+    _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
+
+    Api.getCloudConfig(_param).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+        return
+      }
+
+      this.setState({views: res.menus})
+    })
+  }
+
+  /**
+   * @description 鍥炶溅鎻愪氦
+   */
+  handleSubmit = (e) => {
+    e.preventDefault()
+    this.props.inputSubmit()
+  }
+
+  render() {
+    const { applist } = this.props
+    const { getFieldDecorator } = this.props.form
+    const { sublist, appId, subAppId, type, views } = this.state
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 16 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="app-script-form">
+        <Row gutter={24}>
+          <Col span={12}>
+            <Form.Item label="绫诲瀷">
+              {getFieldDecorator('VType', {
+                initialValue: 'subapp',
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨绫诲瀷!'
+                }]
+              })(
+                <Select onChange={this.changeType}>
+                  <Select.Option value="subapp">瀛愬簲鐢�</Select.Option>
+                  <Select.Option value="view">椤甸潰</Select.Option>
+                  <Select.Option value="role">鏉冮檺鏍�</Select.Option>
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="搴旂敤">
+              {getFieldDecorator('appId', {
+                initialValue: appId,
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨搴旂敤!'
+                }]
+              })(
+                <Select onChange={this.changeApp}>
+                  {applist.map(item => {
+                    return <Select.Option key={item.ID} value={item.ID + ',' + item.kei_no}>{item.remark}</Select.Option>
+                  })}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={12}>
+            <Form.Item label="瀛愬簲鐢�">
+              {getFieldDecorator('subAppId', {
+                initialValue: subAppId,
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨瀛愬簲鐢�!'
+                }]
+              })(
+                <Select onChange={this.changeSubApp}>
+                  {sublist.map(item => {
+                    return <Select.Option key={item.ID} value={item.ID + ',' + item.lang + ',' + item.typename}>{`${item.typename}锛�${item.lang !== 'zh-CN' ? '鑻辨枃' : '涓枃'}锛�${item.title || ''}`}</Select.Option>
+                  })}
+                </Select>
+              )}
+            </Form.Item>
+          </Col>
+          {type === 'view' ? <Col span={12}>
+            <Form.Item label="椤甸潰">
+              {getFieldDecorator('viewId', {
+                initialValue: '',
+                rules: [{
+                  required: true,
+                  message: '璇烽�夋嫨椤甸潰!'
+                }]
+              })(
+                <Select>
+                  {views.map(item => {
+                    return <Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>
+                  })}
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
+          <Col span={24} className="remark">
+            <Form.Item label="璇存槑">
+              {getFieldDecorator('Remark', {
+                initialValue: '',
+                rules: [{
+                  max: 512,
+                  message: '璇存槑涓嶅彲瓒呰繃512涓瓧绗�!'
+                }]
+              })(<TextArea autoSize={{ minRows: 2, maxRows: 6 }} />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(ScriptForm)
\ No newline at end of file
diff --git a/src/views/appmanage/scriptform/index.scss b/src/views/appmanage/scriptform/index.scss
new file mode 100644
index 0000000..74e8f0b
--- /dev/null
+++ b/src/views/appmanage/scriptform/index.scss
@@ -0,0 +1,12 @@
+.app-script-form {
+  padding: 0px 24px 20px;
+
+  .remark {
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/views/appmanage/submutilform/index.jsx b/src/views/appmanage/submutilform/index.jsx
index 712464f..137c862 100644
--- a/src/views/appmanage/submutilform/index.jsx
+++ b/src/views/appmanage/submutilform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Select, Radio, Input } from 'antd'
+import { Form, Row, Col, Select, Radio, Input, Tooltip, Icon, notification } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
@@ -14,7 +14,21 @@
     inputSubmit: PropTypes.func  // input鍥炶溅鎻愪氦
   }
 
-  state = {}
+  state = {msgs: [], typename: 'mob', user_binding: []}
+
+  UNSAFE_componentWillMount() {
+    const { card } = this.props
+    let msgs = sessionStorage.getItem('msgTemplate')
+    let user_binding = []
+    let typename = 'mob'
+
+    if (card) {
+      typename = card.typename || 'mob'
+      user_binding = card.user_binding ? card.user_binding.split(',') : []
+    }
+
+    this.setState({msgs: JSON.parse(msgs), typename, user_binding})
+  }
 
   /**
    * @description 鑾峰彇琛ㄥ崟鍊�
@@ -23,10 +37,14 @@
     return new Promise(resolve => {
       this.props.form.validateFieldsAndScroll((err, values) => {
         if (!err) {
-          if (values.favicon && values.favicon.length > 0 && values.favicon[0].status === 'done') {
-            values.favicon = values.favicon[0].response || values.favicon[0].url || ''
-          } else {
-            values.favicon = ''
+          values.user_binding = values.user_binding ? values.user_binding.join(',') : ''
+          if (values.user_binding.indexOf('sms_vcode') > -1 && !values.sms_id) {
+            notification.warning({
+              top: 92,
+              message: '鎵嬫満鍙风粦瀹氭椂锛岄渶瑕佺煭淇℃ā鏉匡紒',
+              duration: 5
+            })
+            return
           }
           resolve(values)
         }
@@ -45,6 +63,7 @@
   render() {
     const { card, type } = this.props
     const { getFieldDecorator } = this.props.form
+    const { msgs, typename, user_binding } = this.state
     const formItemLayout = {
       labelCol: {
         xs: { span: 24 },
@@ -56,28 +75,23 @@
       }
     }
 
-    let filelist = []
+    let file = ''
 
     if (type === 'edit' && card && card.favicon) {
-      filelist = [{
-        uid: `favicon`,
-        name: card.favicon.slice(card.favicon.lastIndexOf('/') + 1),
-        status: 'done',
-        url: card.favicon,
-        origin: true
-      }]
+      file = card.favicon
     }
 
     return (
-      <Form {...formItemLayout} className="mob-card-edit-form">
+      <Form {...formItemLayout} className="sub-app-edit-form">
         <Row gutter={24}>
           <Col span={12}>
             <Form.Item label="搴旂敤绫诲瀷">
               {getFieldDecorator('typename', {
-                initialValue: card ? card.typename : 'mob'
+                initialValue: typename
               })(
-                <Select disabled={type === 'edit'}>
+                <Select disabled={type === 'edit'} onChange={(val) => this.setState({typename: val})}>
                   <Select.Option value="mob">绉诲姩绔�(鍖呮嫭android銆乮os)</Select.Option>
+                  <Select.Option value="pad">Pad绔�</Select.Option>
                   <Select.Option value="pc">PC绔�</Select.Option>
                 </Select>
               )}
@@ -95,7 +109,7 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={12}>
+          {/* <Col span={12}>
             <Form.Item label="鐧诲綍">
               {getFieldDecorator('login_types', {
                 initialValue: card ? card.login_types || 'true' : 'true'
@@ -106,7 +120,7 @@
                 </Radio.Group>
               )}
             </Form.Item>
-          </Col>
+          </Col> */}
           <Col span={12}>
             <Form.Item label="鏉冮檺绠$悊">
               {getFieldDecorator('role_type', {
@@ -119,52 +133,61 @@
               )}
             </Form.Item>
           </Col>
-          <Col span={12}>
-            <Form.Item label="鐭繛鎺�">
-              {getFieldDecorator('link_type', {
-                initialValue: card ? card.link_type || 'true' : 'true'
+          {typename !== 'pc' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="浣跨敤寰俊鎺堟潈鐧诲綍鏃讹紝鏄惁闇�瑕佺粦瀹氱敤鎴枫��">
+                <Icon type="question-circle" />
+                鐢ㄦ埛缁戝畾
+              </Tooltip>
+            }>
+              {getFieldDecorator('user_binding', {
+                initialValue: user_binding
               })(
-                <Radio.Group>
-                  <Radio value="true">鍚敤</Radio>
-                  <Radio value="false">涓嶅惎鐢�</Radio>
-                </Radio.Group>
+                <Select mode="multiple">
+                  <Select.Option value="uname_pwd">鐢ㄦ埛鍚�</Select.Option>
+                  <Select.Option value="sms_vcode">鎵嬫満鍙�</Select.Option>
+                </Select>
               )}
             </Form.Item>
-          </Col>
+          </Col> : null}
+          {typename !== 'pc' ? <Col span={12}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="鐭俊妯℃澘鍙湪绠$悊绯荤粺 HS-濂囦簯鐭俊妯℃澘 澶勬坊鍔犮��">
+                <Icon type="question-circle" />
+                鐭俊妯℃澘
+              </Tooltip>
+            }>
+              {getFieldDecorator('sms_id', {
+                initialValue: card ? card.sms_id || '' : ''
+              })(
+                <Select allowClear>
+                  {msgs.map(option =>
+                    <Select.Option key={option.ID} value={option.ID}>{option.SignName + ' - ' + option.TemplateCode}</Select.Option>
+                  )}
+                </Select>
+              )}
+            </Form.Item>
+          </Col> : null}
           <Col span={12}>
             <Form.Item label="鐨偆">
               {getFieldDecorator('css', {
                 initialValue: card ? card.css : 'bg_black_style_blue'
               })(
                 <Select>
-                  <Select.Option value="bg_black_style_blue">钃濋粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_blue">钃濈櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_red">绾㈤粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_red">绾㈢櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_orange_red">姗欑孩榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_orange_red">姗欑孩鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_orange">姗欓粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_orange">姗欑櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_orange_yellow">姗欓粍榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_orange_yellow">姗欓粍鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_yellow">榛勯粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_yellow">榛勭櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_yellow_green">榛勭豢榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_yellow_green">榛勭豢鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_green">缁块粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_green">缁跨櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_cyan">闈掗粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_cyan">闈掔櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_blue_purple">钃濈传榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_blue_purple">钃濈传鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_purple">绱粦鑹茬郴</Select.Option>
-                  <Select.Option value="bg_white_style_purple">绱櫧鑹茬郴</Select.Option>
-                  <Select.Option value="bg_black_style_magenta">娲嬬孩榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_magenta">娲嬬孩鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_grass_green">鑽夌豢榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_grass_green">鑽夌豢鐧借壊绯�</Select.Option>
-                  <Select.Option value="bg_black_style_deep_red">娣辩孩榛戣壊绯�</Select.Option>
-                  <Select.Option value="bg_white_style_deep_red">娣辩孩鐧借壊绯�</Select.Option>
+                  <Select.Option value="bg_black_style_blue">钃濊壊</Select.Option>
+                  <Select.Option value="bg_black_style_red">绾㈣壊</Select.Option>
+                  <Select.Option value="bg_black_style_orange_red">姗欑孩鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_orange">姗欒壊</Select.Option>
+                  <Select.Option value="bg_black_style_orange_yellow">姗欓粍鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_yellow">榛勮壊</Select.Option>
+                  <Select.Option value="bg_black_style_yellow_green">榛勭豢鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_green">缁胯壊</Select.Option>
+                  <Select.Option value="bg_black_style_cyan">闈掕壊</Select.Option>
+                  <Select.Option value="bg_black_style_blue_purple">钃濈传鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_purple">绱壊</Select.Option>
+                  <Select.Option value="bg_black_style_magenta">娲嬬孩鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_grass_green">鑽夌豢鑹�</Select.Option>
+                  <Select.Option value="bg_black_style_deep_red">娣辩孩鑹�</Select.Option>
                 </Select>
               )}
             </Form.Item>
@@ -179,8 +202,13 @@
           <Col span={12}>
             <Form.Item label="鍥炬爣">
               {getFieldDecorator('favicon', {
-                initialValue: filelist
-              })(<FileUpload accept=".jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp,.ico" maxFile={1} fileType={'text'} />)}
+                initialValue: file
+              })(<FileUpload config={{
+                initval: file,
+                suffix: '.jpg,.png,.gif,.pjp,.pjpeg,.jpeg,.jfif,.webp,.ico',
+                maxfile: 1,
+                fileType: 'text'
+              }}/>)}
             </Form.Item>
           </Col>
         </Row>
diff --git a/src/views/appmanage/submutilform/index.scss b/src/views/appmanage/submutilform/index.scss
index 28344fe..b2364d9 100644
--- a/src/views/appmanage/submutilform/index.scss
+++ b/src/views/appmanage/submutilform/index.scss
@@ -1,4 +1,8 @@
-.mob-card-edit-form {
+.sub-app-edit-form {
   padding: 0px 24px 20px;
 
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
 }
\ No newline at end of file
diff --git a/src/views/appmanage/transform/index.jsx b/src/views/appmanage/transform/index.jsx
new file mode 100644
index 0000000..9ede6fb
--- /dev/null
+++ b/src/views/appmanage/transform/index.jsx
@@ -0,0 +1,89 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Form, Row, Col, Input } from 'antd'
+import './index.scss'
+
+class MainSearch extends Component {
+  static propTpyes = {
+    type: PropTypes.any,         // 缂栬緫绫诲瀷
+    card: PropTypes.any,         // 缂栬緫搴旂敤
+    inputSubmit: PropTypes.func  // input鍥炶溅鎻愪氦
+  }
+
+  state = {}
+
+  /**
+   * @description 鑾峰彇琛ㄥ崟鍊�
+   */
+  handleConfirm = () => {
+    return new Promise(resolve => {
+      this.props.form.validateFieldsAndScroll((err, values) => {
+        if (!err) {
+          resolve(values)
+        }
+      })
+    })
+  }
+
+  /**
+   * @description 鍥炶溅鎻愪氦
+   */
+  handleSubmit = (e) => {
+    e.preventDefault()
+    this.props.inputSubmit()
+  }
+
+  render() {
+    const { card, type } = this.props
+    const { getFieldDecorator } = this.props.form
+    const formItemLayout = {
+      labelCol: {
+        xs: { span: 24 },
+        sm: { span: 8 }
+      },
+      wrapperCol: {
+        xs: { span: 24 },
+        sm: { span: 12 }
+      }
+    }
+    return (
+      <Form {...formItemLayout} className="mob-card-edit-form">
+        <Row gutter={24}>
+          {type !== 'edit' ? <Col span={24}>
+            <Form.Item label="浼犺緭鍙�">
+              {getFieldDecorator('VersionName', {
+                initialValue: card ? card.VersionName : '',
+                rules: [{
+                  required: true,
+                  message: '璇疯緭鍏ヤ紶杈撳彿!'
+                }, {
+                  pattern: /^[a-zA-Z0-9]*$/gi,
+                  message: '璇疯緭鍏ユ暟瀛楁垨瀛楁瘝!'
+                }, {
+                  max: 20,
+                  message: '浼犺緭鍙蜂笉鍙秴杩�20涓瓧绗�!'
+                }]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col> : null}
+          <Col span={24}>
+            <Form.Item label="鎻忚堪">
+              {getFieldDecorator('ProgramName', {
+                initialValue: card ? card.ProgramName : '',
+                rules: [{
+                  required: true,
+                  message: '璇疯緭鍏ユ弿杩�!'
+                }, {
+                  max: 50,
+                  message: '鎻忚堪涓嶅彲瓒呰繃50涓瓧绗�!'
+                }]
+              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
+            </Form.Item>
+          </Col>
+        </Row>
+      </Form>
+    )
+  }
+}
+
+export default Form.create()(MainSearch)
\ No newline at end of file
diff --git a/src/views/appmanage/transform/index.scss b/src/views/appmanage/transform/index.scss
new file mode 100644
index 0000000..28344fe
--- /dev/null
+++ b/src/views/appmanage/transform/index.scss
@@ -0,0 +1,4 @@
+.mob-card-edit-form {
+  padding: 0px 24px 20px;
+
+}
\ No newline at end of file
diff --git a/src/views/billprint/index.jsx b/src/views/billprint/index.jsx
index 66e09e1..38c9f1e 100644
--- a/src/views/billprint/index.jsx
+++ b/src/views/billprint/index.jsx
@@ -147,16 +147,44 @@
         config.width = pageParam[config.pageSize][config.pageLayout]
         config.style.height = Math.floor(config.width * pageParam[config.pageSize][config.pageLayout + config.pagePadding])
 
+        if (config.printCustom === 'true' && config.printWidth && config.printHeight) {
+          config.width = config.printWidth
+          config.style.height = config.printHeight
+        }
+
         let params = []
         let _pars = []
 
         config.components = config.components.filter(item => !['tabs', 'search'].includes(item.type))
+
+        let userName = sessionStorage.getItem('User_Name') || ''
+        let fullName = sessionStorage.getItem('Full_Name') || ''
+        let city = sessionStorage.getItem('city') || ''
+
+        if (sessionStorage.getItem('isEditState') === 'true') {
+          userName = sessionStorage.getItem('CloudUserName') || ''
+          fullName = sessionStorage.getItem('CloudFullName') || ''
+        }
+
+        let regs = [
+          { reg: /@userName@/ig, value: `'${userName}'` },
+          { reg: /@fullName@/ig, value: `'${fullName}'` },
+          { reg: /@login_city@/ig, value: `'${city}'` }
+        ]
+        
+        if (window.GLOB.externalDatabase !== null) {
+          regs.push({
+            reg: /@db@/ig,
+            value: window.GLOB.externalDatabase
+          })
+        }
+
         config.components = config.components.map(component => {
           if (component.action) component.action = []
           if (component.search) component.search = []
           component.data = [] // 鍒濆鍖栨暟鎹负绌�
 
-          if (['propcard', 'brafteditor', 'sandbox'].includes(component.subtype) && component.wrap.datatype === 'static') {
+          if (component.wrap.datatype === 'static') {
             component.format = ''
           }
     
@@ -198,11 +226,10 @@
             _customScript = _customScript.replace(/@\$|\$@/ig, '')
           }
 
-          // 澶栬仈鏁版嵁搴撴浛鎹�
-          if (window.GLOB.externalDatabase !== null) {
-            component.setting.dataresource = component.setting.dataresource.replace(/@db@/ig, window.GLOB.externalDatabase)
-            _customScript = _customScript.replace(/@db@/ig, window.GLOB.externalDatabase)
-          }
+          regs.forEach(cell => {
+            component.setting.dataresource = component.setting.dataresource.replace(cell.reg, cell.value)
+            _customScript = _customScript.replace(cell.reg, cell.value)
+          })
     
           component.setting.customScript = _customScript // 鏁寸悊鍚庤嚜瀹氫箟鑴氭湰
     
@@ -502,6 +529,7 @@
       let linkList = document.getElementsByTagName('link')     // 鑾峰彇鐖剁獥鍙ink鏍囩瀵硅薄鍒楄〃
       let styleList = document.getElementsByTagName('style')   // 鑾峰彇鐖剁獥鍙tyle鏍囩瀵硅薄鍒楄〃
 
+      iframe.style.marginTop = '600px'
       document.body.appendChild(iframe)
       let doc = iframe.contentWindow.document
       
diff --git a/src/views/billprint/index.scss b/src/views/billprint/index.scss
index 2c5512e..80dd4f8 100644
--- a/src/views/billprint/index.scss
+++ b/src/views/billprint/index.scss
@@ -32,17 +32,23 @@
 }
 
 .print-page {
+  color: rgba(0,0,0,1);
   table {
+    color: rgba(0,0,0,1);
     border-radius: 0!important;
     .ant-table-column-sorter {
       display: none!important;
     }
   }
   .ant-table-thead > tr > th {
+    color: rgba(0,0,0,1);
     background: transparent!important;
     border-radius: 0!important;
   }
 }
+.print-page:last-child {
+  height: auto!important;
+}
 
 .normal-custom-table .main-pickup {
   display: none!important;
diff --git a/src/views/design/header/index.jsx b/src/views/design/header/index.jsx
index 5b8c73d..5b14744 100644
--- a/src/views/design/header/index.jsx
+++ b/src/views/design/header/index.jsx
@@ -2,7 +2,7 @@
 import { withRouter } from 'react-router-dom'
 import {connect} from 'react-redux'
 import { is, fromJS } from 'immutable'
-import { Dropdown, Menu, Icon, Modal, Form, notification, Switch, Button } from 'antd'
+import { Dropdown, Menu, Icon, Modal, notification, Switch, Button } from 'antd'
 
 import asyncComponent from '@/utils/asyncComponent'
 import {
@@ -327,6 +327,9 @@
         {!editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' && this.props.memberLevel >= 20 ?
           <span onClick={() => {window.open('#/appmanage')}} className="mobile" type="edit"> 搴旂敤绠$悊 <Icon type="arrow-right" /></span> : null
         }
+        {!editLevel && options.sysType === 'local' && this.props.memberLevel >= 20 ?
+          <span onClick={() => {window.open('#/interface')}} className="interface" type="edit"> 鎺ュ彛璋冭瘯 <Icon type="arrow-right" /></span> : null
+        }
         {/* window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'home', MenuId: 'home_page_id', MenuName: '棣栭〉' }))) */}
         {!editLevel && window.GLOB.systemType !== 'production' && this.props.memberLevel >= 20 ?
           <span className="home-edit" onClick={() => {window.open('#/menudesign/JTdCJTIyTWVudVR5cGUlMjIlM0ElMjJob21lJTIyJTJDJTIyTWVudUlkJTIyJTNBJTIyaG9tZV9wYWdlX2lkJTIyJTJDJTIyTWVudU5hbWUlMjIlM0ElMjIlRTklQTYlOTYlRTklQTElQjUlMjIlN0Q=')}}>
@@ -379,4 +382,4 @@
   }
 }
 
-export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Form.create()(Header)))
\ No newline at end of file
+export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Header))
\ No newline at end of file
diff --git a/src/views/design/header/index.scss b/src/views/design/header/index.scss
index 705e4d5..4f796e4 100644
--- a/src/views/design/header/index.scss
+++ b/src/views/design/header/index.scss
@@ -130,6 +130,13 @@
     color: #1890ff;
     cursor: pointer;
   }
+  .interface {
+    position: absolute;
+    top: 170px;
+    right: 50px;
+    color: #1890ff;
+    cursor: pointer;
+  }
   .home-edit {
     position: absolute;
     top: 100px;
diff --git a/src/views/design/index.jsx b/src/views/design/index.jsx
index 167b576..51fe335 100644
--- a/src/views/design/index.jsx
+++ b/src/views/design/index.jsx
@@ -5,6 +5,7 @@
 
 import asyncComponent from '@/utils/asyncComponent'
 import Header from './header'
+import { setGLOBFuncs } from '@/utils/utils.js'
 import Sidemenu from './sidemenu'
 
 import './index.scss'
@@ -13,6 +14,10 @@
 const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
 
 class Design extends Component {
+  componentDidMount() {
+    setGLOBFuncs()
+  }
+  
   render () {
     return (
       <div className="mk-main-view">
diff --git a/src/views/design/sidemenu/config.jsx b/src/views/design/sidemenu/config.jsx
index 1ec2bae..9cca512 100644
--- a/src/views/design/sidemenu/config.jsx
+++ b/src/views/design/sidemenu/config.jsx
@@ -170,20 +170,20 @@
     MenuID: '1589788042787ffdt9hle4s45k9r1nvs',
     MenuNo: 'bd_msn_email_tempM',
     MenuName: '閭欢妯℃澘',
-  }, {
-    src: '',
-    PageParam: {OpenType: 'newtab', Template: 'ManageTable'},
-    type: 'ManageTable',
-    MenuID: '15900310928174dro07ihfckghpb5h13',
-    MenuNo: 'bd_msn_sms_tempM',
-    MenuName: '澶т簬鐭俊妯℃澘',
   // }, {
   //   src: '',
   //   PageParam: {OpenType: 'newtab', Template: 'ManageTable'},
   //   type: 'ManageTable',
-  //   MenuID: '1599613340050c8nu6rbst9d4emnnbsq',
-  //   MenuNo: 's_sms_qxM',
-  //   MenuName: '濂囦簯鐭俊妯℃澘',
+  //   MenuID: '15900310928174dro07ihfckghpb5h13',
+  //   MenuNo: 'bd_msn_sms_tempM',
+  //   MenuName: '澶т簬鐭俊妯℃澘',
+  }, {
+    src: '',
+    PageParam: {OpenType: 'newtab', Template: 'ManageTable'},
+    type: 'ManageTable',
+    MenuID: '1599613340050c8nu6rbst9d4emnnbsq',
+    MenuNo: 's_sms_qxM',
+    MenuName: '濂囦簯鐭俊妯℃澘',
   }]
 }, {
   MenuID: 'systemPayManage',
diff --git a/src/views/interface/api/index.js b/src/views/interface/api/index.js
new file mode 100644
index 0000000..59f4941
--- /dev/null
+++ b/src/views/interface/api/index.js
@@ -0,0 +1,175 @@
+import axios from 'axios'
+import md5 from 'md5'
+import jsSHA from 'jssha'
+import { notification } from 'antd'
+
+window.GLOB.WebSql = null
+
+if (window.openDatabase) {
+  let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
+  try {
+    window.GLOB.WebSql = openDatabase(`mkdb${service}`, '1', 'mk-pc-database', 50 * 1024 * 1024)
+    window.GLOB.WebSql.transaction(tx => {
+      tx.executeSql('CREATE TABLE IF NOT EXISTS INTERFACES (uuid varchar(50), createDate varchar(50), method varchar(50), interface text, params text, headers text, active varchar(50), raw text, formData text, CDefine1 varchar(50), CDefine2 varchar(50), CDefine3 varchar(50), CDefine4 varchar(50), CDefine5 text)', [], () => {
+
+      }, () => {
+        // eslint-disable-next-line
+        throw 'CREATE TABLE ERROR'
+      })
+    })
+  } catch (e) {
+    console.warn('WebSql 鍒濆鍖栧け璐ワ紒')
+    window.GLOB.WebSql = null
+  }
+}
+
+axios.defaults.crossDomain = true
+axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'
+axios.defaults.withCredentials = false
+
+axios.interceptors.request.use((config) => {
+  return config
+}, (error) => {
+  return Promise.reject(error)
+})
+
+axios.interceptors.response.use((response) => {
+  return Promise.resolve(response)
+}, (error) => {
+  return Promise.reject(error)
+})
+
+class Api {
+  /**
+   * @description 鐧诲綍绯荤粺, 鑾峰彇鐢ㄦ埛淇℃伅
+   */
+  dologon (url, method, header, n) {
+    let config = {
+      url,
+      method
+    }
+
+    if (header) {
+      config.headers = header
+    }
+
+    if (n) {
+      let _param = JSON.parse(n)
+      let param = {}
+
+      Object.keys(_param).forEach(key => {
+        param[key.toLowerCase()] = _param[key]
+      })
+
+      if (param.type && param.username && param.password && param.timestamp) {
+        if (param.type === 'S') {
+          let shaObj = new jsSHA('SHA-1', 'TEXT')
+          shaObj.update(param.password)
+          param.password = shaObj.getHash('HEX').toUpperCase()
+          param.password = md5(param.username + param.password + param.timestamp)
+        } else if (/^mk_/ig.test(param.type)) {
+          let shaObj = new jsSHA('SHA-1', 'TEXT')
+          shaObj.update(param.password)
+          param.password = shaObj.getHash('HEX').toUpperCase()
+          param.password = md5(param.privatekey + param.username + param.password + param.timestamp)
+
+          delete param.privatekey
+        }
+      }
+
+      config.data = JSON.stringify(param)
+    }
+
+    return axios(config)
+  }
+
+  /**
+   * @description 閫氱敤璇锋眰
+   */
+  normalRequest (url, method, header, n) {
+    let config = {
+      url,
+      method
+    }
+
+    if (header) {
+      config.headers = header
+    }
+    if (n) {
+      config.data = n
+    }
+
+    return axios(config)
+  }
+
+  writeInWebSql (data) {
+    if (!window.GLOB.WebSql) {
+      notification.warning({ top: 92, message: 'WebSql寮�鍚け璐ワ紒', duration: 5 })
+      return
+    }
+    return new Promise((resolve, reject) => {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql(`INSERT INTO INTERFACES (uuid, createDate, method, interface, params, headers, active, raw, formData) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, data, (tx, results) => {
+          resolve(results)
+        }, () => {
+          resolve()
+        })
+      })
+    })
+  }
+
+  getInterfaces () {
+    if (!window.GLOB.WebSql) {
+      notification.warning({ top: 92, message: 'WebSql寮�鍚け璐ワ紒', duration: 5 })
+      return
+    }
+    return new Promise((resolve, reject) => {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql(`SELECT * FROM INTERFACES`, [], (tx, results) => {
+          // let paramItem = results.rows[0]
+          resolve(results)
+        }, () => {
+          window.GLOB.WebSql = null
+          reject()
+        })
+      })
+    })
+  }
+
+  delInterface (uuid) {
+    if (!window.GLOB.WebSql) {
+      notification.warning({ top: 92, message: 'WebSql寮�鍚け璐ワ紒', duration: 5 })
+      return
+    }
+    return new Promise((resolve, reject) => {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql(`DELETE FROM INTERFACES where uuid = '${uuid}'`, [], (tx, results) => {
+          resolve(results)
+        }, () => {
+          resolve()
+        })
+      })
+    })
+  }
+
+  /**
+   * @description 娓呯┖鎺ュ彛璋冪敤璁板綍
+   */
+  clearInterfaces () {
+    if (!window.GLOB.WebSql) {
+      notification.warning({ top: 92, message: 'WebSql寮�鍚け璐ワ紒', duration: 5 })
+      return
+    }
+    return new Promise((resolve, reject) => {
+      window.GLOB.WebSql.transaction(tx => {
+        tx.executeSql(`DELETE FROM INTERFACES`, [], (tx, results) => {
+          resolve(results)
+        }, () => {
+          resolve()
+        })
+      })
+    })
+  }
+}
+
+export default new Api()
\ No newline at end of file
diff --git a/src/views/interface/header/index.jsx b/src/views/interface/header/index.jsx
new file mode 100644
index 0000000..03804df
--- /dev/null
+++ b/src/views/interface/header/index.jsx
@@ -0,0 +1,45 @@
+import React, {Component} from 'react'
+import { withRouter } from 'react-router-dom'
+
+import Utils from '@/utils/utils.js'
+import options from '@/store/options.js'
+import avatar from '@/assets/img/avatar.jpg'
+import MainLogo from '@/assets/img/main-logo.png'
+import './index.scss'
+
+class Header extends Component {
+  state = {
+    userName: sessionStorage.getItem('CloudUserName'),
+    avatar: Utils.getrealurl(sessionStorage.getItem('CloudAvatar')),
+  }
+
+  UNSAFE_componentWillMount() {
+    if (options.sysType !== 'local' || !sessionStorage.getItem('LoginUID')) {
+      sessionStorage.clear()
+      this.props.history.replace('/login')
+    }
+  }
+
+  close = () => {
+    window.close()
+  }
+
+  render () {
+
+    return (
+      <header className="interface-header-container">
+        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="title">鎺ュ彛璋冭瘯</div>
+        <div className="header-setting">
+          <span className="close" onClick={this.close}>鍏抽棴</span>
+          <img src={this.state.avatar || avatar} alt=""/>
+          <span>
+            <span className="username">{this.state.userName}</span>
+          </span>
+        </div>
+      </header>
+    )
+  }
+}
+
+export default withRouter(Header)
\ No newline at end of file
diff --git a/src/views/interface/header/index.scss b/src/views/interface/header/index.scss
new file mode 100644
index 0000000..36f8765
--- /dev/null
+++ b/src/views/interface/header/index.scss
@@ -0,0 +1,63 @@
+.interface-header-container {
+  position: fixed;
+  z-index: 20;
+  left: 0;
+  top: 0;
+  font-weight: bold!important;
+  width: 100%;
+  height: 48px;
+  background: #000;
+
+  .header-logo {
+    float: left;
+    width: 180px;
+    line-height: 48px;
+    text-align: center;
+    padding-left: 5px;
+    box-sizing: border-box;
+    opacity: 1;
+    img {
+      max-width: 100%;
+      max-height: 40px;
+    }
+  }
+
+  .title {
+    position: absolute;
+    top: 10px;
+    left: 50%;
+    transform: translateX(-50%);
+    color: #ffffff;
+    font-size: 18px;
+  }
+
+  .header-setting {
+    float: right;
+    line-height: 48px;
+    margin-right: 10px;
+    .close {
+      margin-right: 20px;
+      cursor: pointer;
+      padding: 10px;
+    }
+    img {
+      width: 29px;
+      height: 29px;
+      border-radius: 30px;
+      margin-right: 7px;
+    }
+    span {
+      color: #ffffff;
+      font-size: 0.95rem;
+      .username {
+        display: inline-block;
+        height: 30px;
+        max-width: 95px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+  }
+}
+
diff --git a/src/views/interface/history/index.jsx b/src/views/interface/history/index.jsx
new file mode 100644
index 0000000..9b0952c
--- /dev/null
+++ b/src/views/interface/history/index.jsx
@@ -0,0 +1,290 @@
+import React, {Component} from 'react'
+import { fromJS } from 'immutable'
+import { Input, Modal, Icon } from 'antd'
+import moment from 'moment'
+
+import Api from '@/views/interface/api'
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const { Search } = Input
+const { confirm } = Modal
+
+class History extends Component {
+  state = {
+    list: [],
+    historys: [],
+    searchKey: ''
+  }
+
+  componentDidMount() {
+    MKEmitter.addListener('insertInterface', this.insertInterface)
+    setTimeout(() => {
+      Api.getInterfaces().then(res => {
+        if (!res || !res.rows) return
+
+        let rows = [...res.rows]
+        rows.sort((a,b) => {
+          return a.createDate < b.createDate ? 1 : -1
+        })
+
+        let list = []
+        let item = null
+        
+        rows.forEach(m => {
+          let date = m.createDate.substring(0, 10)
+
+          if (m.params) {
+            try {
+              m.params = JSON.parse(m.params)
+            } catch {
+              m.params = []
+            }
+          } else {
+            m.params = []
+          }
+
+          if (m.headers) {
+            try {
+              m.headers = JSON.parse(m.headers)
+            } catch {
+              m.headers = []
+            }
+          } else {
+            m.headers = []
+          }
+          
+          if (m.formData) {
+            try {
+              m.formData = JSON.parse(m.formData)
+            } catch {
+              m.formData = []
+            }
+          } else {
+            m.formData = []
+          }
+
+          if (item && item.date !== date) {
+            list.push(item)
+            item = null
+          }
+
+          if (!item) {
+            item = {date, sublist: []}
+            item.sublist.push(m)
+          } else if (item && item.date === date) {
+            item.sublist.push(m)
+          }
+        })
+
+        if (item) {
+          list.push(item)
+        }
+
+        this.setState({list, historys: fromJS(list).toJS()})
+      })
+    }, 200)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('insertInterface', this.insertInterface)
+  }
+
+  clear = () => {
+    const _this = this
+    confirm({
+      content: 'Are you sure you want to clear all your history requests?',
+      onOk() {
+        Api.clearInterfaces().then(res => {
+          if (res && res.rows.length === 0) {
+            _this.setState({list: [], historys: []})
+            Modal.success({
+              title: '娓呴櫎鎴愬姛銆�'
+            })
+          } else {
+            Modal.error({
+              title: '娓呴櫎澶辫触锛佽鍒锋柊閲嶈瘯銆�'
+            })
+          }
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  delete = (m) => {
+    const { searchKey } = this.state
+    Api.delInterface(m.uuid).then(res => {
+      if (res) {
+        let list = this.state.list.filter(item => {
+          item.sublist = item.sublist.filter(cell => cell.uuid !== m.uuid)
+  
+          return item.sublist.length > 0
+        })
+
+        let historys = fromJS(list).toJS()
+        if (searchKey) {
+          historys = historys.filter(item => {
+            item.sublist = item.sublist.filter(cell => cell.interface.indexOf(searchKey) > -1)
+    
+            return item.sublist.length > 0
+          })
+        }
+
+        this.setState({list, historys})
+      } else {
+        Modal.error({
+          title: '鍒犻櫎澶辫触锛佽鍒锋柊閲嶈瘯銆�'
+        })
+      }
+    })
+  }
+
+  insertInterface = (item) => {
+    item.uuid = Utils.getuuid()
+    item.createDate = moment().format('YYYY-MM-DD HH:mm:ss')
+
+    Api.writeInWebSql([item.uuid, item.createDate, item.method, item.interface, JSON.stringify(item.params), JSON.stringify(item.headers), item.active, item.raw, JSON.stringify(item.formData)]).then(res => {
+      if (res) {
+        let list = fromJS(this.state.list).toJS()
+
+        if (list[0]) {
+          if (list[0].date === item.createDate.substring(0, 10)) {
+            list[0].sublist.unshift(item)
+          } else {
+            list.unshift({
+              date: item.createDate.substring(0, 10),
+              sublist: [item]
+            })
+          }
+        } else {
+          list.push({
+            date: item.createDate.substring(0, 10),
+            sublist: [item]
+          })
+        }
+
+        let historys = fromJS(list).toJS()
+        if (this.state.searchKey) {
+          historys = historys.filter(item => {
+            item.sublist = item.sublist.filter(cell => cell.interface.indexOf(this.state.searchKey) > -1)
+    
+            return item.sublist.length > 0
+          })
+        }
+
+        this.setState({ list, historys })
+      } else {
+        Modal.error({
+          title: '娣诲姞澶辫触锛佽鍒锋柊閲嶈瘯銆�'
+        })
+      }
+    })
+  }
+
+  use = (m) => {
+    MKEmitter.emit('useInterface', fromJS(m).toJS())
+  }
+
+  uselogon = () => {
+    let m = {
+      active: 'raw',
+      createDate: '',
+      formData: [],
+      headers: [],
+      interface: 'dologon / logon',
+      method: 'POST',
+      params: [],
+      raw: "{\n \"UserName\":\"******\",\n \"Password\":\"******\",\n \"systemType\":\"local\",\n \"Type\":\"鍏挜\",\n \"privatekey\":\"绉侀挜\",\n \"timestamp\":\"YYYY-MM-DD HH:mm:ss\",\n \"appkey\":\"******\"\n}",
+      uuid: 'dologon'
+    }
+    MKEmitter.emit('useInterface', m)
+  }
+
+  usedostars = () => {
+    let m = {
+      active: 'raw',
+      createDate: '',
+      formData: [],
+      headers: [],
+      interface: 'dostars',
+      method: 'POST',
+      params: [],
+      raw: "{\n \"LoginUID\":\"******\",\n \"UserID\":\"******\",\n \"func\":\"******\"\n}",
+      uuid: 'dologon'
+    }
+    MKEmitter.emit('useInterface', m)
+  }
+
+  changeSearch = (value) => {
+    const { list } = this.state
+
+    let historys = fromJS(list).toJS()
+    if (value) {
+      historys = historys.filter(item => {
+        item.sublist = item.sublist.filter(cell => cell.interface.indexOf(value) > -1)
+
+        return item.sublist.length > 0
+      })
+    }
+
+    this.setState({searchKey: value, historys})
+  }
+
+  render () {
+    const { historys } = this.state
+
+    return (
+      <aside className="interface-side-menu">
+        <Search placeholder="Filter" onSearch={value => this.changeSearch(value)}/>
+        <div className="title">
+          History
+          <span onClick={this.clear}>Clear all</span>
+        </div>
+        <div className="list-view">
+          {historys.map((item, index) => (
+            <div className="list-line" key={index}>
+              <div className="line-title">{item.date}</div>
+              {item.sublist.map(m => (
+                <div className="line-item" key={m.uuid}>
+                  <div className="method">POST</div>
+                  <div className="inter">{m.interface}</div>
+                  <div className="action">
+                    <Icon type="delete" onClick={() => this.delete(m)} />
+                    <Icon type="right" onClick={() => this.use(m)} />
+                  </div>
+                </div>
+              ))}
+            </div>
+          ))}
+          <div className="list-line" key="example">
+            <div className="line-title">绀轰緥</div>
+              <div className="line-item" key="dologon">
+                <div className="method">POST</div>
+                <div className="inter" style={{lineHeight: '40px'}}>dologon / logon</div>
+                <div className="action" style={{paddingLeft: '40px'}}>
+                  <Icon type="right" onClick={this.uselogon} />
+                </div>
+              </div>
+              <div className="line-item" key="dostars">
+                <div className="method">POST</div>
+                <div className="inter" style={{lineHeight: '40px'}}>dostars</div>
+                <div className="action" style={{paddingLeft: '40px'}}>
+                  <Icon type="right" onClick={this.usedostars} />
+                </div>
+              </div>
+          </div>
+        </div>
+      </aside>
+    )
+  }
+}
+
+export default History
\ No newline at end of file
diff --git a/src/views/interface/history/index.scss b/src/views/interface/history/index.scss
new file mode 100644
index 0000000..012eebb
--- /dev/null
+++ b/src/views/interface/history/index.scss
@@ -0,0 +1,113 @@
+.interface-side-menu {
+  display: inline-block;
+  width: 300px;
+  border-right: 2px solid #e8e8e8;
+  height: 100%;
+
+  .ant-input-search {
+    margin: 10px 20px;
+    width: calc(100% - 40px);
+    .ant-input {
+      border-radius: 20px;
+    }
+  }
+  .title {
+    padding-left: 20px;
+    font-size: 16px;
+    border-bottom: 1px solid #e8e8e8;
+    padding-bottom: 3px;
+    span {
+      font-size: 14px;
+      float: right;
+      color: #fa541c;
+      margin-right: 10px;
+      cursor: pointer;
+    }
+  }
+  .list-view {
+    .ant-empty {
+      margin-top: 50px;
+    }
+    .list-line {
+      border-bottom: 1px solid #e8e8e8;
+      .line-title {
+        padding: 5px 15px;
+        color: rgba(0, 0, 0, 0.85);
+      }
+      .line-item {
+        position: relative;
+        display: flex;
+        padding-left: 25px;
+        margin-bottom: 8px;
+        transition: all 0.3s;
+        .method {
+          width: 42px;
+          color: #faad14;
+          font-size: 12px;
+          font-weight: 600;
+          line-height: 40px;
+        }
+        .inter {
+          width: 225px;
+          height: 42px;
+          word-break: break-all;
+          text-overflow: ellipsis;
+          display: -webkit-box;
+          -webkit-box-orient: vertical;
+          -webkit-line-clamp: 2;
+          overflow: hidden;
+        }
+        .action {
+          width: 70px;
+          position: absolute;
+          line-height: 40px;
+          right: 0px;
+          height: 42px;
+          background: #ffffff;
+          padding-left: 15px;
+          opacity: 0;
+          transition: all 0.3s;
+          i {
+            cursor: pointer;
+          }
+          i:first-child {
+            margin-right: 12px;
+          }
+          .anticon-delete {
+            color: #fa541c;
+          }
+          .anticon-right {
+            color: #1890ff;
+          }
+        }
+      }
+      .line-item:hover {
+        background: #e9e9e9;
+        .action {
+          opacity: 1;
+          background: #e9e9e9;
+        }
+      }
+    }
+  }
+
+  .list-view {
+    height: calc(100vh - 128px);
+    overflow-x: hidden;
+    overflow-y: auto;
+  }
+  .list-view::-webkit-scrollbar {
+    width: 5px;
+  }
+  .list-view::-webkit-scrollbar-thumb {
+    border-radius: 5px;
+    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09);
+    background: rgba(0, 0, 0, 0.09);
+  }
+  .list-view::-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);
+  }
+}
\ No newline at end of file
diff --git a/src/views/interface/index.jsx b/src/views/interface/index.jsx
new file mode 100644
index 0000000..573e87c
--- /dev/null
+++ b/src/views/interface/index.jsx
@@ -0,0 +1,28 @@
+import React, {Component} from 'react'
+import { ConfigProvider } from 'antd'
+import enUS from 'antd/es/locale/en_US'
+import zhCN from 'antd/es/locale/zh_CN'
+
+import Header from './header'
+import History from './history'
+import WorkSpace from './workspace'
+
+import './index.scss'
+
+const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+
+class Interface extends Component {
+  render () {
+    return (
+      <div className="interface-view">
+        <ConfigProvider locale={_locale}>
+          <Header key="header"/>
+          <History key="history"/>
+          <WorkSpace key="workspace"/>
+        </ConfigProvider>
+      </div>
+    )
+  }
+}
+
+export default Interface
\ No newline at end of file
diff --git a/src/views/interface/index.scss b/src/views/interface/index.scss
new file mode 100644
index 0000000..6c53933
--- /dev/null
+++ b/src/views/interface/index.scss
@@ -0,0 +1,6 @@
+.interface-view {
+  padding-top: 48px;
+  width: 100vw;
+  height: 100vh;
+  overflow: hidden;
+}
\ No newline at end of file
diff --git a/src/views/interface/workspace/editTable/index.jsx b/src/views/interface/workspace/editTable/index.jsx
new file mode 100644
index 0000000..dc5ff0f
--- /dev/null
+++ b/src/views/interface/workspace/editTable/index.jsx
@@ -0,0 +1,249 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { Table, Input, Form, Icon } from 'antd'
+import Utils from '@/utils/utils.js'
+import './index.scss'
+
+const EditableContext = React.createContext()
+
+const EditableRow = ({ form, index, ...props }) => (
+  <EditableContext.Provider value={form}>
+    <tr {...props} />
+  </EditableContext.Provider>
+)
+
+const EditableFormRow = Form.create()(EditableRow)
+
+class EditableCell extends Component {
+  state = {
+    editing: false
+  }
+
+  toggleEdit = () => {
+    const { dataIndex } = this.props
+
+    if (!dataIndex) return
+
+    const editing = !this.state.editing
+    this.setState({ editing }, () => {
+      if (editing && this.input && this.input.select) {
+        this.input.select()
+      } else if (editing && this.input && this.input.focus) {
+        this.input.focus()
+      }
+    })
+  }
+
+  save = e => {
+    const { record, handleSave } = this.props
+    this.form.validateFields((error, values) => {
+      handleSave({ ...record, ...values })
+      if (error && error[e.currentTarget.id]) {
+        return
+      }
+      this.toggleEdit()
+    })
+  }
+
+  renderCell = form => {
+    this.form = form
+    const { children, dataIndex, record } = this.props
+    const { editing } = this.state
+
+    return editing ? (
+      <Form.Item style={{ margin: 0 }}>
+        {form.getFieldDecorator(dataIndex, {
+          initialValue: record[dataIndex]
+        })(<Input ref={node => (this.input = node)} autoComplete="off" onPressEnter={this.save} onBlur={this.save} />)}
+      </Form.Item>
+    ) : (
+      <div
+        className="editable-cell-value-wrap"
+        onClick={this.toggleEdit}
+      >
+        {children}
+      </div>
+    )
+  }
+
+  render() {
+    const { dataIndex, title, record, index, handleSave, children, ...restProps } = this.props
+    return (
+      <td {...restProps}>
+        <EditableContext.Consumer style={{padding: 0}}>{this.renderCell}</EditableContext.Consumer>
+      </td>
+    )
+  }
+}
+
+class EditTable extends Component {
+  static propTpyes = {
+    data: PropTypes.array,
+    onChange: PropTypes.func
+  }
+
+  state = {
+    dataSource: [],
+    selectedRowKeys: [],
+    count: 0,
+    columns: [{
+      dataIndex: 'key',
+      title: 'KEY',
+      width: '33%'
+    }, {
+      dataIndex: 'value',
+      title: 'VALUE',
+      width: '33%'
+    }, {
+      dataIndex: 'description',
+      title: 'DESCRIPTION',
+      className: 'no-border',
+      width: '33%'
+    }, {
+      dataIndex: '',
+      title: '',
+      width: '20px',
+      render: (text, record) => {
+        return (<Icon type="close" onClick={() => this.delete(record)}/>)
+      }
+    }]
+  }
+
+  UNSAFE_componentWillMount () {
+    const { data } = this.props
+    
+    let _data = data || []
+    let selectedRowKeys = []
+    if (_data && _data.length > 0) {
+      _data.forEach(item => {
+        if (item.selected) {
+          selectedRowKeys.push(item.uuid)
+        }
+      })
+    } else {
+      _data = [{
+        uuid: Utils.getuuid(),
+        key: '',
+        value: '',
+        description: '',
+        selected: true
+      }]
+      selectedRowKeys.push(_data[0].uuid)
+      this.props.onChange(_data)
+    }
+
+    this.setState({
+      dataSource: _data,
+      selectedRowKeys
+    })
+  }
+
+  handleDelete = key => {
+    const { dataSource } = this.state
+    let _data = dataSource.filter(item => item.key !== key)
+
+    this.setState({ dataSource: _data }, () => {
+      this.props.onChange(_data)
+    })
+  }
+
+  delete = (item) => {
+    const { dataSource, selectedRowKeys } = this.state
+
+    let _data = dataSource.filter(cell => cell.uuid !== item.uuid)
+    let _keys = selectedRowKeys.filter(key => key !== item.uuid)
+
+    if (_data.length === 0) {
+      _data = [{
+        uuid: Utils.getuuid(),
+        key: '',
+        value: '',
+        description: '',
+        selected: true
+      }]
+      _keys = [_data[0].uuid]
+      this.props.onChange(_data)
+    }
+
+    this.setState({
+      dataSource: _data,
+      selectedRowKeys: _keys
+    }, () => {
+      this.props.onChange(_data)
+    })
+  }
+
+  handleSave = row => {
+    let newData = this.state.dataSource.map(item => {
+      if (row.uuid === item.uuid) return row
+      return item
+    })
+
+    let selectedRowKeys = this.state.selectedRowKeys
+
+    let last = newData[newData.length - 1]
+    if (last.key || last.value || last.description) {
+      const item = {
+        uuid: Utils.getuuid(),
+        key: '',
+        value: '',
+        description: '',
+        selected: true
+      }
+  
+      newData = [...newData, item]
+      selectedRowKeys = [...selectedRowKeys, item.uuid]
+    }
+
+    this.setState({ dataSource: newData, selectedRowKeys }, () => {
+      this.props.onChange(newData)
+    })
+  }
+
+  onChange = selectedRowKeys => {
+    const newData = this.state.dataSource.map(item => {
+      item.selected = selectedRowKeys.includes(item.uuid)
+      return item
+    })
+
+    this.setState({ dataSource: newData, selectedRowKeys }, () => {
+      this.props.onChange(newData)
+    })
+  }
+
+  render() {
+    const { dataSource, selectedRowKeys } = this.state
+    const components = {
+      body: {
+        row: EditableFormRow,
+        cell: EditableCell
+      }
+    }
+    const columns = this.state.columns.map(col => {
+      return {
+        ...col,
+        onCell: record => ({
+          record,
+          dataIndex: col.dataIndex,
+          title: col.title,
+          handleSave: this.handleSave,
+        })
+      }
+    })
+    return (
+      <div className="params-edit-table">
+        <Table
+          rowKey="uuid"
+          components={components}
+          bordered
+          dataSource={dataSource}
+          columns={columns}
+          rowSelection={{ type: 'checkbox', selectedRowKeys, onChange: this.onChange }}
+          pagination={false}
+        />
+      </div>
+    )
+  }
+}
+
+export default EditTable
\ No newline at end of file
diff --git a/src/views/interface/workspace/editTable/index.scss b/src/views/interface/workspace/editTable/index.scss
new file mode 100644
index 0000000..10cd1a4
--- /dev/null
+++ b/src/views/interface/workspace/editTable/index.scss
@@ -0,0 +1,85 @@
+.params-edit-table {
+  .add-row {
+    position: absolute;
+    z-index: 1;
+    right: 10px;
+    top: 0px;
+    padding: 5px;
+    font-size: 22px;
+    color: #26C281;
+  }
+  .ant-table table {
+    border-radius: 0;
+  }
+  .no-border {
+    border-right: 0!important;
+  }
+  .ant-table-thead > tr {
+    > th {
+      padding: 10px 10px;
+    }
+    .ant-table-selection-column {
+      .ant-table-header-column {
+        display: none;
+      }
+    }
+  }
+  .ant-table-tbody {
+    > tr {
+      > td {
+        background: #ffffff!important;
+        padding: 2px 10px;
+        .ant-input {
+          height: 28px;
+        }
+        .ant-form-item {
+          height: 30px;
+          line-height: 30px;
+          .ant-form-item-control {
+            line-height: 30px;
+          }
+        }
+        .anticon-close {
+          opacity: 0;
+        }
+      }
+    }
+    > tr:hover {
+      > td {
+        background: #ffffff!important;
+        .anticon-close {
+          opacity: 1;
+        }
+      }
+    }
+  }
+  .editable-cell-value-wrap {
+    cursor: pointer;
+    height: 36px;
+    width: 300px;
+    display: table-cell;
+    vertical-align: middle;
+    word-wrap: break-word;
+    word-break: break-word;
+    .ant-input {
+      height: 30px;
+      padding: 0 11px;
+    }
+  }
+  .ant-form-item-control-wrapper {
+    width: 100%;
+  }
+  .ant-table-placeholder {
+    padding: 5px 16px;
+    .ant-empty-normal {
+      margin: 0;
+    }
+  }
+  .operation-btn {
+    margin-right: 10px;
+    cursor: pointer;
+  }
+  .ant-form-explain {
+    font-size: 12px;
+  }
+}
diff --git a/src/views/interface/workspace/index.jsx b/src/views/interface/workspace/index.jsx
new file mode 100644
index 0000000..f02ba5d
--- /dev/null
+++ b/src/views/interface/workspace/index.jsx
@@ -0,0 +1,123 @@
+import React, {Component} from 'react'
+import { Icon, Tabs } from 'antd'
+
+import Utils from '@/utils/utils.js'
+import MKEmitter from '@/utils/events.js'
+import Request from './request'
+import './index.scss'
+import { fromJS } from 'immutable'
+
+
+class WorkSpace extends Component {
+  state = {
+    tabviews: [{
+      uuid: Utils.getuuid(),
+      createDate: '',
+      method: 'POST',
+      interface: '',
+      params: [],
+      headers: [],
+      active: 'raw',
+      raw: '',
+      formData: []
+    }]
+  }
+
+  componentDidMount() {
+    MKEmitter.addListener('useInterface', this.useInterface)
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('useInterface', this.useInterface)
+  }
+
+  useInterface = (item) => {
+    item.uuid = Utils.getuuid()
+    
+    this.setState({tabviews: [...this.state.tabviews, item]}, () => {
+      let div = document.getElementById(item.uuid)
+      div && div.click && div.click()
+    })
+  }
+
+  handleTabview = (view) => {
+    let tabviews = fromJS(this.state.tabviews).toJS()
+    tabviews = tabviews.filter(item => item.uuid !== view.uuid)
+
+    this.setState({tabviews}, () => {
+      if (tabviews.length > 0) return
+
+      setTimeout(() => {
+        this.setState({tabviews: [{
+          uuid: Utils.getuuid(),
+          createDate: '',
+          method: 'POST',
+          interface: '',
+          params: [],
+          headers: [],
+          active: 'raw',
+          raw: '',
+          formData: []
+        }]})
+      }, 300)
+    })
+  }
+
+  handleAdd = () => {
+    let item = {
+      uuid: Utils.getuuid(),
+      createDate: '',
+      method: 'POST',
+      interface: '',
+      params: [],
+      headers: [],
+      active: 'raw',
+      raw: '',
+      formData: []
+    }
+    this.setState({tabviews: [...this.state.tabviews, item]}, () => {
+      let div = document.getElementById(item.uuid)
+      div && div.click && div.click()
+    })
+  }
+
+  render () {
+    const { tabviews } = this.state
+
+    return (
+      <div className="workspace-wrap">
+        <Icon className="add-view" type="plus" onClick={this.handleAdd} />
+        <Tabs type="card">
+          {tabviews.map(view => {
+            return (
+              <Tabs.TabPane
+                tab={
+                  <span className="control" id={view.uuid || ''}>
+                    <span className="method">
+                      {view.method || 'POST'}
+                    </span>
+                    <span className="interface">
+                      {view.interface || 'Untitled Request'}
+                    </span>
+                    <Icon type="close" onClick={() => this.handleTabview(view)}/>
+                  </span>
+                }
+                key={view.uuid}
+              >
+                <Request config={view} />
+              </Tabs.TabPane>
+            )
+          })}
+        </Tabs>
+      </div>
+    )
+  }
+}
+
+export default WorkSpace
\ No newline at end of file
diff --git a/src/views/interface/workspace/index.scss b/src/views/interface/workspace/index.scss
new file mode 100644
index 0000000..7078d44
--- /dev/null
+++ b/src/views/interface/workspace/index.scss
@@ -0,0 +1,52 @@
+.workspace-wrap {
+  display: inline-block;
+  width: calc(100vw - 300px);
+  height: 100%;
+  vertical-align: top;
+  padding-top: 10px;
+  position: relative;
+  .add-view {
+    position: absolute;
+    right: 25px;
+    top: 12px;
+    z-index: 2;
+    padding: 5px;
+    cursor: pointer;
+    font-size: 22px;
+    color: #26C281;
+  }
+
+  .ant-tabs.ant-tabs-card .ant-tabs-card-bar {
+    >.ant-tabs-nav-container {
+      margin-right: 100px;
+    }
+    padding-left: 5px;
+    .ant-tabs-tab {
+      margin-right: 7px;
+      padding: 0 10px;
+      .method {
+        color: #faad14;
+        font-size: 12px;
+        font-weight: 600;
+        margin-right: 5px;
+        vertical-align: top;
+      }
+      .interface {
+        display: inline-block;
+        color: rgba(0, 0, 0, 0.65);
+        width: 200px;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+        vertical-align: top;
+      }
+      .anticon-close {
+        color:rgba(0, 0, 0, 0.65);
+        margin: 0;
+      }
+    }
+    .ant-tabs-tab.ant-tabs-tab-active {
+      border-top-color: #fa541c;
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/views/interface/workspace/request/index.jsx b/src/views/interface/workspace/request/index.jsx
new file mode 100644
index 0000000..90672df
--- /dev/null
+++ b/src/views/interface/workspace/request/index.jsx
@@ -0,0 +1,310 @@
+import React, {Component} from 'react'
+import { fromJS } from 'immutable'
+import md5 from 'md5'
+import { Input, Select, Button, Tabs, Radio, Modal, Spin } from 'antd'
+
+import Api from '@/views/interface/api'
+import Utils from '@/utils/utils.js'
+import EditTable from '../editTable'
+import CodeMirror from '@/templates/zshare/codemirror'
+import MKEmitter from '@/utils/events.js'
+import './index.scss'
+
+const InputGroup = Input.Group
+const { Option } = Select
+
+class Request extends Component {
+  state = {
+    active: 'raw',
+    body: null,
+    response: null,
+    status: '',
+    loading: false
+  }
+
+  UNSAFE_componentWillMount() {
+    const { config } = this.props
+
+    this.setState({active: config.active, config: fromJS(config).toJS()})
+  }
+
+  componentDidMount() {
+
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  onChange = (e) => {
+    const { config } = this.state
+
+    this.setState({active: e.target.value, config: {...config, active: e.target.value}})
+  }
+
+  rawChange = (val) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, raw: val}})
+  }
+
+  changeFormData = (vals) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, formData: vals}})
+  }
+
+  changeHeader = (vals) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, headers: vals}})
+  }
+
+  changeParams = (vals) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, params: vals}})
+  }
+
+  changeMethod = (val) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, method: val}})
+  }
+
+  changeInter = (e) => {
+    const { config } = this.state
+
+    this.setState({config: {...config, interface: e.target.value}})
+  }
+
+  send = () => {
+    const { config } = this.state
+
+    let raws = null
+    if (!config.interface) {
+      Modal.error({
+        title: '璇峰~鍏ユ帴鍙e湴鍧�锛�'
+      })
+      return
+    } else if (config.active === 'raw') {
+      if (config.raw) {
+        try {
+          raws = JSON.parse(config.raw)
+        } catch {
+          Modal.error({
+            title: '鍙傛暟鏍煎紡閿欒锛屽繀椤讳负JSON鏍煎紡锛�'
+          })
+          return
+        }
+      }
+    }
+
+    let url = config.interface
+
+    let m = []
+    config.params.forEach(item => {
+      if (!item.selected || !item.key) return
+      m.push(`${item.key}=${item.value}`)
+    })
+
+    m = m.join('&')
+
+    if (m) {
+      if (/\?/ig.test(url)) {
+        url = url + '&' + m
+      } else {
+        url = url + '?' + m
+      }
+    }
+
+    let header = null
+    config.headers.forEach(item => {
+      if (!item.selected || !item.key) return
+
+      header = header || {}
+
+      header[item.key] = item.value
+    })
+
+    let n = null
+    if (config.active === 'raw' && raws) {
+      n = JSON.stringify(raws)
+    } else if (config.active === 'formData') {
+      config.formData.forEach(item => {
+        if (!item.selected || !item.key) return
+  
+        n = n || {}
+  
+        n[item.key] = item.value
+      })
+      n = JSON.stringify(n)
+    }
+
+    this.setState({loading: true})
+
+    if (/logon/ig.test(url)) {
+      Api.dologon(url, config.method, header, n).then(res => {
+        this.handleResponse(res)
+      }, (err) => {
+        this.handleResponse(err)
+      })
+    } else if (/dostars/ig.test(url)) {
+      if (n) {
+        n = JSON.parse(n)
+        n = this.encryptParam(n)
+        n = JSON.stringify(n)
+      }
+      Api.normalRequest(url, config.method, header, n).then(res => {
+        this.handleResponse(res)
+      }, (err) => {
+        this.handleResponse(err)
+      })
+    } else {
+      Api.normalRequest(url, config.method, header, n).then(res => {
+        this.handleResponse(res)
+      }, (err) => {
+        this.handleResponse(err)
+      })
+    }
+  }
+
+  handleResponse = (res) => {
+    let body = null
+
+    if (res && res.data) {
+      try {
+        body = JSON.stringify(res.data, null, 2)
+
+        body = body.replace(/\n/ig, '<br/>')
+        body = body.replace(/\s/ig, '&nbsp;')
+      } catch {
+        body = null
+      }
+    }
+
+    let status = ''
+    if (res.status) {
+      status = res.status + res.statusText
+    } else if (res.name === 'Error') {
+      status = res.message
+      body = `璇锋眰寮傚父${status === 'Network Error' ? '锛屽彲鑳藉師鍥狅細1銆佺綉缁滃紓甯革紱2銆佹帴鍙h法鍩熴��' : '锛�'}`
+    }
+
+    this.setState({response: res, body, status, loading: false})
+  }
+
+  encryptParam (param) {
+    param.nonc = Utils.getuuid()
+      
+    let keys = Object.keys(param).sort()
+    let values = ''
+    keys.forEach(key => {
+      if (key.toLowerCase() === 'rduri') return
+      if (key.toLowerCase() === 't' || key.toLowerCase() === 'sign' || param[key] === undefined) {
+        delete param[key]
+        return
+      }
+
+      if (typeof(param[key]) === 'object') {
+        values += key + JSON.stringify(param[key])
+      } else {
+        if (param[key] && /: =$/.test(param[key])) {
+          param[key] = param[key].replace(/: =$/, '==')
+        }
+        values += key + param[key]
+      }
+    })
+    param.sign = md5(values)
+    param.t = new Date().getTime()
+
+    return param
+  }
+
+  save = () => {
+    const { config } = this.state
+
+    if (!config.interface) {
+      Modal.error({
+        title: '璇峰~鍏ユ帴鍙e湴鍧�锛�'
+      })
+      return
+    }
+
+    MKEmitter.emit('insertInterface', config)
+  }
+
+  render () {
+    const { active, config, response, body, status, loading } = this.state
+
+    let hasParam = config.params.filter(item => item.selected && item.key).length > 0
+    let hasHeader = config.headers.filter(item => item.selected && item.key).length
+    let hasBody = false
+
+    if (active === 'raw' && config.raw) {
+      hasBody = true
+    } else if (active === 'formData' && config.formData.filter(item => item.selected && item.key).length > 0) {
+      hasBody = true
+    }
+
+    return (
+      <div className="request-wrap">
+        <div className="request-interface">
+          <InputGroup compact>
+            <Select defaultValue={config.method} onChange={this.changeMethod}>
+              <Option value="POST">POST</Option>
+              <Option value="GET">GET</Option>
+            </Select>
+            <Input placeholder="Enter request URL" defaultValue={config.interface} onChange={this.changeInter}/>
+          </InputGroup>
+          <Button type="primary" onClick={this.send}>Send</Button>
+          <Button onClick={this.save}>Save</Button>
+        </div>
+        <Tabs animated={false} defaultActiveKey={hasBody ? 'Body' : 'Params'}>
+          <Tabs.TabPane forceRender={true} tab={<span className={hasParam ? 'active' : ''}>Params</span>} key="Params">
+            <EditTable data={config.params} onChange={this.changeParams}/>
+          </Tabs.TabPane>
+          <Tabs.TabPane forceRender={true} tab={<span>Headers{hasHeader ? <span className="number">{`(${hasHeader})`}</span> : ''}</span>} key="Headers">
+            <EditTable data={config.headers} onChange={this.changeHeader}/>
+          </Tabs.TabPane>
+          <Tabs.TabPane forceRender={true} tab={<span className={hasBody ? 'active' : ''}>Body</span>} key="Body">
+            <div className="body-class">
+              <Radio.Group onChange={this.onChange} value={active}>
+                <Radio value={'none'}>none</Radio>
+                <Radio value={'formData'}>formData</Radio>
+                <Radio value={'raw'}>raw</Radio>
+              </Radio.Group>
+            </div>
+            <div className={'body-content ' + (active === 'none' ? 'show' : '')}>
+              <div className="no-body">This request does not have a body</div>
+            </div>
+            <div className={'body-content ' + (active === 'formData' ? 'show' : '')}>
+              <EditTable data={config.formData} onChange={this.changeFormData}/>
+            </div>
+            <div className={'body-content ' + (active === 'raw' ? 'show' : '')}>
+              <CodeMirror value={config.raw} mode="text/javascript" onChange={this.rawChange} />
+            </div>
+          </Tabs.TabPane>
+        </Tabs>
+        <div className="response">
+          {response ? <div className="header">
+            {body ? 'Body' : 'Response'}
+            {status ? <span className="status">Status: <span className={status === '200OK' ? 'green' : 'yellow'}>{status}</span></span> : null}
+          </div> : <div className="header">
+            Response
+            <span className="empty">Hit the Send button to get a response.</span>
+          </div>}
+          <div style={{paddingLeft: '3px', paddingTop: '3px'}} dangerouslySetInnerHTML={{__html: body}}></div>
+          {loading ? <div className="pending"><Spin size="large"/></div> : null}
+        </div>
+      </div>
+    )
+  }
+}
+
+export default Request
\ No newline at end of file
diff --git a/src/views/interface/workspace/request/index.scss b/src/views/interface/workspace/request/index.scss
new file mode 100644
index 0000000..7dfc719
--- /dev/null
+++ b/src/views/interface/workspace/request/index.scss
@@ -0,0 +1,162 @@
+.request-wrap {
+  position: relative;
+  padding: 0px 10px;
+  height: calc(100vh - 115px);
+  overflow-x: hidden;
+  overflow-y: auto;
+
+  .request-interface {
+    background: #ffffff;
+    margin-bottom: 10px;
+
+    .ant-input-group.ant-input-group-compact > *:not(:last-child) {
+      border-right-width: 0px;
+    }
+    .ant-select-selection {
+      height: 40px;
+      width: 90px;
+    }
+    .ant-select-selection__rendered {
+      line-height: 40px;
+    }
+    .ant-input {
+      height: 40px;
+      width: calc(100% - 100px);
+    }
+    .ant-input-group {
+      display: inline-block;
+      width: calc(100% - 210px);
+      vertical-align: top;
+    }
+    .ant-btn {
+      height: 40px;
+      width: 90px;
+    }
+    .ant-btn-primary {
+      margin-right: 10px;
+    }
+  }
+  .ant-tabs.ant-tabs-line {
+    .ant-tabs-top-bar {
+      margin-bottom: 0px;
+      border: 0;
+      .ant-tabs-nav {
+        .ant-tabs-tab {
+          color: rgba(0, 0, 0, 0.65);
+          padding-bottom: 5px;
+          span {
+            position: relative;
+          }
+          .number {
+            color: #26C281;
+            margin-left: 3px;
+            font-size: 13px;
+          }
+          span.active::after {
+            content: ' ';
+            display: block;
+            position: absolute;
+            right: -12px;
+            top: 2px;
+            width: 8px;
+            height: 8px;
+            border-radius: 8px;
+            background-color: #26C281;
+          }
+        }
+        .ant-tabs-tab.ant-tabs-tab-active {
+          color: rgba(0, 0, 0, 0.85);
+        }
+      }
+      .ant-tabs-ink-bar {
+        background-color: #fa541c;
+      }
+    }
+  }
+  .body-class {
+    height: 40px;
+    line-height: 40px;
+    padding-left: 15px;
+    border-top: 1px solid #e8e8e8;
+    .ant-radio-wrapper {
+      margin-right: 20px;
+    }
+  }
+  .body-content {
+    display: none;
+    .no-body {
+      color: rgba(0, 0, 0, 0.45);
+      border-top: 1px solid #e8e8e8;
+      border-bottom: 1px solid #e8e8e8;
+      text-align: center;
+      height: 40px;
+      line-height: 40px;
+    }
+    .CodeMirror {
+      height: 200px;
+      line-height: 1.5;
+    }
+  }
+  .body-content.show {
+    display: block;
+  }
+  .anticon-fullscreen {
+    display: none;
+  }
+  .code-mirror-wrap .code-mirror-area {
+    border-radius: 0;
+  }
+  .response {
+    position: relative;
+    min-height: 400px;
+    border-left: 1px solid #e8e8e8;
+    border-right: 1px solid #e8e8e8;
+    .header {
+      position: relative;
+      height: 40px;
+      background-color: #fafafa;
+      line-height: 40px;
+      padding-left: 10px;
+      border-bottom: 1px solid #e8e8e8;
+      .empty {
+        position: absolute;
+        top: 150px;
+        left: 50%;
+        transform: translateX(-50%);
+        font-size: 20px;
+        color:rgba(0, 0, 0, 0.45)
+      }
+      .status {
+        font-size: 13px;
+        float: right;
+        margin-right: 40px;
+        span.green {
+          color: #26C281;
+        }
+        span.yellow {
+          color: #fa541c;
+        }
+      }
+    }
+    .pending {
+      position: absolute;
+      left: 50%;
+      top: 160px;
+    }
+  }
+}
+
+.request-wrap::-webkit-scrollbar {
+  width: 5px;
+}
+.request-wrap::-webkit-scrollbar-thumb {
+  border-radius: 5px;
+  box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.09);
+  background: rgba(0, 0, 0, 0.09);
+}
+.request-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);
+}
\ No newline at end of file
diff --git a/src/views/login/index.jsx b/src/views/login/index.jsx
index 996d2b8..e7045ff 100644
--- a/src/views/login/index.jsx
+++ b/src/views/login/index.jsx
@@ -66,12 +66,6 @@
       dict: item === 'zh-CN' ? zhCN : enUS
     })
   }
-  
-  md5Password (pwd) {
-    // md5瀵嗙爜鍔犲瘑
-    const salt = 'minkesoft'
-    return md5(md5(pwd + salt))
-  }
 
   handleSubmit = () => {
     this.loginformRef.handleConfirm().then(res => {
@@ -375,7 +369,11 @@
               navBar: res.menu_type
             }
 
-            sessionStorage.setItem('home_background', res.index_background_color)
+            sessionStorage.setItem('home_background', res.index_background_color || '')
+            if (res.sys_datetime) {
+              sessionStorage.setItem('sys_datetime', res.sys_datetime)
+              sessionStorage.setItem('app_datetime', new Date().getTime())
+            }
 
             // url鏍囬
             document.title = systemMsg.platTitle
diff --git a/src/views/login/index.scss b/src/views/login/index.scss
index 031f932..236e2ad 100644
--- a/src/views/login/index.scss
+++ b/src/views/login/index.scss
@@ -26,61 +26,6 @@
     }
   }
 
-  .ant-tabs.ant-tabs-card {
-    .ant-tabs-card-bar {
-      border-bottom: 0;
-      .ant-tabs-nav-container {
-        height: 50px;
-        line-height: 50px;
-      }
-      margin-bottom: 10px;
-      .ant-tabs-nav-scroll {
-        .ant-tabs-nav {
-          display: block;
-          > div {
-            display: flex;
-            > .ant-tabs-tab {
-              height: 50px;
-              line-height: 50px;
-              flex: 1;
-            }
-          }
-        }
-      }
-      .ant-tabs-tab {
-        display: block;
-        margin-right: 0;
-        border-radius: 0;
-        text-align: center;
-        font-size: 17px;
-        white-space: nowrap;
-        text-overflow: ellipsis;
-        overflow: hidden;
-        border-top: 0;
-      }
-      .ant-tabs-tab:first-child {
-        border-left: 0;
-      }
-      .ant-tabs-tab:last-child {
-        border-right: 0;
-      }
-      .ant-tabs-tab.ant-tabs-tab-active {
-        cursor: default;
-      }
-    }
-  }
-  .login-form-1 {
-    .ant-tabs.ant-tabs-card {
-      .ant-tabs-card-bar {
-        .ant-tabs-tab {
-          font-size: 18px;
-          text-align: left!important;
-          padding-left: 1.6vw!important;
-          line-height: 60px!important;
-        }
-      }
-    }
-  }
   .login-middle {
     position: relative;
     height: calc(100vh - 194px);
@@ -102,6 +47,47 @@
       overflow: hidden;
       border: 1px solid #bfbfbf;
 
+      .login-way-wrap {
+        height: 50px;
+        line-height: 50px;
+        margin-bottom: 10px;
+        display: flex;
+        .login-way {
+          flex: 1;
+          width: 50%;
+          font-size: 17px;
+          text-align: center;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+          overflow: hidden;
+          padding: 0 16px;
+          transition: all 0.3s;
+          border: 1px solid transparent;
+          border-top: 0!important;
+        }
+        .login-way.active, .login-way:hover {
+          color: #1890ff;
+        }
+        .login-way:not(.active) {
+          cursor: pointer;
+          background: #fafafa;
+          border: 1px solid #e8e8e8;
+        }
+        .login-way:first-child {
+          border-left: 0;
+        }
+        .login-way:last-child {
+          border-right: 0;
+        }
+      }
+      .login-way-wrap.simple {
+        .login-way {
+          font-size: 18px;
+          text-align: left!important;
+          padding-left: 1.6vw!important;
+          line-height: 60px!important;
+        }
+      }
       .form-item-wrap {
         padding: 0.6vw 1.6vw 1.6vw;
       }
@@ -123,6 +109,19 @@
         margin-bottom: 3vh;
         height: 40px;
       }
+      .ant-form-item.vercode {
+        .ant-input-group {
+          border: 1px solid #d9d9d9;
+          border-radius: 4px;
+          .ant-input {
+            border: 0;
+            border-right: 1px solid #d9d9d9;
+          }
+          .ant-input-group-addon {
+            border: 0;
+          }
+        }
+      }
       .btn-login {
         margin-bottom: 3vh;
         clear: both;
diff --git a/src/views/login/loginform.jsx b/src/views/login/loginform.jsx
index 0bf62a6..9eb898c 100644
--- a/src/views/login/loginform.jsx
+++ b/src/views/login/loginform.jsx
@@ -199,30 +199,61 @@
       return
     }
 
-    let param = {
-      func: 'MSN_sms_send_code',
+    let _param = {
+      func: 'mes_sms_send_code_sso',
       send_type: 'login',
       mob: _phone,
-      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
       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') || ''
 
-    param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
-    param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
+    Api.getSystemConfig(_param).then(res => {
+      if (!res.status || !res.n_id) {
+        message.warning(res.message || '楠岃瘉鐮佽幏鍙栧け璐ワ紒')
+        return
+      }
 
-    param.userid = sessionStorage.getItem('visitorUserID') || ''
-    param.LoginUID = sessionStorage.getItem('visitorLoginUID') || ''
+      let param = {
+        func: 'MSN_sms_send_code',
+        send_type: 'login',
+        mob: _phone,
+        timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+        ID: smsId,
+        n_id: res.n_id
+      }
+  
+      param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
+      param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
 
-    this.setState({
-      verdisabled: true,
-      delay: 60
-    })
-    LoginVerCodeTimer = setTimeout(this.resetVerCodeDelay, 1000)
-
-    Api.getSystemConfig(param).then(res => {
-      if (res.status) {
-
-      } else {
+      param.rduri = 'http://sso.mk9h.cn/webapi/dostars'
+      param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
+      param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
+  
+      this.setState({
+        verdisabled: true,
+        delay: 60
+      })
+      LoginVerCodeTimer = setTimeout(this.resetVerCodeDelay, 1000)
+  
+      Api.getLocalConfig(param).then(res => {
+        if (res.status) {
+  
+        } else {
+          if (LoginVerCodeTimer) {
+            clearTimeout(LoginVerCodeTimer)
+          }
+          this.setState({
+            verdisabled: false,
+            delay: null
+          })
+          message.warning(res.message)
+        }
+      }, () => {
         if (LoginVerCodeTimer) {
           clearTimeout(LoginVerCodeTimer)
         }
@@ -230,15 +261,6 @@
           verdisabled: false,
           delay: null
         })
-        message.warning(res.message)
-      }
-    }, () => {
-      if (LoginVerCodeTimer) {
-        clearTimeout(LoginVerCodeTimer)
-      }
-      this.setState({
-        verdisabled: false,
-        delay: null
       })
     })
   }
@@ -314,7 +336,7 @@
               />
             )}
           </Form.Item> : null}
-          {activeKey === 'sms_vcode' ? <Form.Item>
+          {activeKey === 'sms_vcode' ? <Form.Item className="vercode">
             {getFieldDecorator('vercode', {
               initialValue: '',
               rules: [
@@ -356,7 +378,7 @@
               {this.props.dict['login.submit']}
             </Button>
           </Form.Item> : null}
-          {options.sysType === 'cloud' ? <Form.Item className="register-line">
+          {options.sysType === 'cloud' && options.cdomain.indexOf('mk9h') > -1 ? <Form.Item className="register-line">
             <a href="http://minkesoft.com/#/signup" target="_blank" rel="noopener noreferrer" className="register">娉ㄥ唽</a>
             <a href="http://minkesoft.com/#/forgotPwd" target="_blank" rel="noopener noreferrer" className="forgot">蹇樿瀵嗙爜锛�</a>
           </Form.Item> : null}
diff --git a/src/views/menudesign/homeform/index.jsx b/src/views/menudesign/homeform/index.jsx
index 6ca64be..ba1e5d7 100644
--- a/src/views/menudesign/homeform/index.jsx
+++ b/src/views/menudesign/homeform/index.jsx
@@ -1,7 +1,9 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, Radio, Icon, Tooltip, InputNumber } from 'antd'
+import { Form, Row, Col, Radio, Icon, Tooltip, InputNumber, notification } from 'antd'
 
+import Api from '@/api'
+import options from '@/store/options.js'
 import './index.scss'
 
 class CustomMenuForm extends Component {
@@ -11,6 +13,71 @@
     updateConfig: PropTypes.func
   }
 
+  state = {
+    menulist: []
+  }
+
+  UNSAFE_componentWillMount () {
+    let _param = {func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}
+    _param.pro_sys = window.GLOB.systemType === 'production' ? 'Y' : ''
+
+    Api.getSystemConfig(_param).then(result => {
+      if (result.status) {
+        let menulist = result.fst_menu.map(fst => {
+          let fstItem = {
+            MenuID: fst.MenuID,
+            MenuName: fst.MenuName,
+            value: fst.MenuID,
+            label: fst.MenuName,
+            isLeaf: false,
+            children: []
+          }
+    
+          if (fst.snd_menu) {
+            fstItem.children = fst.snd_menu.map(snd => {
+              let sndItem = {
+                ParentId: fst.MenuID,
+                MenuID: snd.MenuID,
+                MenuName: snd.MenuName,
+                value: snd.MenuID,
+                label: snd.MenuName,
+                children: []
+              }
+    
+              if (snd.trd_menu) {
+                sndItem.children = snd.trd_menu.map(trd => {
+                  let trdItem = {
+                    FstId: fst.MenuID,
+                    ParentId: snd.MenuID,
+                    MenuID: trd.MenuID,
+                    MenuName: trd.MenuName,
+                    MenuNo: trd.MenuNo,
+                    EasyCode: trd.EasyCode,
+                    value: trd.MenuID,
+                    label: trd.MenuName,
+                    disabled: false
+                  }
+
+                  return trdItem
+                })
+              }
+              return sndItem
+            })
+          }
+          return fstItem
+        })
+
+        sessionStorage.setItem('fstMenuList', JSON.stringify(menulist))
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
   // 涓�浜岀骇鑿滃崟鍒囨崲
   selectChange = (key, value) => {
     const { config } = this.props
diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx
index 84cee4d..85e7fe4 100644
--- a/src/views/menudesign/index.jsx
+++ b/src/views/menudesign/index.jsx
@@ -8,7 +8,7 @@
 
 import Api from '@/api'
 import options from '@/store/options.js'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -34,6 +34,7 @@
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const PaddingController = asyncComponent(() => import('@/menu/padcontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
@@ -44,6 +45,7 @@
 
 sessionStorage.setItem('isEditState', 'true')
 sessionStorage.setItem('editMenuType', 'menu') // 缂栬緫鑿滃崟绫诲瀷
+sessionStorage.setItem('appType', '')          // 搴旂敤绫诲瀷
 document.body.className = ''
 window.GLOB.UserComponentMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夌粍浠�
 window.GLOB.urlFields = []               // url鍙橀噺
@@ -66,7 +68,8 @@
     config: null,
     popBtn: null,             // 寮圭獥鏍囩椤�
     visible: false,
-    customComponents: []
+    customComponents: [],
+    comloading: false
   }
 
   UNSAFE_componentWillMount() {
@@ -105,6 +108,7 @@
     setTimeout(() => {
       this.updateCustomComponent()
       this.getAppPictures()
+      setGLOBFuncs()
     }, 1000)
   }
 
@@ -152,6 +156,7 @@
   updateCustomComponent = () => {
     Api.getSystemConfig({
       func: 's_get_custom_components',
+      typename: '',
       typecharone: ''
     }).then(res => {
       let coms = []
@@ -199,10 +204,11 @@
     })
 
     this.setState({
-      config: {...config, components: []}
+      config: {...config, components},
+      comloading: true
     }, () => {
       this.setState({
-        config: {...config, components: components}
+        comloading: false
       })
     })
   }
@@ -393,6 +399,13 @@
               buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
               _sort++
             })
+          })
+        } else if (item.type === 'balcony') {
+          item.elements && item.elements.forEach(cell => {
+            if (cell.eleType !== 'button') return
+            this.checkBtn(cell)
+            buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
+            _sort++
           })
         } else if (item.type === 'line' || item.type === 'bar') {
           item.action && item.action.forEach(btn => {
@@ -645,7 +658,8 @@
         if (res.status) {
           config.open_edition = res.open_edition || ''
           this.setState({
-            oriConfig: fromJS(config).toJS()
+            config,
+            oriConfig: fromJS(config).toJS(),
           })
 
           if (btnParam.LText) {
@@ -763,10 +777,10 @@
             copyButtons: [],
             thawButtons: [],
             menuloading: false,
-            config: {...config, components: []}
+            comloading: true
           }, () => {
             this.setState({
-              config: {...this.state.config, components: this.state.oriConfig.components}
+              comloading: false
             })
           })
           notification.success({
@@ -827,28 +841,48 @@
   }
 
   verifyConfig = (show) => {
-    const { config, MenuType } = this.state
+    const { config } = this.state
     let error = ''
 
-    config.components.forEach(item => {
-      if (error) return
-      if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && item.wrap.datatype === 'static') return
+    let check = (components) => {
+      components.forEach(item => {
+        if (error) return
+        if (item.type === 'tabs') {
+          item.subtabs.forEach(tab => {
+            check(tab.components)
+          })
+          return
+        } else if (item.type === 'group') {
+          check(item.components)
+          return
+        }
+        if (['propcard', 'brafteditor', 'sandbox', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
+        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
+  
+        if (item.setting) {
+          if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (!item.setting.primaryKey) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
+          }
+        }
+        if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
+          if (!item.plot.Xaxis) {
+            error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
+          }
+        } else if (item.type === 'dashboard' && !item.plot.valueField) {
+          error = `缁勪欢銆�${item.name}銆嬫樉绀哄�煎皻鏈缃紒`
+        } else if (item.type === 'scatter' && (!item.plot.Xaxis || !item.plot.Yaxis || !item.plot.gender)) {
+          error = `缁勪欢銆�${item.name}銆嬪潗鏍囪酱灏氭湭璁剧疆锛乣
+        } else if (item.type === 'tree' && (!item.wrap.valueField || !item.wrap.labelField || !item.wrap.parentField)) {
+          error = `缁勪欢銆�${item.name}銆嬪熀鏈俊鎭皻鏈缃紒`
+        }
+      })
+    }
 
-      if (item.setting) {
-        if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType && !item.setting.primaryKey && MenuType !== 'billPrint') {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
-        }
-      }
-      if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
-        if (!item.plot.Xaxis) {
-          error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
-        }
-      }
-    })
+    check(config.components)
 
     if (show && error) {
       notification.warning({
@@ -869,6 +903,18 @@
     window.GLOB.customMenu = config
   }
 
+  resetConfig = (config) => {
+    this.setState({
+      config,
+      comloading: true
+    }, () => {
+      this.setState({
+        comloading: false
+      })
+    })
+    window.GLOB.customMenu = config
+  }
+
   insert = (item) => {
     let config = fromJS(this.state.config).toJS()
 
@@ -879,7 +925,7 @@
   }
 
   render () {
-    const { activeKey, MenuType, popBtn, visible, dict, MenuId, config, ParentId, MenuName, MenuNo, menuloading, customComponents } = this.state
+    const { activeKey, comloading, MenuType, popBtn, visible, dict, MenuId, config, ParentId, MenuName, MenuNo, menuloading, customComponents } = this.state
 
     return (
       <ConfigProvider locale={_locale}>
@@ -901,10 +947,6 @@
                       MenuNo={MenuNo}
                       updateConfig={this.updateConfig}
                     /> : null}
-                    {config && MenuType === 'custom' ? <UrlFieldComponent
-                      config={config}
-                      updateConfig={this.updateConfig}
-                    /> : null}
                     {config && MenuType === 'home' ? <HomeForm
                       dict={dict}
                       config={config}
@@ -912,6 +954,10 @@
                     /> : null}
                     {config && MenuType === 'billPrint' ? <PrintMenuForm
                       dict={dict}
+                      config={config}
+                      updateConfig={this.updateConfig}
+                    /> : null}
+                    {config ? <UrlFieldComponent
                       config={config}
                       updateConfig={this.updateConfig}
                     /> : null}
@@ -938,16 +984,17 @@
                   <div> {config && config.MenuName} </div>
                 } bordered={false} extra={
                   <div>
+                    <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                     <SysInterface config={config} updateConfig={this.updateConfig}/>
                     <PictureController/>
                     <StyleCombControlButton menu={config} />
                     <PasteController type="menu" Tab={null} insert={this.insert} />
                     <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config && config.enabled} onChange={this.onEnabledChange} />
                     <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
-                    <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
+                    <Button type="default" onClick={this.closeView}>鍏抽棴</Button>
                   </div>
                 } style={{ width: '100%' }}>
-                  {config && config.components ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
+                  {config && !comloading ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
                 </Card>
               </div>
             </div>
diff --git a/src/views/menudesign/index.scss b/src/views/menudesign/index.scss
index 65fadca..b9b5812 100644
--- a/src/views/menudesign/index.scss
+++ b/src/views/menudesign/index.scss
@@ -1,7 +1,7 @@
 .pc-menu-view {
   background: #000;
   min-height: 100vh;
-  .menu-body {
+  >.menu-body {
     width: 100vw;
     height: 100vh;
     overflow-x: hidden;
diff --git a/src/views/menudesign/printmenuform/index.jsx b/src/views/menudesign/printmenuform/index.jsx
index a6de29a..b9204e6 100644
--- a/src/views/menudesign/printmenuform/index.jsx
+++ b/src/views/menudesign/printmenuform/index.jsx
@@ -1,6 +1,6 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
-import { Form, Row, Col, InputNumber, Select, Radio } from 'antd'
+import { Form, Row, Col, InputNumber, Select, Radio, Tooltip, Icon } from 'antd'
 
 import './index.scss'
 
@@ -25,6 +25,20 @@
     this.props.updateConfig({...this.props.config, everyPCount: val})
   }
 
+  changePrintWidth = (val) => {
+    if (typeof(val) !== 'number') {
+      val = ''
+    }
+    this.props.updateConfig({...this.props.config, printWidth: val})
+  }
+
+  changePrintHeight = (val) => {
+    if (typeof(val) !== 'number') {
+      val = ''
+    }
+    this.props.updateConfig({...this.props.config, printHeight: val})
+  }
+
   changeLastCount = (val) => {
     if (typeof(val) !== 'number') {
       val = ''
@@ -34,14 +48,67 @@
 
   pageSizeChange = (val) => {
     this.props.updateConfig({...this.props.config, pageSize: val})
+    this.resetPage()
   }
 
   onLayoutChange = (val) => {
     this.props.updateConfig({...this.props.config, pageLayout: val})
+    this.resetPage()
   }
   
   onPaddingChange = (val) => {
     this.props.updateConfig({...this.props.config, pagePadding: val})
+    this.resetPage()
+  }
+
+  onPrintCustomChange = (val) => {
+    this.props.updateConfig({...this.props.config, printCustom: val})
+    this.resetPage()
+  }
+
+  resetPage = () => {
+    this.setState({}, () => {
+      const { config } = this.props
+  
+      if (config.printCustom !== 'true') return
+  
+      let pageSize = config.pageSize || 'A4'
+      let pageLayout = config.pageLayout !== 'horizontal' ? 'vertical' : 'horizontal'
+      let pagePadding = config.pagePadding !== 'without' ? 'default' : 'without'
+  
+      let pageParam = {
+        A4: {
+          vertical: 980,
+          horizontal: 1200,
+          verticaldefault: 1.455,
+          verticalwithout: 1.411,
+          horizontaldefault: 0.679,
+          horizontalwithout: 0.701,
+        },
+        A3: {
+          vertical: 1200,
+          horizontal: 1600,
+          verticaldefault: 1.441,
+          verticalwithout: 1.410,
+          horizontaldefault: 0.688,
+          horizontalwithout: 0.703,
+        },
+        A5: {
+          vertical: 700,
+          horizontal: 1000,
+          verticaldefault: 1.478,
+          verticalwithout: 1.413,
+          horizontaldefault: 0.669,
+          horizontalwithout: 0.700,
+        }
+      }
+  
+      let width = pageParam[pageSize][pageLayout]
+      let height = Math.floor(width * pageParam[pageSize][pageLayout + pagePadding])
+  
+      this.props.updateConfig({...config, printHeight: height, printWidth: width})
+      this.props.form.setFieldsValue({printHeight: height, printWidth: width})
+    })
   }
 
   render() {
@@ -149,6 +216,37 @@
               })(<InputNumber min={1} max={1000} precision={0} onChange={this.changeLastCount}/>)}
             </Form.Item>
           </Col>
+          <Col span={24}>
+            <Form.Item label={
+              <Tooltip placement="topLeft" title="閽堝涓嶈鍒欑焊寮狅紝鍙嚜瀹氫箟璁剧疆鎵撳嵃楂樺害鍜屽搴︼紝娉細鍚屾椂璁剧疆鎵撳嵃瀹藉害鍜岄珮搴﹀悗鏂瑰彲鐢熸晥銆�">
+                <Icon type="question-circle" />
+                鑷畾涔�
+              </Tooltip>
+            }>
+              {getFieldDecorator('printCustom', {
+                initialValue: config.printCustom || 'false'
+              })(
+                <Radio.Group onChange={(e) => {this.onPrintCustomChange(e.target.value)}}>
+                  <Radio value="false">涓嶅惎鐢�</Radio>
+                  <Radio value="true">鍚敤</Radio>
+                </Radio.Group>
+              )}
+            </Form.Item>
+          </Col>
+          {config.printCustom === 'true' ? <Col span={24}>
+            <Form.Item label="鎵撳嵃瀹藉害">
+              {getFieldDecorator('printWidth', {
+                initialValue: config.printWidth || ''
+              })(<InputNumber min={10} max={9999} precision={0} onChange={this.changePrintWidth}/>)}
+            </Form.Item>
+          </Col> : null}
+          {config.printCustom === 'true' ? <Col span={24}>
+            <Form.Item label="鎵撳嵃楂樺害">
+              {getFieldDecorator('printHeight', {
+                initialValue: config.printHeight || ''
+              })(<InputNumber min={10} max={9999} precision={0} onChange={this.changePrintHeight}/>)}
+            </Form.Item>
+          </Col> : null}
         </Row>
       </Form>
     )
diff --git a/src/views/menudesign/printmenuform/index.scss b/src/views/menudesign/printmenuform/index.scss
index 0c9f8a8..0295f37 100644
--- a/src/views/menudesign/printmenuform/index.scss
+++ b/src/views/menudesign/printmenuform/index.scss
@@ -2,4 +2,9 @@
   .ant-input-number {
     width: 100%;
   }
+  .anticon-question-circle {
+    color: #c49f47;
+    position: relative;
+    left: -3px;
+  }
 }
\ No newline at end of file
diff --git a/src/views/mobdesign/index.jsx b/src/views/mobdesign/index.jsx
index 677496a..e983907 100644
--- a/src/views/mobdesign/index.jsx
+++ b/src/views/mobdesign/index.jsx
@@ -5,10 +5,10 @@
 import { is, fromJS } from 'immutable'
 import moment from 'moment'
 import HTML5Backend from 'react-dnd-html5-backend'
-import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin } from 'antd'
+import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin, Icon } from 'antd'
 
 import Api from '@/api'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -25,15 +25,19 @@
 const Header = asyncComponent(() => import('@/mob/header'))
 const MenuForm = asyncComponent(() => import('./menuform'))
 const MobShell = asyncComponent(() => import('@/mob/mobshell'))
+const CreateView = asyncComponent(() => import('@/pc/createview'))
+const Transfer = asyncComponent(() => import('@/pc/transfer'))
 const SourceWrap = asyncComponent(() => import('@/mob/modulesource'))
 const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent'))
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
-const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller'))
+const ModalController = asyncComponent(() => import('@/mob/modalconfig/controller'))
+const SearchController = asyncComponent(() => import('@/mob/searchconfig/controller'))
 const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller'))
 const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton'))
 const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
@@ -55,15 +59,15 @@
     MenuId: '',
     MenuName: '',
     MenuNo: '',
-    delButtons: [],
-    copyButtons: [],
-    thawButtons: [],
-    activeKey: 'basedata',
+    activeKey: 'component',
     menuloading: false,
     oriConfig: null,
     config: null,
-    visible: false,
     customComponents: [],
+    direction: 'vertical',
+    settingshow: true,
+    controlshow: true,
+    comloading: false
   }
 
   UNSAFE_componentWillMount() {
@@ -75,9 +79,9 @@
         sessionStorage.setItem('appId', param.ID || '')
         sessionStorage.setItem('lang', param.lang || 'zh-CN')
         sessionStorage.setItem('kei_no', param.kei_no || '')
-        sessionStorage.setItem('link_type', param.link_type || 'true')
         sessionStorage.setItem('role_type', param.role_type || 'true')
-        sessionStorage.setItem('login_types', param.login_types || 'true')
+        sessionStorage.setItem('login_types', param.login_types || 'false')
+        sessionStorage.setItem('typename', param.typename || 'mob')
 
         this.setState({
           localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
@@ -85,6 +89,18 @@
         })
         this.getAppMessage()
       } else if (param.type === 'view') {
+        window.GLOB.winWidth = 420
+        window.GLOB.winHeight = 738
+        window.GLOB.shellWidth = 376
+        window.GLOB.shellHeight = 680
+
+        if (sessionStorage.getItem('typename') === 'pad') {
+          window.GLOB.winWidth = 736
+          window.GLOB.winHeight = 945
+          window.GLOB.shellWidth = 640
+          window.GLOB.shellHeight = 853
+        }
+
         this.setState({
           MenuId: param.MenuID
         }, () => {
@@ -115,15 +131,14 @@
       document.getElementById('mk-mob-design-view').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh; height: 100vh; background: #fff;">鏈簲鐢ㄦ病鏈塒C绔〉闈㈢殑缂栬緫鏉冮檺锛岃鑱旂郴绠$悊鍛橈紒</div>'
       return
     }
-    MKEmitter.addListener('delButtons', this.delButtons)
-    MKEmitter.addListener('thawButtons', this.thawButtons)
-    MKEmitter.addListener('copyButtons', this.copyButtons)
     MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
     MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
     MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
     setTimeout(() => {
       this.updateCustomComponent()
       this.getAppPictures()
+      this.getSmStemp()
+      setGLOBFuncs()
     }, 1000)
   }
 
@@ -134,12 +149,42 @@
     this.setState = () => {
       return
     }
-    MKEmitter.removeListener('delButtons', this.delButtons)
-    MKEmitter.removeListener('thawButtons', this.thawButtons)
-    MKEmitter.removeListener('copyButtons', this.copyButtons)
     MKEmitter.removeListener('changeEditMenu', this.changeEditMenu)
     MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
     MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
+  }
+
+  getSmStemp = () => {
+    let _sql = `select ID,TemplateCode,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) => {
@@ -160,11 +205,8 @@
       type: 'view'
     }
 
-    if (menu.fixed && menu.MenuNo && menu.MenuName) {
-      param.fixed = true
-      param.MenuNo = menu.MenuNo
-      param.MenuName = menu.MenuName
-    }
+    param.MenuNo = menu.MenuNo || ''
+    param.MenuName = menu.MenuName || ''
 
     param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
 
@@ -233,13 +275,11 @@
             })
           } else {
             sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
-            sessionStorage.setItem('appHomeId', homeId)
             this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
           }
         })
       } else {
         sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
-        sessionStorage.setItem('appHomeId', homeId)
         this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
       }
     })
@@ -276,6 +316,7 @@
   updateCustomComponent = () => {
     Api.getSystemConfig({
       func: 's_get_custom_components',
+      typename: sessionStorage.getItem('typename'),
       typecharone: ''
     }).then(res => {
       let coms = []
@@ -323,29 +364,13 @@
     })
 
     this.setState({
-      config: {...config, components: []}
+      config: {...config, components},
+      comloading: true
     }, () => {
       this.setState({
-        config: {...config, components: components}
+        comloading: false
       })
     })
-  }
-
-  delButtons = (items) => {
-    const { copyButtons, delButtons } = this.state
-
-    this.setState({
-      delButtons: [...delButtons, ...items],
-      copyButtons: copyButtons.filter(item => !items.includes(item.uuid))
-    })
-  }
-
-  copyButtons = (items) => {
-    this.setState({copyButtons: [...this.state.copyButtons, ...items]})
-  }
-  
-  thawButtons = (item) => {
-    this.setState({thawButtons: [...this.state.thawButtons, item]})
   }
 
   closeView = () => {
@@ -376,7 +401,7 @@
     let param = {
       func: 'sPC_Get_LongParam',
       TypeCharOne: sessionStorage.getItem('kei_no'),
-      typename: 'mob',
+      typename: sessionStorage.getItem('typename'),
       MenuID: MenuId
     }
 
@@ -410,8 +435,8 @@
             MenuID: MenuId,
             Template: 'webPage',
             enabled: false,
-            MenuName: '',
-            MenuNo: '',
+            MenuName: urlParam.MenuName || '',
+            MenuNo: urlParam.MenuNo || '',
             tables: [],
             components: [],
             viewType: 'menu',
@@ -426,12 +451,6 @@
         config.open_edition = result.open_edition || ''
         window.GLOB.urlFields = config.urlFields || []
 
-        if (urlParam.fixed) {
-          config.fixed = true
-          config.MenuName = urlParam.MenuName
-          config.MenuNo = urlParam.MenuNo
-        }
-
         let indeComs = []
         config.components.forEach(item => {
           if (item.type === 'navbar') {
@@ -443,6 +462,7 @@
           this.setState({
             oriConfig: isCreate ? null : config,
             config: fromJS(config).toJS(),
+            activeKey: isCreate ? 'basedata' : 'component',
             loading: false
           })
           window.GLOB.customMenu = config
@@ -458,7 +478,7 @@
     let _param = {
       func: 's_get_app_menus',
       TypeCharOne: sessionStorage.getItem('kei_no'),
-      typename: 'mob',
+      typename: sessionStorage.getItem('typename'),
       LText: `select '${window.GLOB.appkey}'`,
       timestamp: moment().format('YYYY-MM-DD HH:mm:ss')
     }
@@ -490,7 +510,7 @@
     let param = {
       func: 'sPC_Get_LongParam',
       TypeCharOne: sessionStorage.getItem('kei_no'),
-      typename: 'mob',
+      typename: sessionStorage.getItem('typename'),
       MenuID: urlParam.copyMenuId
     }
 
@@ -545,6 +565,8 @@
       config.uuid = MenuId
       config.MenuID = MenuId
       config.open_edition = ''
+      config.MenuName = urlParam.MenuName || ''
+      config.MenuNo = urlParam.MenuNo || ''
 
       let indeComs = []
       config.components.forEach(item => {
@@ -573,7 +595,7 @@
         Api.getSystemConfig({
           func: 'sPC_Get_LongParam',
           TypeCharOne: sessionStorage.getItem('kei_no'),
-          typename: 'mob',
+          typename: sessionStorage.getItem('typename'),
           MenuID: item.uuid
         }).then(res => {
           res.uuid = item.uuid
@@ -632,6 +654,7 @@
 
       this.setState({
         oriConfig: isCreate ? null : fromJS(config).toJS(),
+        activeKey: isCreate ? 'basedata' : 'component',
         config: config,
         loading: false
       })
@@ -641,64 +664,123 @@
 
   getMenuMessage = () => {
     const { config } = this.state
-    let buttons = []
-    let _sort = 1
-
+    
     let traversal = (components) => {
-      components.forEach(item => {
+      let list = components.map(item => {
+        let m = {
+          key: item.uuid,
+          title: item.name,
+          children: []
+        }
         if (item.type === 'tabs') {
+          let tabs = []
           item.subtabs.forEach(tab => {
-            traversal(tab.components)
+            let s = traversal(tab.components)
+
+            if (s.length === 0) return
+
+            tabs.push({
+              key: tab.uuid,
+              title: tab.label,
+              children: s
+            })
           })
+
+          if (tabs.length > 0) {
+            m.children = tabs
+          }
         } else if (item.type === 'group') {
-          traversal(item.components)
+          m.children = traversal(item.components)
         } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
           item.action && item.action.forEach(btn => {
             this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+            m.children.push({
+              key: btn.uuid,
+              title: btn.label,
+            })
           })
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
-              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
             })
             card.backElements && card.backElements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
-              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
             })
           })
-        } else if (item.type === 'line' || item.type === 'bar') {
-          item.action && item.action.forEach(btn => {
-            this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+        } else if (item.type === 'carousel') {
+          item.subcards.forEach(card => {
+            card.elements && card.elements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              this.checkBtn(cell)
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
+            })
+          })
+        } else if (item.type === 'balcony') {
+          item.elements && item.elements.forEach(cell => {
+            if (cell.eleType !== 'button') return
+            this.checkBtn(cell)
+            m.children.push({
+              key: cell.uuid,
+              title: cell.label,
+            })
+          })
+        } else if (item.type === 'menubar') {
+          if (item.wrap.title) {
+            m.title = item.wrap.title
+          }
+
+          m.children = item.subMenus.map(menu => {
+            return {
+              key: menu.uuid,
+              title: menu.setting.name
+            }
           })
         } else if (item.type === 'table' && item.subtype === 'normaltable') {
           item.action && item.action.forEach(btn => {
             this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+            m.children.push({
+              key: btn.uuid,
+              title: btn.label,
+            })
           })
           item.cols && item.cols.forEach(col => {
             if (col.type !== 'action') return
             col.elements.forEach(btn => {
               this.checkBtn(btn)
-              buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: btn.uuid,
+                title: btn.label,
+              })
             })
           })
         }
+
+        if (m.children.length === 0) return null
+
+        return m
       })
+
+      list = list.filter(Boolean)
+
+      return list
     }
 
-    traversal(config.components)
+    let trees = traversal(config.components)
 
-    return buttons
+    return trees
   }
 
   checkBtn = (btn) => {
@@ -739,7 +821,6 @@
   }
 
   submitConfig = () => {
-    const { delButtons, copyButtons, thawButtons } = this.state
     let config = fromJS(this.state.config).toJS()
 
     if (!config.MenuName || !config.MenuNo || (config.cacheUseful === 'true' && !config.cacheTime)) {
@@ -749,6 +830,7 @@
         duration: 5
       })
       this.setState({
+        settingshow: true,
         activeKey: 'basedata'
       })
       return
@@ -765,47 +847,30 @@
         config.enabled = false
       }
 
-      let parMenuId = sessionStorage.getItem('kei_no') + 'pc' + sessionStorage.getItem('lang')
+      let roleParam = {type: 'view', key: config.uuid, title: config.MenuName, children: []}
+      roleParam.children = this.getMenuMessage()
+
       let param = {
         func: 'sPC_TrdMenu_AddUpt',
-        FstID: parMenuId,
-        SndID: parMenuId,
-        ParentID: parMenuId,
+        FstID: 'mk_app',
+        SndID: 'mk_app',
+        ParentID: 'mk_app',
         MenuID: config.uuid,
         MenuNo: config.MenuNo || '',
         EasyCode: '',
         Template: 'webPage',
         TypeCharOne: sessionStorage.getItem('kei_no'),
-        Typename: 'mob',
+        Typename: sessionStorage.getItem('typename'),
         MenuName: config.MenuName || '',
         PageParam: JSON.stringify({Template: 'webPage'}),
         open_edition: config.open_edition,
+        menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roleParam))),
         LText: '',
         LTexttb: ''
       }
 
       param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
       param.secretkey = Utils.encrypt('', param.timestamp)
-
-      let btnParam = {             // 娣诲姞鑿滃崟鎸夐挳
-        func: 'sPC_Button_AddUpt',
-        Type: 40,                  // 娣诲姞鑿滃崟涓嬬殑鎸夐挳type涓�40锛屾寜閽笅鐨勬寜閽畉ype涓�60
-        ParentID: config.uuid,
-        MenuNo: config.MenuNo,
-        Template: 'webPage',
-        PageParam: '',
-        LongParam: '',
-        LText: []
-      }
-
-      btnParam.LText = this.getMenuMessage()
-      btnParam.LText = btnParam.LText.join(' union all ')
-
-      let btnIds = btnParam.LText // 鐢ㄤ簬澶嶅埗鎸夐挳鐨勮繃婊�
-
-      btnParam.LText = Utils.formatOptions(btnParam.LText)
-      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
 
       new Promise(resolve => {
         let _config = fromJS(config).toJS()
@@ -836,20 +901,35 @@
                 return
               }
 
+              let roles = {
+                type: 'navbar',
+                key: item.uuid,
+                title: item.name,
+                children: []
+              }
+      
+              roles.children = item.menus.map(menu => {
+                return {
+                  key: menu.MenuID,
+                  title: menu.name
+                }
+              })
+
               let _param = {
                 func: 'sPC_TrdMenu_AddUpt',
-                FstID: parMenuId,
-                SndID: parMenuId,
-                ParentID: parMenuId,
+                FstID: 'mk_app',
+                SndID: 'mk_app',
+                ParentID: 'mk_app',
                 MenuID: item.uuid,
-                MenuNo: item.wrap.MenuNo || '',
+                MenuNo: item.wrap.MenuNo || Utils.getuuid(),
                 EasyCode: '',
                 Template: item.type,
                 TypeCharOne: sessionStorage.getItem('kei_no'),
-                Typename: 'mob',
+                Typename: sessionStorage.getItem('typename'),
                 MenuName: item.name || '',
                 PageParam: JSON.stringify({Template: item.type}),
                 open_edition: item.open_edition || '',
+                menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
                 LText: '',
                 LTexttb: ''
               }
@@ -857,96 +937,28 @@
               _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(item)))
               _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
               _param.secretkey = Utils.encrypt('', _param.timestamp)
-
-              let appMenuParam = null
-              if (item.type === 'navbar') {
-                appMenuParam = {
-                  func: 's_appmenus_addupt',
-                  exec_type: 'y'
-                }
-  
-                appMenuParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-                appMenuParam.secretkey = Utils.encrypt('', _param.timestamp)
-
-                let LText = []
-                let app_param = []
-                let kei_no = sessionStorage.getItem('kei_no')
-                let userid = sessionStorage.getItem('CloudUserID') || ''
-
-                item.menus.forEach((fst, findex) => {
-                  // LText.push(`select '${fst.MenuID}','${fst.name}','','0','${sessionStorage.getItem('appId')}','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
-                  LText.push(`select '${fst.MenuID}','${fst.name}','','0','0','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
-                  app_param.push(`select '${window.GLOB.appkey}','${fst.MenuID}','${userid}','${(findex + 1) * 10}','','${fst.name}','${fst.MenuNo || ''}','0','10','${kei_no}','pc'`)
-                  if (fst.property === 'classify' && fst.sublist.length > 0) {
-                    fst.sublist.forEach(scd => {
-                      LText.push(`select '${scd.MenuID}','${scd.name}','','0','${fst.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${scd.MenuNo || ''}','${kei_no}','pc'`)
-                      app_param.push(`select '${window.GLOB.appkey}','${scd.MenuID}','${userid}','${(findex + 1) * 10}','','${scd.name}','${scd.MenuNo || ''}','${fst.MenuID}','20','${kei_no}','pc'`)
-                    
-                      if (scd.property === 'classify' && scd.sublist.length > 0) {
-                        scd.sublist.forEach(thd => {
-                          LText.push(`select '${thd.MenuID}','${thd.name}','','0','${scd.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${thd.MenuNo || ''}','${kei_no}','pc'`)
-                          app_param.push(`select '${window.GLOB.appkey}','${thd.MenuID}','${userid}','${(findex + 1) * 10}','','${thd.name}','${thd.MenuNo || ''}','${scd.MenuID}','20','${kei_no}','pc'`)
-                        })
-                      }
-                    })
-                  }
-                })
-                appMenuParam.LText = Utils.formatOptions(LText.join(' union '))
-                appMenuParam.LText1 = Utils.formatOptions(app_param.join(' union '))
-              }
-
-              if (appMenuParam) {
-                Api.getSystemConfig(appMenuParam).then(_res => {
-                  if (!_res.status) {
-                    notification.warning({
-                      top: 92,
-                      message: _res.message,
-                      duration: 5
-                    })
-                    this.setState({ menuloading: false })
-                    return
-                  }
-
-                  Api.getSystemConfig(_param).then(res => {
-                    if (!res.status) {
-                      notification.warning({
-                        top: 92,
-                        message: res.message,
-                        duration: 5
-                      })
-                      this.setState({ menuloading: false })
-                      return
-                    }
-    
-                    new_open_edition[item.uuid] = res.open_edition || ''
-                    
-                    resolve()
+              
+              Api.getSystemConfig(_param).then(res => {
+                if (!res.status) {
+                  notification.warning({
+                    top: 92,
+                    message: res.message,
+                    duration: 5
                   })
-                })
-              } else {
-                Api.getSystemConfig(_param).then(res => {
-                  if (!res.status) {
-                    notification.warning({
-                      top: 92,
-                      message: res.message,
-                      duration: 5
-                    })
-                    this.setState({ menuloading: false })
-                    return
-                  }
-  
-                  new_open_edition[item.uuid] = res.open_edition || ''
-                  resolve()
-                })
-              }
+                  this.setState({ menuloading: false })
+                  return
+                }
+
+                new_open_edition[item.uuid] = res.open_edition || ''
+                resolve()
+              })
             })
           })
           Promise.all(deffers).then(() => {
             let appViewList = sessionStorage.getItem('appViewList')
             appViewList = JSON.parse(appViewList)
-            let _length = appViewList.length
+            let _appViewList = fromJS(appViewList).toJS()
             let appIndeList = appViewList.map(item => item.keys_id).join(',')
-            
 
             config.components = config.components.map(item => {
               if (item.type === 'navbar') {
@@ -962,12 +974,19 @@
                     keys_type: 'navbar',
                     remark: item.name
                   })
+                } else {
+                  appViewList = appViewList.map(view => {
+                    if (view.keys_id === item.uuid) {
+                      view.remark = item.name
+                    }
+                    return view
+                  })
                 }
               }
               return item
             })
 
-            if (appViewList.length > _length) {
+            if (!is(fromJS(appViewList), fromJS(_appViewList))) {
               let param = {
                 func: 's_kei_link_keyids_addupt',
                 BID: sessionStorage.getItem('appId'),
@@ -1000,191 +1019,38 @@
             }
           })
         }
-      }).then(res => { // 鎸夐挳鎴栬彍鍗曞垹闄�
-        if (!res) return
-
-        if (delButtons.length === 0) {
-          return { status: true, nonexec: true }
-        } else {
-          let appHomeId = sessionStorage.getItem('appHomeId')
-          let _param = {
-            func: 'sPC_MainMenu_Del',
-            MenuID: delButtons.filter(id => id !== appHomeId).join(',')
-          }
-          return Api.getSystemConfig(_param)
-        }
-      }).then(res => { // 鎸夐挳瑙i櫎鍐荤粨
-        if (!res) return
-        if (!res.status) {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-          return false
-        } else if (!res.nonexec) { // 鎵ц鍒犻櫎鍚庡埛鏂拌彍鍗曞垪琛�
-          this.getAppMenus()
-        }
-
-        let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1)
-        if (ids.length === 0) {
-          return { status: true }
-        } else {
-          return Api.getSystemConfig({
-            func: 'sPC_MainMenu_ReDel',
-            MenuID: ids.join(',')
-          })
-        }
       }).then(res => { // 椤甸潰淇濆瓨
         if (!res) return
 
-        if (res.status) {
-          return Api.getSystemConfig(param)
-        } else {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-          return false
-        }
-      }).then(res => { // 椤甸潰鎸夐挳鍏崇郴淇濆瓨
+        return Api.getSystemConfig(param)
+      }).then(res => {
         if (!res) return
 
         if (res.status) {
           config.open_edition = res.open_edition || ''
-
+          
           this.setState({
+            config,
             oriConfig: fromJS(config).toJS(),
-          })
-
-          if (btnParam.LText) {
-            return Api.getSystemConfig(btnParam)
-          } else {
-            return {
-              status: true
-            }
-          }
-        } else {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-          return false
-        }
-      }).then(res => { // 鎸夐挳澶嶅埗
-        if (!res) return
-        if (!res.status) {
-          notification.warning({
-            top: 92,
-            message: res.message,
-            duration: 5
-          })
-          return false
-        }
-
-        if (copyButtons.length === 0) {
-          return {
-            status: true
-          }
-        } else {
-          return new Promise(resolve => {
-            let deffers = copyButtons.map(item => {
-              return new Promise(resolve => {
-                if (btnIds.indexOf(item.uuid) === -1) { // 澶嶅埗鐨勬寜閽凡鍒犻櫎
-                  resolve({
-                    status: true
-                  })
-                  return
-                }
-
-                Api.getSystemConfig({
-                  func: 'sPC_Get_LongParam',
-                  MenuID: item.$originUuid
-                }).then(result => {
-                  if (result.status) {
-                    let _conf = ''
-              
-                    try {
-                      _conf = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : ''
-                    } catch (e) {
-                      console.warn('Parse Failure')
-                      _conf = ''
-                    }
-                    
-                    if (_conf) {
-                      _conf.components = MenuUtils.resetConfig(_conf.components)
-                      _conf.uuid = item.uuid
-                      _conf.MenuID = item.uuid
-                      _conf.Template = 'webPage'
-                    } else {
-                      resolve({
-                        status: true
-                      })
-                      return
-                    }
-
-                    let _param = {
-                      func: 'sPC_ButtonParam_AddUpt',
-                      ParentID: config.uuid,
-                      MenuID: item.uuid,
-                      MenuNo: '',
-                      Template: 'webPage',
-                      MenuName: item.label,
-                      PageParam: JSON.stringify({Template: 'webPage'}),
-                      LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(_conf)))
-                    }
-            
-                    Api.getSystemConfig(_param).then(response => {
-                      resolve(response)
-                    })
-                  }
-                })
-              })
-            })
-            Promise.all(deffers).then(result => {
-              let error = null
-              result.forEach(response => {
-                if (!response.status) {
-                  error = response
-                }
-              })
-    
-              if (error) {
-                notification.warning({
-                  top: 92,
-                  message: error.message,
-                  duration: 5
-                })
-                resolve(false)
-              } else {
-                resolve({
-                  status: true
-                })
-              }
-            })
-          })
-        }
-      }).then(res => {
-        if (res && res.status) {
-          this.setState({
-            delButtons: [],
-            copyButtons: [],
-            thawButtons: [],
             menuloading: false,
-            config: {...config, components: []}
+            comloading: true
           }, () => {
             this.setState({
-              config: {...this.state.config, components: this.state.oriConfig.components}
+              comloading: false
             })
           })
+
           notification.success({
             top: 92,
             message: '淇濆瓨鎴愬姛',
             duration: 2
           })
         } else {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
           this.setState({
             menuloading: false
           })
@@ -1241,25 +1107,46 @@
     const { config } = this.state
     let error = ''
 
-    config.components.forEach(item => {
-      if (error) return
-      if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && item.wrap.datatype === 'static') return
+    let check = (components) => {
+      components.forEach(item => {
+        if (error) return
+        if (item.type === 'tabs') {
+          item.subtabs.forEach(tab => {
+            check(tab.components)
+          })
+          return
+        } else if (item.type === 'group') {
+          check(item.components)
+          return
+        } else if (item.type === 'navbar' && !item.wrap.MenuNo) {
+          error = `瀵艰埅鏍忋��${item.name}銆嬫湭璁剧疆鑿滃崟鍙傛暟锛乣
+        }
 
-      if (item.setting) {
-        if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType && !item.setting.primaryKey) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
+        if (['propcard', 'brafteditor', 'sandbox', 'tabbar', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
+        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
+
+        if (item.setting) {
+          if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (!item.setting.primaryKey) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
+          }
         }
-      }
-      if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
-        if (!item.plot.Xaxis) {
-          error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
+        if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
+          if (!item.plot.Xaxis) {
+            error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
+          }
+        } else if (item.type === 'dashboard' && !item.plot.valueField) {
+          error = `缁勪欢銆�${item.name}銆嬫樉绀哄�煎皻鏈缃紒`
+        } else if (item.type === 'scatter' && (!item.plot.Xaxis || !item.plot.Yaxis || !item.plot.gender)) {
+          error = `缁勪欢銆�${item.name}銆嬪潗鏍囪酱灏氭湭璁剧疆锛乣
         }
-      }
-    })
+      })
+    }
+
+    check(config.components)
 
     if (show && error) {
       notification.warning({
@@ -1301,11 +1188,6 @@
       })
       return
     }
-
-    // Api.getSystemConfig({
-    //   func: 'sPC_MainMenu_Del',
-    //   MenuID: '1614740497468ku800sbg853vupf65v4'
-    // })
 
     sessionStorage.removeItem('sysRoles')
     sessionStorage.removeItem('permFuncField')
@@ -1366,7 +1248,6 @@
               duration: 5
             })
           } else {
-            sessionStorage.setItem('appHomeId', config.MenuID)
             sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
           }
         })
@@ -1375,20 +1256,59 @@
     })
   }
 
+  changeView = (val) => {
+    if (val !== 'vertical') {
+      window.GLOB.winWidth = 992
+      window.GLOB.winHeight = 690
+      window.GLOB.shellWidth = 853
+      window.GLOB.shellHeight = 640
+    } else {
+      window.GLOB.winWidth = 736
+      window.GLOB.winHeight = 945
+      window.GLOB.shellWidth = 640
+      window.GLOB.shellHeight = 853
+    }
+
+    this.setState({
+      direction: val,
+      comloading: true
+    }, () => {
+      this.setState({ comloading: false })
+    })
+  }
+
+  resetConfig = (config) => {
+    this.setState({
+      config: config,
+      comloading: true
+    }, () => {
+      this.setState({
+        comloading: false
+      })
+    })
+
+    window.GLOB.customMenu = config
+  }
+
+
   render () {
-    const { localedict, loading, activeKey, dict, MenuId, config, menuloading, customComponents } = this.state
+    const { localedict, comloading, loading, settingshow, controlshow, activeKey, dict, MenuId, config, menuloading, customComponents } = this.state
 
     return (
       <ConfigProvider locale={localedict}>
         <div className="mk-mob-view" id="mk-mob-design-view">
-          <Header />
+          <Header changeView={this.changeView}/>
           {loading ? <Spin className="view-spin" size="large" /> : null}
           <DndProvider backend={HTML5Backend}>
-            <div className="menu-setting">
+            <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
+              <div className="draw">
+                {settingshow ? <Icon onClick={() => {this.setState({settingshow: false})}} type="double-left" /> : null}
+                {!settingshow ? <Icon onClick={() => {this.setState({settingshow: true})}} type="double-right" /> : null}
+              </div>
               <div className="pc-setting-tools">
                 <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
                   {/* 鍩烘湰淇℃伅 */}
-                  <Panel header={dict['mob.basemsg']} key="basedata">
+                  <Panel header={dict['mob.basemsg']} forceRender key="basedata">
                     {/* 鑿滃崟淇℃伅 */}
                     {config ? <MenuForm
                       dict={dict}
@@ -1413,9 +1333,14 @@
                 </Collapse>
               </div>
             </div>
-            <div className="menu-control">
+            <div className={'menu-control ' + (!controlshow ? 'hidden' : '')}>
+              <div className="draw">
+                {controlshow ? <Icon onClick={() => {this.setState({controlshow: false})}} type="double-right" /> : null}
+                {!controlshow ? <Icon onClick={() => {this.setState({controlshow: true})}} type="double-left" /> : null}
+              </div>
               <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
               <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config && config.enabled} onChange={this.onEnabledChange} />
+              <CreateView resetmenu={this.getAppMenus} />
               <PasteController type="menu" Tab={null} insert={this.insert} />
               <StyleCombControlButton menu={config} />
               <SysInterface config={config} updateConfig={this.updateConfig}/>
@@ -1423,17 +1348,20 @@
               <Quotecomponent config={config} updateConfig={this.updateConfig}/>
               <Button className="mk-border-green" icon="home" onClick={this.setHomeView}>璁句负棣栭〉</Button>
               <Button className="mk-border-danger" icon="redo" onClick={this.refreshView}>寮哄埗鍒锋柊</Button>
-              <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
+              <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
+              <Transfer MenuID={MenuId} />
+              <Button type="default" onClick={this.closeView}>鍏抽棴</Button>
             </div>
-            <div className={'menu-body' + (menuloading ? 'saving' : '')}>
-              <div className="mob-shell">
-                {config ? <MobShell menu={config} handleList={this.updateConfig} /> : null}
-              </div>
+            <div className={'menu-body menu-view' + (menuloading ? 'saving' : '')}>
+              {config && !comloading ? <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
+                <MobShell menu={config} handleList={this.updateConfig} />
+              </div> : null}
             </div>
           </DndProvider>
           <StyleController />
           <StyleCombController />
           <ModalController />
+          <SearchController />
         </div>
       </ConfigProvider>
     )
diff --git a/src/views/mobdesign/index.scss b/src/views/mobdesign/index.scss
index 7699f0b..82ae4e6 100644
--- a/src/views/mobdesign/index.scss
+++ b/src/views/mobdesign/index.scss
@@ -17,6 +17,20 @@
     z-index: 10;
     transition: left 0.3s;
 
+    .draw {
+      position: absolute;
+      z-index: 1;
+      background: #ffffff;
+      right: -20px;
+      top: 0px;
+      box-shadow: 0 0 1px #959595;
+      border-radius: 0 2px 2px 0px;
+
+      i {
+        padding: 12px 3px;
+      }
+    }
+
     .pc-setting-tools {
       height: calc(100vh - 48px);
       width: 300px;
@@ -102,36 +116,33 @@
       background: rgba(0, 0, 0, 0);
     }
   }
+  .menu-setting.hidden {
+    left: -300px;
+  }
   .mob-shell {
-    width: 375px;
-    height: 680px;
     margin: 0 auto;
     background: #000000;
     background-size: 100% 100%;
     padding: 25px 13px 40px;
     border-radius: 30px;
-
-    .mob-shell-inner {
-      width: 100%;
-      height: 100%;
-      overflow-y: auto;
-      overflow-x: hidden;
-      background: #ffffff;
-      box-shadow: 0px 0px 2px #000000;
-    }
-    .mob-shell-inner::-webkit-scrollbar {
-      width: 2px;
-    }
-    .mob-shell-inner::-webkit-scrollbar-thumb {
-      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
-      background: rgba(0, 0, 0, 0.23);
-      border-radius: 5px;
-    }
-    .mob-shell-inner::-webkit-scrollbar-track {
-      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
-      border: 1px solid rgba(0, 0, 0, 0.07);
-      background: rgba(0, 0, 0, 0);
-      border-radius: 3px;
+    .main-search-edit-list {
+      .page-card > div > .ant-form-item {
+        display: flex;
+        >.ant-form-item-label {
+          width: 70px;
+        }
+        >.ant-form-item-control-wrapper {
+          flex: 1;
+        }
+        .ant-form-item-label > label::after {
+          content: ' ';
+          
+        }
+      }
+      .page-card.date .ant-form-item, .page-card.datemonth .ant-form-item {
+        // box-shadow: 0px 1px 1px #f0f0f0;
+        border-bottom: 1px solid #f0f0f0;
+      }
     }
   }
   .menu-control {
@@ -143,6 +154,20 @@
     background: #ffffff;
     z-index: 10;
     transition: right 0.3s;
+
+    .draw {
+      position: absolute;
+      z-index: 1;
+      background: #ffffff;
+      left: -21px;
+      top: 0px;
+      box-shadow: 0 0 1px #959595;
+      border-radius: 0 2px 2px 0px;
+
+      i {
+        padding: 12px 3px;
+      }
+    }
 
     div:not(.draw), button:not(.ant-switch) {
       display: block!important;
@@ -163,6 +188,9 @@
       height: 22px;
     }
   }
+  .menu-control.hidden {
+    right: -130px;
+  }
 
   .menu-body {
     width: 100vw;
@@ -172,12 +200,9 @@
     background: #959595;
     padding: 50px 0px 0px;
     overflow-y: auto;
-    .menu-shell-inner {
-      min-height: 100vh;
-      margin: 0 auto;
-    }
+
   }
-  .menu-body.saving {
+  .menu-body.saving, .menu-view.saving {
     .anticon-tool {
       display: none;
     }
diff --git a/src/views/mobdesign/menuform/index.jsx b/src/views/mobdesign/menuform/index.jsx
index 2335bcf..cedb3a5 100644
--- a/src/views/mobdesign/menuform/index.jsx
+++ b/src/views/mobdesign/menuform/index.jsx
@@ -69,7 +69,7 @@
                     message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.name'] + '!'
                   }
                 ]
-              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeName}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
@@ -82,7 +82,7 @@
                     message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.param'] + '!'
                   }
                 ]
-              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeNo}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
diff --git a/src/views/pcdesign/index.jsx b/src/views/pcdesign/index.jsx
index 29818ec..bde0d56 100644
--- a/src/views/pcdesign/index.jsx
+++ b/src/views/pcdesign/index.jsx
@@ -8,7 +8,7 @@
 import { ConfigProvider, notification, Modal, Collapse, Switch, Button, Icon, message, Spin } from 'antd'
 
 import Api from '@/api'
-import Utils from '@/utils/utils.js'
+import Utils, { setGLOBFuncs } from '@/utils/utils.js'
 import zhCN from '@/locales/zh-CN/mob.js'
 import enUS from '@/locales/en-US/mob.js'
 import antdEnUS from 'antd/es/locale/en_US'
@@ -23,12 +23,16 @@
 const { confirm } = Modal
 
 const MenuForm = asyncComponent(() => import('./menuform'))
+const Transfer = asyncComponent(() => import('@/pc/transfer'))
+const PopviewController = asyncComponent(() => import('@/menu/popview'))
 const MenuShell = asyncComponent(() => import('@/pc/menushell'))
 const SourceWrap = asyncComponent(() => import('@/pc/modulesource'))
+const CreateView = asyncComponent(() => import('@/pc/createview'))
 const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
 const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent'))
 const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
 const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
+const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
 const SysInterface = asyncComponent(() => import('@/menu/sysinterface'))
 const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
 const PictureController = asyncComponent(() => import('@/menu/picturecontroller'))
@@ -40,6 +44,7 @@
 sessionStorage.setItem('isEditState', 'true')
 sessionStorage.setItem('editMenuType', 'menu') // 缂栬緫鑿滃崟绫诲瀷
 sessionStorage.setItem('appType', 'pc')        // 搴旂敤绫诲瀷
+sessionStorage.setItem('typename', 'pc')
 document.body.className = ''
 window.GLOB.UserComponentMap = new Map() // 缂撳瓨鐢ㄦ埛鑷畾涔夌粍浠�
 window.GLOB.CacheIndependent = new Map()
@@ -66,6 +71,7 @@
     customComponents: [],
     settingshow: sessionStorage.getItem('settingshow') !== 'false',
     controlshow: sessionStorage.getItem('controlshow') !== 'false',
+    comloading: false
   }
 
   UNSAFE_componentWillMount() {
@@ -77,9 +83,8 @@
         sessionStorage.setItem('appId', param.ID || '')
         sessionStorage.setItem('lang', param.lang || 'zh-CN')
         sessionStorage.setItem('kei_no', param.kei_no || '')
-        sessionStorage.setItem('link_type', param.link_type || 'true')
         sessionStorage.setItem('role_type', param.role_type || 'true')
-        sessionStorage.setItem('login_types', param.login_types || 'true')
+        sessionStorage.setItem('login_types', param.login_types || 'false')
 
         this.setState({
           localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
@@ -127,6 +132,8 @@
     setTimeout(() => {
       this.updateCustomComponent()
       this.getAppPictures()
+      this.getSmStemp()
+      setGLOBFuncs()
     }, 1000)
   }
 
@@ -164,15 +171,15 @@
       type: 'view'
     }
 
-    if (menu.fixed && menu.MenuNo && menu.MenuName) {
-      param.fixed = true
-      param.MenuNo = menu.MenuNo
-      param.MenuName = menu.MenuName
-    }
+    param.MenuNo = menu.MenuNo || ''
+    param.MenuName = menu.MenuName || ''
 
     param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
 
-    if (param === this.props.match.params.param) return
+    if (param === this.props.match.params.param) {
+      window.location.reload()
+      return
+    }
 
     this.props.history.push('/pcdesign/' + param)
   }
@@ -237,15 +244,46 @@
             })
           } else {
             sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
-            sessionStorage.setItem('appHomeId', homeId)
             this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
           }
         })
       } else {
         sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
-        sessionStorage.setItem('appHomeId', homeId)
         this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
       }
+    })
+  }
+
+  getSmStemp = () => {
+    let _sql = `select ID,TemplateCode,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))
     })
   }
 
@@ -261,6 +299,12 @@
     }).then(res => {
       if (res.status) {
         sessionStorage.setItem('app_pictures', JSON.stringify(res.data || []))
+      } else if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
       }
 
       Api.getSystemConfig({
@@ -272,6 +316,12 @@
       }).then(res => {
         if (res.status) {
           sessionStorage.setItem('app_videos', JSON.stringify(res.data || []))
+        } else if (!res.status) {
+          notification.warning({
+            top: 92,
+            message: res.message,
+            duration: 5
+          })
         }
       })
     })
@@ -280,10 +330,17 @@
   updateCustomComponent = () => {
     Api.getSystemConfig({
       func: 's_get_custom_components',
+      typename: 'pc',
       typecharone: ''
     }).then(res => {
       let coms = []
-      if (res.cus_list && res.cus_list.length > 0) {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      } else if (res.cus_list && res.cus_list.length > 0) {
         res.cus_list.forEach(item => {
           let config = ''
 
@@ -314,6 +371,14 @@
     })
   }
 
+  handleBack = () => {
+    this.setState({popBtn: null, delButtons: [], copyButtons: [], thawButtons: []}, () => {
+      sessionStorage.setItem('editMenuType', 'menu')
+      window.GLOB.customMenu = this.state.config
+      this.setState({visible: false})
+    })
+  }
+
   updateComponentStyle = (parentId, keys, style) => {
     const { config } = this.state
 
@@ -327,10 +392,11 @@
     })
 
     this.setState({
-      config: {...config, components: []}
+      config: {...config, components},
+      comloading: true
     }, () => {
       this.setState({
-        config: {...config, components: components}
+        comloading: false
       })
     })
   }
@@ -434,8 +500,8 @@
             MenuID: MenuId,
             Template: 'webPage',
             enabled: false,
-            MenuName: '',
-            MenuNo: '',
+            MenuName: urlParam.MenuName || '',
+            MenuNo: urlParam.MenuNo || '',
             tables: [],
             components: [],
             viewType: 'menu',
@@ -444,17 +510,11 @@
             }
           }
         }
-        
+
         config.uuid = MenuId
         config.MenuID = MenuId
         config.open_edition = result.open_edition || ''
         window.GLOB.urlFields = config.urlFields || []
-
-        if (urlParam.fixed) {
-          config.fixed = true
-          config.MenuName = urlParam.MenuName
-          config.MenuNo = urlParam.MenuNo
-        }
 
         let indeComs = []
         config.components.forEach(item => {
@@ -570,6 +630,8 @@
       config.uuid = MenuId
       config.MenuID = MenuId
       config.open_edition = ''
+      config.MenuName = urlParam.MenuName || ''
+      config.MenuNo = urlParam.MenuNo || ''
 
       let indeComs = []
       config.components.forEach(item => {
@@ -666,64 +728,149 @@
 
   getMenuMessage = () => {
     const { config } = this.state
-    let buttons = []
-    let _sort = 1
+    let nodes = {type: 'view', key: config.uuid, title: config.MenuName, children: []}
+    let popviews = []
 
     let traversal = (components) => {
-      components.forEach(item => {
+      let list = components.map(item => {
+        let m = {
+          key: item.uuid,
+          title: item.name,
+          children: []
+        }
         if (item.type === 'tabs') {
+          let tabs = []
           item.subtabs.forEach(tab => {
-            traversal(tab.components)
+            let s = traversal(tab.components)
+
+            if (s.length === 0) return
+
+            tabs.push({
+              key: tab.uuid,
+              title: tab.label,
+              children: s
+            })
           })
+
+          if (tabs.length > 0) {
+            m.children = tabs
+          }
         } else if (item.type === 'group') {
-          traversal(item.components)
+          m.children = traversal(item.components)
         } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
           item.action && item.action.forEach(btn => {
             this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+            m.children.push({
+              key: btn.uuid,
+              title: btn.label,
+            })
+            if (btn.OpenType === 'popview') {
+              popviews.push(btn.uuid)
+            }
           })
           item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
-              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
+              if (cell.OpenType === 'popview') {
+                popviews.push(cell.uuid)
+              }
             })
             card.backElements && card.backElements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
-              buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
+              if (cell.OpenType === 'popview') {
+                popviews.push(cell.uuid)
+              }
             })
           })
-        } else if (item.type === 'line' || item.type === 'bar') {
-          item.action && item.action.forEach(btn => {
-            this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+        } else if (item.type === 'carousel') {
+          item.subcards.forEach(card => {
+            card.elements && card.elements.forEach(cell => {
+              if (cell.eleType !== 'button') return
+              this.checkBtn(cell)
+              m.children.push({
+                key: cell.uuid,
+                title: cell.label,
+              })
+              if (cell.OpenType === 'popview') {
+                popviews.push(cell.uuid)
+              }
+            })
+          })
+        } else if (item.type === 'balcony') {
+          item.elements && item.elements.forEach(cell => {
+            if (cell.eleType !== 'button') return
+            this.checkBtn(cell)
+            m.children.push({
+              key: cell.uuid,
+              title: cell.label,
+            })
+            if (cell.OpenType === 'popview') {
+              popviews.push(cell.uuid)
+            }
+          })
+        } else if (item.type === 'menubar') {
+          if (item.wrap.title) {
+            m.title = item.wrap.title
+          }
+
+          m.children = item.subMenus.map(menu => {
+            return {
+              key: menu.uuid,
+              title: menu.setting.name
+            }
           })
         } else if (item.type === 'table' && item.subtype === 'normaltable') {
           item.action && item.action.forEach(btn => {
             this.checkBtn(btn)
-            buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-            _sort++
+            m.children.push({
+              key: btn.uuid,
+              title: btn.label,
+            })
+            if (btn.OpenType === 'popview') {
+              popviews.push(btn.uuid)
+            }
           })
           item.cols && item.cols.forEach(col => {
             if (col.type !== 'action') return
             col.elements.forEach(btn => {
               this.checkBtn(btn)
-              buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
-              _sort++
+              m.children.push({
+                key: btn.uuid,
+                title: btn.label,
+              })
+              if (btn.OpenType === 'popview') {
+                popviews.push(btn.uuid)
+              }
             })
           })
         }
+
+        if (m.children.length === 0) return null
+
+        return m
       })
+
+      list = list.filter(Boolean)
+
+      return list
     }
 
-    traversal(config.components)
+    let trees = traversal(config.components)
 
-    return buttons
+    nodes.children = trees
+    nodes.popviews = popviews
+
+    return nodes
   }
 
   checkBtn = (btn) => {
@@ -792,12 +939,13 @@
         config.enabled = false
       }
 
-      let parMenuId = sessionStorage.getItem('kei_no') + 'pc' + sessionStorage.getItem('lang')
+      let roleParam = this.getMenuMessage()
+
       let param = {
         func: 'sPC_TrdMenu_AddUpt',
-        FstID: parMenuId,
-        SndID: parMenuId,
-        ParentID: parMenuId,
+        FstID: 'mk_app',
+        SndID: 'mk_app',
+        ParentID: 'mk_app',
         MenuID: config.uuid,
         MenuNo: config.MenuNo || '',
         EasyCode: '',
@@ -806,6 +954,7 @@
         Typename: 'pc',
         MenuName: config.MenuName || '',
         PageParam: JSON.stringify({Template: 'webPage'}),
+        menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roleParam))),
         open_edition: config.open_edition,
         LText: '',
         LTexttb: ''
@@ -813,26 +962,6 @@
 
       param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
       param.secretkey = Utils.encrypt('', param.timestamp)
-
-      let btnParam = {             // 娣诲姞鑿滃崟鎸夐挳
-        func: 'sPC_Button_AddUpt',
-        Type: 40,                  // 娣诲姞鑿滃崟涓嬬殑鎸夐挳type涓�40锛屾寜閽笅鐨勬寜閽畉ype涓�60
-        ParentID: config.uuid,
-        MenuNo: config.MenuNo,
-        Template: 'webPage',
-        PageParam: '',
-        LongParam: '',
-        LText: []
-      }
-
-      btnParam.LText = this.getMenuMessage()
-      btnParam.LText = btnParam.LText.join(' union all ')
-
-      let btnIds = btnParam.LText // 鐢ㄤ簬澶嶅埗鎸夐挳鐨勮繃婊�
-
-      btnParam.LText = Utils.formatOptions(btnParam.LText)
-      btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-      btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
 
       new Promise(resolve => {
         let _config = fromJS(config).toJS()
@@ -863,19 +992,51 @@
                 return
               }
 
+              let roles = {
+                type: 'navbar',
+                key: item.uuid,
+                title: item.name,
+                children: []
+              }
+      
+              roles.children = item.menus.map(fst => {
+                if (fst.property === 'classify' && fst.sublist.length > 0) {
+                  return {
+                    key: fst.MenuID,
+                    title: fst.name,
+                    children: fst.sublist.map(scd => {
+                      if (scd.property === 'classify' && scd.sublist.length > 0) {
+                        return {
+                          key: scd.MenuID,
+                          title: scd.name,
+                          children: scd.sublist.map(thd => {
+                            return { key: thd.MenuID, title: thd.name }
+                          })
+                        }
+                      } else {
+                        return { key: scd.MenuID, title: scd.name }
+                      }
+                    })
+                  }
+                } else {
+                  return { key: fst.MenuID, title: fst.name }
+                }
+              })
+
               let _param = {
                 func: 'sPC_TrdMenu_AddUpt',
-                FstID: parMenuId,
-                SndID: parMenuId,
-                ParentID: parMenuId,
+                FstID: 'mk_app',
+                SndID: 'mk_app',
+                ParentID: 'mk_app',
                 MenuID: item.uuid,
-                MenuNo: item.wrap.MenuNo || '',
+                MenuNo: item.wrap.MenuNo || Utils.getuuid(),
                 EasyCode: '',
                 Template: item.type,
                 TypeCharOne: sessionStorage.getItem('kei_no'),
                 Typename: 'pc',
                 MenuName: item.name || '',
                 PageParam: JSON.stringify({Template: item.type}),
+                menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
                 open_edition: item.open_edition || '',
                 LText: '',
                 LTexttb: ''
@@ -885,95 +1046,27 @@
               _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
               _param.secretkey = Utils.encrypt('', _param.timestamp)
 
-              let appMenuParam = null
-              if (item.type === 'navbar') {
-                appMenuParam = {
-                  func: 's_appmenus_addupt',
-                  exec_type: 'y'
-                }
-  
-                appMenuParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-                appMenuParam.secretkey = Utils.encrypt('', _param.timestamp)
-
-                let LText = []
-                let app_param = []
-                let kei_no = sessionStorage.getItem('kei_no')
-                let userid = sessionStorage.getItem('CloudUserID') || ''
-
-                item.menus.forEach((fst, findex) => {
-                  // LText.push(`select '${fst.MenuID}','${fst.name}','','0','${sessionStorage.getItem('appId')}','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
-                  LText.push(`select '${fst.MenuID}','${fst.name}','','0','0','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`)
-                  app_param.push(`select '${window.GLOB.appkey}','${fst.MenuID}','${userid}','${(findex + 1) * 10}','','${fst.name}','${fst.MenuNo || ''}','0','10','${kei_no}','pc'`)
-                  if (fst.property === 'classify' && fst.sublist.length > 0) {
-                    fst.sublist.forEach(scd => {
-                      LText.push(`select '${scd.MenuID}','${scd.name}','','0','${fst.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${scd.MenuNo || ''}','${kei_no}','pc'`)
-                      app_param.push(`select '${window.GLOB.appkey}','${scd.MenuID}','${userid}','${(findex + 1) * 10}','','${scd.name}','${scd.MenuNo || ''}','${fst.MenuID}','20','${kei_no}','pc'`)
-                    
-                      if (scd.property === 'classify' && scd.sublist.length > 0) {
-                        scd.sublist.forEach(thd => {
-                          LText.push(`select '${thd.MenuID}','${thd.name}','','0','${scd.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${thd.MenuNo || ''}','${kei_no}','pc'`)
-                          app_param.push(`select '${window.GLOB.appkey}','${thd.MenuID}','${userid}','${(findex + 1) * 10}','','${thd.name}','${thd.MenuNo || ''}','${scd.MenuID}','20','${kei_no}','pc'`)
-                        })
-                      }
-                    })
-                  }
-                })
-                appMenuParam.LText = Utils.formatOptions(LText.join(' union '))
-                appMenuParam.LText1 = Utils.formatOptions(app_param.join(' union '))
-              }
-
-              if (appMenuParam) {
-                Api.getSystemConfig(appMenuParam).then(_res => {
-                  if (!_res.status) {
-                    notification.warning({
-                      top: 92,
-                      message: _res.message,
-                      duration: 5
-                    })
-                    this.setState({ menuloading: false })
-                    return
-                  }
-
-                  Api.getSystemConfig(_param).then(res => {
-                    if (!res.status) {
-                      notification.warning({
-                        top: 92,
-                        message: res.message,
-                        duration: 5
-                      })
-                      this.setState({ menuloading: false })
-                      return
-                    }
-    
-                    new_open_edition[item.uuid] = res.open_edition || ''
-                    
-                    resolve()
+              Api.getSystemConfig(_param).then(res => {
+                if (!res.status) {
+                  notification.warning({
+                    top: 92,
+                    message: res.message,
+                    duration: 5
                   })
-                })
-              } else {
-                Api.getSystemConfig(_param).then(res => {
-                  if (!res.status) {
-                    notification.warning({
-                      top: 92,
-                      message: res.message,
-                      duration: 5
-                    })
-                    this.setState({ menuloading: false })
-                    return
-                  }
-  
-                  new_open_edition[item.uuid] = res.open_edition || ''
-                  resolve()
-                })
-              }
+                  this.setState({ menuloading: false })
+                  return
+                }
+
+                new_open_edition[item.uuid] = res.open_edition || ''
+                resolve()
+              })
             })
           })
           Promise.all(deffers).then(() => {
             let appViewList = sessionStorage.getItem('appViewList')
             appViewList = JSON.parse(appViewList)
-            let _length = appViewList.length
+            let _appViewList = fromJS(appViewList).toJS()
             let appIndeList = appViewList.map(item => item.keys_id).join(',')
-            
 
             config.components = config.components.map(item => {
               if (item.type === 'navbar') {
@@ -989,27 +1082,34 @@
                     keys_type: 'navbar',
                     remark: item.name
                   })
+                } else {
+                  appViewList = appViewList.map(view => {
+                    if (view.keys_id === item.uuid) {
+                      view.remark = item.name
+                    }
+                    return view
+                  })
                 }
               }
               return item
             })
 
-            if (appViewList.length > _length) {
-              let param = {
+            if (!is(fromJS(appViewList), fromJS(_appViewList))) {
+              let kparam = {
                 func: 's_kei_link_keyids_addupt',
                 BID: sessionStorage.getItem('appId'),
                 exec_type: 'y',
                 LText: ''
               }
     
-              param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
-              param.LText = param.LText.join(' union all ')
-              param.LText = Utils.formatOptions(param.LText)
+              kparam.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
+              kparam.LText = kparam.LText.join(' union all ')
+              kparam.LText = Utils.formatOptions(kparam.LText)
         
-              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
-              param.secretkey = Utils.encrypt('', param.timestamp)
+              kparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
+              kparam.secretkey = Utils.encrypt('', kparam.timestamp)
     
-              Api.getSystemConfig(param).then(result => {
+              Api.getSystemConfig(kparam).then(result => {
                 if (!result.status) {
                   notification.warning({
                     top: 92,
@@ -1033,10 +1133,9 @@
         if (delButtons.length === 0) {
           return { status: true, nonexec: true }
         } else {
-          let appHomeId = sessionStorage.getItem('appHomeId')
           let _param = {
             func: 'sPC_MainMenu_Del',
-            MenuID: delButtons.filter(id => id !== appHomeId).join(',')
+            MenuID: delButtons.join(',')
           }
           return Api.getSystemConfig(_param)
         }
@@ -1053,13 +1152,12 @@
           this.getAppMenus()
         }
 
-        let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1)
-        if (ids.length === 0) {
+        if (thawButtons.length === 0) {
           return { status: true }
         } else {
           return Api.getSystemConfig({
             func: 'sPC_MainMenu_ReDel',
-            MenuID: ids.join(',')
+            MenuID: thawButtons.join(',')
           })
         }
       }).then(res => { // 椤甸潰淇濆瓨
@@ -1082,15 +1180,12 @@
           config.open_edition = res.open_edition || ''
 
           this.setState({
+            config,
             oriConfig: fromJS(config).toJS(),
           })
 
-          if (btnParam.LText) {
-            return Api.getSystemConfig(btnParam)
-          } else {
-            return {
-              status: true
-            }
+          return {
+            status: true
           }
         } else {
           notification.warning({
@@ -1119,7 +1214,7 @@
           return new Promise(resolve => {
             let deffers = copyButtons.map(item => {
               return new Promise(resolve => {
-                if (btnIds.indexOf(item.uuid) === -1) { // 澶嶅埗鐨勬寜閽凡鍒犻櫎
+                if (delButtons.includes(item.uuid)) { // 澶嶅埗鐨勬寜閽凡鍒犻櫎
                   resolve({
                     status: true
                   })
@@ -1200,10 +1295,10 @@
             copyButtons: [],
             thawButtons: [],
             menuloading: false,
-            config: {...config, components: []}
+            comloading: true
           }, () => {
             this.setState({
-              config: {...this.state.config, components: this.state.oriConfig.components}
+              comloading: false
             })
           })
           notification.success({
@@ -1268,25 +1363,45 @@
     const { config } = this.state
     let error = ''
 
-    config.components.forEach(item => {
-      if (error) return
-      if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && item.wrap.datatype === 'static') return
+    let check = (components) => {
+      components.forEach(item => {
+        if (error) return
+        if (item.type === 'tabs') {
+          item.subtabs.forEach(tab => {
+            check(tab.components)
+          })
+          return
+        } else if (item.type === 'group') {
+          check(item.components)
+          return
+        }
+        if (['propcard', 'brafteditor', 'sandbox', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
+        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
+        
+        if (item.setting) {
+          if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
+          } else if (!item.setting.primaryKey) {
+            error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
+          }
+        }
+        if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
+          if (!item.plot.Xaxis) {
+            error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
+          }
+        } else if (item.type === 'dashboard' && !item.plot.valueField) {
+          error = `缁勪欢銆�${item.name}銆嬫樉绀哄�煎皻鏈缃紒`
+        } else if (item.type === 'scatter' && (!item.plot.Xaxis || !item.plot.Yaxis || !item.plot.gender)) {
+          error = `缁勪欢銆�${item.name}銆嬪潗鏍囪酱灏氭湭璁剧疆锛乣
+        } else if (item.type === 'tree' && (!item.wrap.valueField || !item.wrap.labelField || !item.wrap.parentField)) {
+          error = `缁勪欢銆�${item.name}銆嬪熀鏈俊鎭皻鏈缃紒`
+        }
+      })
+    }
 
-      if (item.setting) {
-        if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆鏁版嵁婧愶紒`
-        } else if (item.setting.interType && !item.setting.primaryKey) {
-          error = `缁勪欢銆�${item.name}銆嬫湭璁剧疆涓婚敭锛乣
-        }
-      }
-      if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') {
-        if (!item.plot.Xaxis) {
-          error = `缁勪欢銆�${item.name}銆嬪浘琛ㄥ瓧娈靛皻鏈缃紒`
-        }
-      }
-    })
+    check(config.components)
 
     if (show && error) {
       notification.warning({
@@ -1303,6 +1418,19 @@
   updateConfig = (config) => {
     this.setState({
       config: config
+    })
+
+    window.GLOB.customMenu = config
+  }
+
+  resetConfig = (config) => {
+    this.setState({
+      config: config,
+      comloading: true
+    }, () => {
+      this.setState({
+        comloading: false
+      })
     })
 
     window.GLOB.customMenu = config
@@ -1328,11 +1456,6 @@
       })
       return
     }
-
-    // Api.getSystemConfig({
-    //   func: 'sPC_MainMenu_Del',
-    //   MenuID: '1614740497468ku800sbg853vupf65v4'
-    // })
 
     sessionStorage.removeItem('sysRoles')
     sessionStorage.removeItem('permFuncField')
@@ -1393,7 +1516,6 @@
               duration: 5
             })
           } else {
-            sessionStorage.setItem('appHomeId', config.MenuID)
             sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
           }
         })
@@ -1403,13 +1525,13 @@
   }
 
   render () {
-    const { localedict, loading, activeKey, settingshow, controlshow, dict, MenuId, config, menuloading, customComponents } = this.state
+    const { localedict, loading, visible, popBtn, comloading, activeKey, settingshow, controlshow, dict, MenuId, config, menuloading, customComponents } = this.state
 
     return (
       <ConfigProvider locale={localedict}>
         <div className={'mk-pc-view '} id="mk-pc-design-view">
           {loading ? <Spin className="view-spin" size="large" /> : null}
-          <DndProvider backend={HTML5Backend}>
+          {!popBtn && !visible ? <DndProvider backend={HTML5Backend}>
             <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
               <div className="draw">
                 {settingshow ? <Icon onClick={() => {sessionStorage.setItem('settingshow', 'false'); this.setState({settingshow: false})}} type="double-left" /> : null}
@@ -1450,6 +1572,7 @@
               </div>
               <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button>
               <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config && config.enabled} onChange={this.onEnabledChange} />
+              <CreateView resetmenu={this.getAppMenus} />
               <PasteController type="menu" Tab={null} insert={this.insert} />
               <StyleCombControlButton menu={config} />
               <SysInterface config={config} updateConfig={this.updateConfig}/>
@@ -1457,12 +1580,15 @@
               <Quotecomponent config={config} updateConfig={this.updateConfig}/>
               <Button className="mk-border-green" icon="home" onClick={this.setHomeView}>璁句负棣栭〉</Button>
               <Button className="mk-border-danger" icon="redo" onClick={this.refreshView}>寮哄埗鍒锋柊</Button>
-              <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button>
+              <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
+              <Transfer MenuID={MenuId} />
+              <Button type="default" onClick={this.closeView}>鍏抽棴</Button>
             </div>
-            <div className={'menu-body ' + (menuloading ? 'saving' : '')}>
-              {config && config.components ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
+            <div className={'menu-body menu-view' + (menuloading ? 'saving' : '')}>
+              {config && !comloading ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
             </div>
-          </DndProvider>
+          </DndProvider> : null}
+          {popBtn && visible ? <PopviewController btn={popBtn} handleBack={this.handleBack}/> : null}
           <StyleController />
           <StyleCombController />
           <ModalController />
diff --git a/src/views/pcdesign/index.scss b/src/views/pcdesign/index.scss
index 01fc2a0..3cf126b 100644
--- a/src/views/pcdesign/index.scss
+++ b/src/views/pcdesign/index.scss
@@ -182,7 +182,7 @@
       margin: 0 auto;
     }
   }
-  .menu-body.saving {
+  .menu-body.saving, .menu-view.saving {
     .anticon-tool {
       display: none;
     }
diff --git a/src/views/pcdesign/menuform/index.jsx b/src/views/pcdesign/menuform/index.jsx
index 2335bcf..cedb3a5 100644
--- a/src/views/pcdesign/menuform/index.jsx
+++ b/src/views/pcdesign/menuform/index.jsx
@@ -69,7 +69,7 @@
                     message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.name'] + '!'
                   }
                 ]
-              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeName}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
@@ -82,7 +82,7 @@
                     message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.param'] + '!'
                   }
                 ]
-              })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeNo}/>)}
+              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
             </Form.Item>
           </Col>
           <Col span={24}>
diff --git a/src/views/printTemplate/index.jsx b/src/views/printTemplate/index.jsx
index e6e46a6..af5cce2 100644
--- a/src/views/printTemplate/index.jsx
+++ b/src/views/printTemplate/index.jsx
@@ -681,12 +681,6 @@
         } else if (res.type === 'qrcode') {
           res.url = qrurl
         } else if (res.type === 'image') {
-          if (res.value && res.value.length > 0) {
-            let url = res.value[0].url || res.value[0].response
-            res.value = url || ''
-          } else {
-            res.value = ''
-          }
           res.url = imgurl
         }
 
diff --git a/src/views/printTemplate/mutilform/index.jsx b/src/views/printTemplate/mutilform/index.jsx
index f26ae33..120c3fd 100644
--- a/src/views/printTemplate/mutilform/index.jsx
+++ b/src/views/printTemplate/mutilform/index.jsx
@@ -1,12 +1,14 @@
 import React, {Component} from 'react'
 import PropTypes from 'prop-types'
 import { is, fromJS } from 'immutable'
-import { Form, Row, Col, Input, InputNumber, Select } from 'antd'
+import { Form, Row, Col, Input, InputNumber, Select, Tooltip, Icon } from 'antd'
 import { formRule } from '@/utils/option.js'
-import FileUpload from '@/tabviews/zshare/fileupload'
+// import FileUpload from '@/tabviews/zshare/fileupload'
+import asyncComponent from '@/utils/asyncComponent'
 import './index.scss'
 
 const { TextArea } = Input
+const FileUpload = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
 
 class MainSearch extends Component {
   static propTpyes = {
@@ -52,6 +54,9 @@
           formlist: nextProps.formlist.map(item => {
             if (item.key === 'cusfield' && isCusField) {
               item.hidden = false
+            } else if (item.key === 'value' && item.type === 'fileupload') {
+              item.hidden = true
+              item.initval = fieldsvalue.value
             }
 
             return item
@@ -60,15 +65,17 @@
           if (!isCusField) {
             delete fieldsvalue.cusfield
           }
-          if (nextProps.editItem.type === 'image' && fieldsvalue.value) {
-            fieldsvalue.value = [{
-              uid: '1',
-              name: fieldsvalue.value,
-              status: 'done',
-              url: fieldsvalue.value
-            }]
-          } else if (nextProps.editItem.type === 'image') {
-            fieldsvalue.value = []
+          if (nextProps.editItem.type === 'image') {
+            this.setState({
+              formlist: this.state.formlist.map(item => {
+                if (item.key === 'value' && item.type === 'fileupload') {
+                  item.hidden = false
+                }
+    
+                return item
+              })
+            })
+            delete fieldsvalue.value
           }
 
           this.props.form.setFieldsValue(fieldsvalue)
@@ -112,19 +119,6 @@
     this.handleSubmit()
   }
 
-  updateImg = (list) => {
-    if (list && list.length > 0) {
-      let url = list[0].url || list[0].response
-      if (url) {
-        this.props.form.setFieldsValue({ value: list })
-        this.handleSubmit()
-      }
-    } else {
-      this.props.form.setFieldsValue({ value: [] })
-      this.handleSubmit()
-    }
-  }
-
   resetForm = (param) => {
     let _param = JSON.parse(JSON.stringify(param))
     delete _param.type
@@ -134,15 +128,9 @@
     if (_param.field !== 'other_field') {
       delete _param.cusfield
     }
-    if (param.type === 'image' && param.value) {
-      _param.value = [{
-        uid: '1',
-        name: param.value,
-        status: 'done',
-        url: param.value
-      }]
-    } else if (param.type === 'image') {
-      _param.value = []
+
+    if (param.type === 'image') {
+      delete _param.value
     }
 
     this.props.form.setFieldsValue(_param)
@@ -238,21 +226,16 @@
           </Col>
         )
       } else if (item.type === 'fileupload') {
-        let filelist = []
-        if (item.initval) {
-          filelist = [{
-            uid: '1',
-            name: item.initval,
-            status: 'done',
-            url: item.initval
-          }]
-        }
-
         fields.push(
           <Col span={24} key={index}>
-            <Form.Item label={item.label}>
+            <Form.Item label={
+              item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
               {getFieldDecorator(item.key, {
-                initialValue: filelist,
+                initialValue: item.initval || '',
                 rules: [
                   {
                     required: item.required,
@@ -260,7 +243,7 @@
                   }
                 ]
               })(
-                <FileUpload maxFile={1} fileType={'text'} onChange={this.updateImg} />
+                <FileUpload type="picture" placement="right" onChange={this.handleSubmit} />
               )}
             </Form.Item>
           </Col>
@@ -268,7 +251,12 @@
       } else if (item.type === 'textarea') {
         fields.push(
           <Col span={24} key={index}>
-            <Form.Item label={item.label} >
+            <Form.Item label={
+              item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}>
+                <Icon type="question-circle" />
+                {item.label}
+              </Tooltip> : item.label
+            }>
               {getFieldDecorator(item.key, {
                 initialValue: item.initval || '',
                 rules: [
@@ -298,7 +286,6 @@
         if (!err) {
           values.uuid = this.props.editItem.uuid
           values.type = this.props.editItem.type
-
           resolve(values)
         }
       })
diff --git a/src/views/printTemplate/mutilform/index.scss b/src/views/printTemplate/mutilform/index.scss
index 2b92a82..006a247 100644
--- a/src/views/printTemplate/mutilform/index.scss
+++ b/src/views/printTemplate/mutilform/index.scss
@@ -21,6 +21,20 @@
   //     width: 89.5%;
   //   }
   // }
+  .mk-source-wrap {
+    >.ant-radio-group {
+      >.ant-radio-button-wrapper:last-child {
+        display: none;
+      }
+      >.ant-radio-button-wrapper:not(:first-child) {
+        border-radius: 0 4px 4px 0;
+      }
+    }
+  }
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
   .ant-input-number {
     width: 100%;
   }
diff --git a/src/views/printTemplate/option.js b/src/views/printTemplate/option.js
index 3731a2b..1671000 100644
--- a/src/views/printTemplate/option.js
+++ b/src/views/printTemplate/option.js
@@ -795,6 +795,14 @@
       required: false
     },
     {
+      type: 'textarea',
+      key: 'productValue',
+      label: '姝e紡鍦板潃',
+      initval: item.productValue || '',
+      tooltip: '姝e紡绯荤粺浣跨敤鐨勫浘鐗囷紝涓虹┖鏃朵娇鐢ㄥ浘鐗囧湴鍧�銆�',
+      required: false
+    },
+    {
       type: 'select',
       key: 'field',
       label: '鍏宠仈瀛楁',
diff --git a/src/views/printTemplate/print.js b/src/views/printTemplate/print.js
index b2cbe6f..4247780 100644
--- a/src/views/printTemplate/print.js
+++ b/src/views/printTemplate/print.js
@@ -382,7 +382,7 @@
 
       if (image.complete) {
         context.drawImage(image, _left, _top, element.imgWidth, element.imgHeight)
-
+        
         context.restore() // 閲嶇疆鐢诲竷
         if (elements.length > 0) {
           this.sketchothers(context, elements, selectId, ratio, resolve)
@@ -401,6 +401,14 @@
           }
         }
       }
+      image.onerror = () => {
+        context.restore() // 閲嶇疆鐢诲竷
+        if (elements.length > 0) {
+          this.sketchothers(context, elements, selectId, ratio, resolve)
+        } else {
+          this.cachesketch(context, resolve)
+        }
+      }
     }
   }
 
diff --git a/src/views/rolemanage/header/index.jsx b/src/views/rolemanage/header/index.jsx
new file mode 100644
index 0000000..d49edb8
--- /dev/null
+++ b/src/views/rolemanage/header/index.jsx
@@ -0,0 +1,32 @@
+import React, {Component} from 'react'
+
+import avatar from '@/assets/img/avatar.jpg'
+import MainLogo from '@/assets/img/main-logo.png'
+import './index.scss'
+
+class AppManageHeader extends Component {
+  state = {
+    avatar: sessionStorage.getItem('CloudAvatar') || avatar,
+    userName: sessionStorage.getItem('CloudUserName')
+  }
+
+  render () {
+    const { app } = this.props
+    return (
+      <header className="app-manage-header-container">
+        <div className="header-logo"><img src={MainLogo} alt=""/></div>
+        <div className="title">
+          {`${app.remark} ${app.typename}`}
+        </div>
+        <div className="header-user">
+          <img src={this.state.avatar} alt=""/>
+          <span>
+            <span className="username">{this.state.userName}</span>
+          </span>
+        </div>
+      </header>
+    )
+  }
+}
+
+export default AppManageHeader
\ No newline at end of file
diff --git a/src/views/rolemanage/header/index.scss b/src/views/rolemanage/header/index.scss
new file mode 100644
index 0000000..84580f7
--- /dev/null
+++ b/src/views/rolemanage/header/index.scss
@@ -0,0 +1,58 @@
+.app-manage-header-container {
+  width: 100%;
+  height: 48px;
+  color: rgba(255, 255, 255, 0.65);
+  position: fixed;
+  top: 0px;
+  z-index: 10;
+  padding-right: 0px;
+  left: 0;
+  
+  background: #001529;
+  border-bottom: 1px solid #000;
+
+  .header-logo {
+    float: left;
+    width: 180px;
+    line-height: 48px;
+    text-align: center;
+    padding-left: 5px;
+    box-sizing: border-box;
+    opacity: 1;
+    img {
+      max-width: 100%;
+      max-height: 40px;
+    }
+  }
+  .header-user {
+    float: right;
+    line-height: 48px;
+    margin-right: 10px;
+    img {
+      width: 29px;
+      height: 29px;
+      border-radius: 30px;
+      margin-right: 7px;
+    }
+    span {
+      color: #ffffff;
+      font-size: 0.95rem;
+      .username {
+        display: inline-block;
+        height: 30px;
+        max-width: 95px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+      }
+    }
+  }
+  .title {
+    position: absolute;
+    left: 50%;
+    top: 10px;
+    color: #ffffff;
+    font-size: 18px;
+    transform: translateX(-50%);
+  }
+}
\ No newline at end of file
diff --git a/src/views/rolemanage/index.jsx b/src/views/rolemanage/index.jsx
new file mode 100644
index 0000000..e9164c3
--- /dev/null
+++ b/src/views/rolemanage/index.jsx
@@ -0,0 +1,813 @@
+import React, {Component} from 'react'
+import { fromJS } from 'immutable'
+import { Spin, notification, Button, Table, Modal, ConfigProvider, Tree, Input, Empty } from 'antd'
+import moment from 'moment'
+import md5 from 'md5'
+import enUS from 'antd/es/locale/en_US'
+import zhCN from 'antd/es/locale/zh_CN'
+
+import Api from '@/api'
+import Utils from '@/utils/utils.js'
+import asyncComponent from '@/utils/asyncComponent'
+import './index.scss'
+
+const { confirm } = Modal
+const { TreeNode } = Tree
+const { Search } = Input
+
+const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
+const Header = asyncComponent(() => import('./header'))
+const TransferForm = asyncComponent(() => import('@/templates/zshare/basetransferform'))
+
+sessionStorage.setItem('isEditState', 'true')
+
+class RoleManage extends Component {
+  state = {
+    app: null,
+    loading: false,
+    menulist: [],
+    columns: [
+      { title: '鑿滃崟鍚嶇О', dataIndex: 'MenuName', key: 'MenuName', align: 'center' },
+      {
+        title: '鎿嶄綔',
+        key: 'action',
+        align: 'center',
+        render: (text, record) => (
+          <div>
+            <Button type="link" onClick={() => this.deleteMenu(record)} style={{color: '#ff4d4f'}}>鍒犻櫎</Button>
+          </div>
+        ),
+      },
+    ],
+    selectApp: null,
+    selectSubApp: null,
+    visible: false,
+    thawmenulist: [],
+    confirmLoading: false,
+    targetKeys: [],
+    trees: null,
+    expandedKeys: [],
+    searchkey: ''
+  }
+
+  oriTrees = null
+
+  UNSAFE_componentWillMount() {
+    let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
+
+    this.setState({app: param}, () => {
+      this.getTreeList()
+      this.getMenuList()
+    })
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  getMenuList = (reset) => {
+    const { app } = this.state
+    let param = {
+      func: 's_get_app_menus',
+      TypeCharOne: app.kei_no,
+      typename: app.typename,
+      LText: `select '${window.GLOB.appkey}'`,
+      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+      lang: app.lang
+    }
+
+    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+    this.setState({
+      loading: true
+    })
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        this.setState({
+          menulist: result.menus.map(item => {
+            item.nodes = ''
+            item.type = 'view'
+            if (item.menus_rolelist) {
+              try {
+                let pageParam = JSON.parse(window.decodeURIComponent(window.atob(item.menus_rolelist)))
+                item.nodes = pageParam
+                if (pageParam.type === 'navbar') {
+                  item.type = 'navbar'
+                }
+              } catch {
+                item.nodes = ''
+              }
+            }
+            
+            return item
+          })
+        }, () => {
+          if (reset && (!this.oriTrees || this.oriTrees.length === 0)) {
+            this.initMenutree()
+          } else if (!reset && this.oriTrees && this.oriTrees.length === 0) {
+            this.initMenutree()
+          }
+          this.setState({loading: false})
+        })
+      } else {
+        this.setState({
+          loading: false
+        })
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  getTreeList = () => {
+    const { app } = this.state
+    let param = {
+      func: 's_get_menus_roles_tree',
+      typecharone: app.kei_no,
+      lang: app.lang
+    }
+
+    param.upid = md5(window.GLOB.appkey + app.kei_no + app.typename + app.lang)
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        if (!result.data || result.data.length === 0) {
+          this.oriTrees = []
+          if (this.state.menulist.length > 0) {
+            this.initMenutree()
+          }
+          this.setState({trees: [], loading: false})
+        } else {
+          this.oriTrees = result.data
+          this.initTrees(result.data)
+          this.setState({loading: false})
+        }
+      } else {
+        this.setState({
+          loading: false
+        })
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  initTrees = (data) => {
+    let trees = []
+    let map = new Map()
+    let _data = data.sort((a, b) => {
+      return a.sort - b.sort
+    })
+
+    _data.forEach(menu => {
+      if (menu.ParentID === 'top') {
+        trees.push({
+          key: menu.MenuID,
+          title: menu.MenuName,
+          children: []
+        })
+      } else {
+        map.set(menu.MenuID, menu)
+      }
+    })
+
+    let reset = (m) => {
+      return m.map(n => {
+        [...map.keys()].forEach(key => {
+          if (map.get(key).ParentID === n.key) {
+            let c = map.get(key)
+            n.children.push({
+              key: c.MenuID,
+              title: c.MenuName,
+              children: []
+            })
+            map.delete(key)
+          }
+        })
+        if (n.children.length > 0) {
+          n.children = reset(n.children)
+        }
+        return n
+      })
+    }
+
+    trees = reset(trees)
+
+    let expandedKeys = this.getExpandedKeys(trees, 0, [])
+
+    this.setState({trees, expandedKeys})
+  }
+
+  getExpandedKeys = (trees, i, keys) => {
+    if (i >= 3 || !trees[0]) return keys
+
+    keys.push(trees[0].key)
+
+    i++
+
+    if (trees[0].children && trees[0].children.length > 0) {
+      keys = this.getExpandedKeys(trees[0].children, i, keys)
+    }
+
+    return keys
+  }
+
+  initMenutree = (resolve) => {
+    const { menulist } = this.state
+
+    if (!menulist || menulist.length === 0) {
+      this.setState({trees: [], expandedKeys: []}, () => {
+        if (resolve) {
+          this.execSave(resolve)
+        }
+      })
+
+      return
+    }
+
+    let navbars = []
+    let map = new Map()
+
+    fromJS(menulist).toJS().forEach(menu => {
+      if (!menu.nodes) return
+      
+      if (menu.type === 'navbar') {
+        navbars.push(menu.nodes)
+      } else {
+        map.set(menu.MenuID, menu.nodes)
+      }
+    })
+
+    let data = []
+
+    if (navbars.length === 0) {
+      data = [...map.values()]
+    } else {
+      let reset = (m) => {
+        return m.map(n => {
+          if (n.children && n.children.length > 0) {
+            n.children = reset(n.children)
+          } else if (map.has(n.key)) {
+            let p = map.get(n.key)
+            if (p.children && p.children.length > 0) {
+              n.children = reset(p.children)
+            }
+            map.delete(n.key)
+          }
+          return n
+        })
+      }
+
+      data = reset(navbars)
+      data = [...data, ...map.values()]
+    }
+
+    let expandedKeys = this.getExpandedKeys(data, 0, [])
+
+    this.setState({trees: [], expandedKeys: []}, () => {
+      this.setState({trees: data, expandedKeys}, () => {
+        if (resolve) {
+          this.execSave(resolve)
+        }
+      })
+    })
+  }
+
+  getThawMenulist = () => {
+    const { app } = this.state
+
+    Api.getCloudConfig({
+      func: 'sPC_Get_FrozenMenu',
+      ParentID: 'mk_app',
+      TypeCharOne: app.kei_no,
+      typename: app.typename,
+      lang: app.lang
+    }).then(res => {
+      if (res.status) {
+        this.setState({
+          thawmenulist: res.data.map(menu => {
+            return {
+              key: menu.MenuID,
+              title: menu.MenuName
+            }
+          })
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 5
+        })
+      }
+    })
+  }
+
+  deleteMenu = (record) => {
+    const { app } = this.state
+    const _this = this
+
+    let param = {
+      func: 'sPC_MainMenu_Del',
+      MenuID: record.MenuID,
+      TypeCharOne: app.kei_no,
+      typename: app.typename,
+      lang: app.lang
+    }
+
+    if (app.typename === 'pc' && record.nodes && record.nodes.popviews && record.nodes.popviews.length > 0) {
+      param.MenuID = param.MenuID + ',' + record.nodes.popviews.join(',')
+    }
+
+    confirm({
+      content: '纭畾鍒犻櫎璇ヨ彍鍗曞悧锛�',
+      onOk() {
+        return new Promise(resolve => {
+          Api.getCloudConfig(param).then(result => {
+            if (result.status) {
+              notification.success({
+                top: 92,
+                message: '鎿嶄綔鎴愬姛锛�',
+                duration: 3
+              })
+              _this.getMenuList(true)
+            } else {
+              notification.warning({
+                top: 92,
+                message: result.message,
+                duration: 5
+              })
+            }
+            resolve()
+          }, () => {
+            resolve()
+          })
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  thawSubmit = () => {
+    const { targetKeys, app } = this.state
+
+    if (targetKeys.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '璇烽�夋嫨瑙i櫎鍐荤粨鐨勮彍鍗曪紒',
+        duration: 5
+      })
+      return
+    }
+
+    this.setState({
+      confirmLoading: true
+    })
+
+    Api.getSystemConfig({
+      func: 'sPC_MainMenu_ReDel',
+      MenuID: targetKeys.join(','),
+      TypeCharOne: app.kei_no,
+      typename: app.typename,
+      lang: app.lang
+    }).then(res => {
+      if (!res.status) {
+        notification.warning({
+          top: 92,
+          message: res.message,
+          duration: 2
+        })
+        this.setState({
+          confirmLoading: false
+        })
+      } else {
+        let param = {
+          func: 's_get_app_menus',
+          TypeCharOne: app.kei_no,
+          typename: app.typename,
+          LText: `select '${window.GLOB.appkey}'`,
+          timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
+          lang: app.lang
+        }
+
+        param.secretkey = Utils.encrypt(param.LText, param.timestamp)
+
+        Api.getCloudConfig(param).then(result => {
+          if (result.status) {
+            let list = []
+            this.setState({
+              menulist: result.menus.map(item => {
+                item.nodes = ''
+                item.type = 'view'
+                if (item.menus_rolelist) {
+                  try {
+                    let pageParam = JSON.parse(window.decodeURIComponent(window.atob(item.menus_rolelist)))
+                    item.nodes = pageParam
+                    if (pageParam.type === 'navbar') {
+                      item.type = 'navbar'
+                    }
+                  } catch {
+                    item.nodes = ''
+                  }
+                }
+
+                if (targetKeys.includes(item.MenuID) && item.nodes && item.nodes.popviews && item.nodes.popviews.length > 0) {
+                  list = [...list, ...item.nodes.popviews]
+                }
+                
+                return item
+              })
+            }, () => {
+              if (!this.oriTrees || this.oriTrees.length === 0) {
+                this.initMenutree()
+              }
+            })
+
+            if (app.typename === 'pc' && list.length > 0) {
+              Api.getSystemConfig({
+                func: 'sPC_MainMenu_ReDel',
+                MenuID: list.join(','),
+                TypeCharOne: app.kei_no,
+                typename: app.typename,
+                lang: app.lang
+              }).then(response => {
+                if (!response.status) {
+                  notification.warning({
+                    top: 92,
+                    message: response.message,
+                    duration: 2
+                  })
+                  this.setState({
+                    confirmLoading: false
+                  })
+                } else {
+                  this.setState({
+                    confirmLoading: false,
+                    visible: false,
+                    targetKeys: []
+                  })
+                }
+              })
+            } else {
+              this.setState({
+                confirmLoading: false,
+                visible: false,
+                targetKeys: []
+              })
+            }
+          } else {
+            this.setState({
+              confirmLoading: false
+            })
+            notification.warning({
+              top: 92,
+              message: result.message,
+              duration: 5
+            })
+          }
+        })
+      }
+    })
+  }
+
+  onDrop = info => {
+    const dropKey = info.node.props.eventKey
+    const dragKey = info.dragNode.props.eventKey
+    const dropPos = info.node.props.pos.split('-')
+    const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1])
+
+    const loop = (data, key, callback) => {
+      data.forEach((item, index, arr) => {
+        if (item.key === key) {
+          return callback(item, index, arr)
+        }
+        if (item.children) {
+          return loop(item.children, key, callback)
+        }
+      })
+    }
+    const data = [...this.state.trees]
+
+    let dragObj
+    loop(data, dragKey, (item, index, arr) => {
+      arr.splice(index, 1)
+      dragObj = item
+    })
+
+    if (!info.dropToGap) {
+      loop(data, dropKey, item => {
+        item.children = item.children || []
+
+        item.children.push(dragObj)
+      })
+    } else if ((info.node.props.children || []).length > 0 && info.node.props.expanded && dropPosition === 1 ) {
+      loop(data, dropKey, item => {
+        item.children = item.children || []
+
+        item.children.unshift(dragObj)
+      })
+    } else {
+      let ar;
+      let i;
+
+      loop(data, dropKey, (item, index, arr) => {
+        ar = arr
+        i = index
+      })
+
+      if (dropPosition === -1) {
+        ar.splice(i, 0, dragObj)
+      } else {
+        ar.splice(i + 1, 0, dragObj)
+      }
+    }
+
+    this.setState({
+      trees: data
+    })
+  }
+
+  renderNode = data => {
+    return data.map(item => {
+      if (item.children && item.children.length) {
+        return (
+          <TreeNode key={item.key} title={item.title}>
+            {this.renderNode(item.children)}
+          </TreeNode>
+        )
+      }
+      return <TreeNode key={item.key} title={item.title} />
+    })
+  }
+
+  initTree = () => {
+    const _this = this
+    confirm({
+      content: '鍒濆鍖栦細鏍规嵁鑿滃崟閲嶇疆鏉冮檺鏍戯紝纭畾鎵ц鍚楋紵',
+      onOk() {
+        return new Promise(resolve => {
+          _this.initMenutree(resolve)
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  syncTree = () => {
+    const _this = this
+
+    confirm({
+      content: '鍚屾浼氭牴鎹彍鍗曞垹闄ゆ垨鏂板鑺傜偣锛岀‘瀹氭墽琛屽悧锛�',
+      onOk() {
+        return new Promise(resolve => {
+          _this.syncMenutree(resolve)
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  saveTree = () => {
+    const { trees } = this.state
+    const _this = this
+
+    if (!trees || trees.length === 0) {
+      notification.warning({
+        top: 92,
+        message: '鏈幏鍙栧埌鏉冮檺淇℃伅锛�',
+        duration: 5
+      })
+      return
+    }
+
+    confirm({
+      content: '纭畾鎵ц鍚楋紵',
+      onOk() {
+        return new Promise(resolve => {
+          _this.execSave(resolve)
+        })
+      },
+      onCancel() {}
+    })
+  }
+
+  syncMenutree = (resolve) => {
+    const { menulist } = this.state
+
+    if (menulist.length === 0) {
+      this.setState({trees: [], expandedKeys: []}, () => {
+        this.execSave(resolve)
+      })
+
+      return
+    }
+
+    let navbars = []
+    let map = new Map()
+
+    fromJS(menulist).toJS().forEach(menu => {
+      if (!menu.nodes) return
+      
+      if (menu.type === 'navbar') {
+        navbars.push(menu.nodes)
+      } else {
+        map.set(menu.MenuID, menu.nodes)
+      }
+    })
+
+    let re = {}
+    this.oriTrees && this.oriTrees.forEach(item => {
+      if (item.ParentID === 'top') return
+      if (!re[item.ParentID]) {
+        re[item.ParentID] = []
+      }
+      re[item.ParentID].push(item.MenuID)
+    })
+
+    let data = []
+
+    if (navbars.length === 0) {
+      data = [...map.values()]
+    } else {
+      let reset = (m) => {
+        return m.map(n => {
+          if (n.children && n.children.length > 0) {
+            n.children = reset(n.children)
+          } else if (map.has(n.key)) {
+            let p = map.get(n.key)
+            if (p.children && p.children.length > 0) {
+              n.children = reset(p.children)
+            }
+            map.delete(n.key)
+          }
+          if (re[n.key]) {
+            n.children = n.children || []
+            re[n.key].forEach(c => {
+              if (map.has(c)) {
+                let p = map.get(c)
+                if (p.children && p.children.length > 0) {
+                  p.children = reset(p.children)
+                }
+                map.delete(c)
+                n.children.push(p)
+              }
+            })
+          }
+          return n
+        })
+      }
+
+      data = reset(navbars)
+      data = [...data, ...map.values()]
+    }
+
+    let expandedKeys = this.getExpandedKeys(data, 0, [])
+
+    this.setState({trees: [], expandedKeys: []}, () => {
+      this.setState({trees: data, expandedKeys}, () => {
+        this.execSave(resolve)
+      })
+    })
+  }
+
+  execSave = (resolve) => {
+    const { trees, app } = this.state
+
+    let lines = []
+    let i = 0
+    let reset = (m) => {
+      m.children.forEach(n => {
+        lines.push(`'${n.key}','${n.title}','${m.key}',${i}`)
+        i++
+        if (n.children) {
+          reset(n)
+        }
+      })
+    }
+
+    trees.forEach(g => {
+      lines.push(`'${g.key}','${g.title}','top',${i}`)
+      i++
+      if (g.children) {
+        reset(g)
+      }
+    })
+
+    let param = {
+      func: 's_menus_roles_tree_adduptdel',
+      typecharone: app.kei_no,
+      typename: app.typename,
+      lang: app.lang
+    }
+
+    lines = lines.join(';')
+
+    param.upid = md5(window.GLOB.appkey + param.typecharone + param.typename + param.lang)
+    param.menus_roles_longtext = window.btoa(window.encodeURIComponent(lines))
+
+    Api.getCloudConfig(param).then(result => {
+      if (result.status) {
+        notification.success({
+          top: 92,
+          message: '鎿嶄綔鎴愬姛锛�',
+          duration: 3
+        })
+      } else {
+        notification.warning({
+          top: 92,
+          message: result.message,
+          duration: 5
+        })
+      }
+      resolve()
+    }, () => {
+      resolve()
+    })
+  }
+
+  triggerThaw = () => {
+    this.getThawMenulist()
+    this.setState({ visible: true, targetKeys: [] })
+  }
+
+  render () {
+    const { app, loading, columns, menulist, trees, searchkey } = this.state
+    let _menulist = menulist
+
+    if (searchkey) {
+      _menulist = _menulist.filter(item => item.MenuName.toLowerCase().indexOf(searchkey.toLowerCase()) > -1)
+    }
+
+    return (
+      <div className="mk-role-manage">
+        <ConfigProvider locale={_locale}>
+          <Header app={app} />
+          {loading ?
+            <div className="loading-mask">
+              <Spin size="large" />
+            </div> : null
+          }
+          <div className="view-wrap">
+            <div className="left-view">
+              <div className="app-table">
+                <div className="app-action">
+                  <Button className="mk-green" onClick={this.triggerThaw}>瑙e喕鑿滃崟</Button>
+                  <Search placeholder="缁煎悎鎼滅储" onSearch={value => this.setState({ searchkey: value })} enterButton />
+                </div>
+                <Table
+                  rowKey="MenuID"
+                  columns={columns}
+                  dataSource={_menulist}
+                  pagination={false}
+                />
+              </div>
+            </div>
+            <div className="right-view">
+              <div className="app-action">
+                <Button className="mk-primary" onClick={this.initTree}>鍒濆鍖�</Button>
+                <Button className="mk-purple" onClick={this.syncTree}>鍚屾</Button>
+                <Button className="mk-green save" onClick={this.saveTree}>淇濆瓨</Button>
+              </div>
+              {trees && trees.length ? <Tree
+                className="draggable-tree"
+                defaultExpandedKeys={this.state.expandedKeys}
+                // showLine
+                draggable
+                blockNode
+                onDrop={this.onDrop}
+              >
+                {this.renderNode(trees)}
+              </Tree> : <div className="empty">
+                <Empty />
+              </div>}
+            </div>
+          </div>
+          <Modal
+            title="瑙i櫎鍐荤粨"
+            visible={this.state.visible}
+            width={600}
+            onOk={this.thawSubmit}
+            confirmLoading={this.state.confirmLoading}
+            onCancel={() => this.setState({visible: false, targetKeys: []})}
+            destroyOnClose
+          >
+            <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>
+          </Modal>
+        </ConfigProvider>
+      </div>
+    )
+  }
+}
+
+export default RoleManage
\ No newline at end of file
diff --git a/src/views/rolemanage/index.scss b/src/views/rolemanage/index.scss
new file mode 100644
index 0000000..277ceb0
--- /dev/null
+++ b/src/views/rolemanage/index.scss
@@ -0,0 +1,90 @@
+.mk-role-manage {
+  background: #fff;
+  min-height: 100vh;
+  padding: 70px 30px;
+
+  .loading-mask {
+    position: fixed;
+    top: 0px;
+    bottom: 0px;
+    left: 0px;
+    right: 0px;
+    z-index: 2;
+    background: rgba(255, 255, 255, 0.35);
+
+    .ant-spin {
+      position: absolute;
+      left: 50%;
+      top: 50%;
+    }
+  }
+  .mob-header-container {
+    padding-right: 0px;
+    z-index: 10;
+    left: 0;
+  }
+  .view-wrap {
+    width: 100%;
+    position: relative;
+    display: flex;
+
+    .left-view {
+      flex: 1;
+      width: 50%;
+      padding-right: 5px;
+      .ant-table-tbody > tr > td {
+        padding: 8px 16px;
+      }
+    }
+    .right-view {
+      width: 50%;
+      padding-left: 20px;
+
+      .draggable-tree {
+        border: 1px solid #e8e8e8;
+        padding: 10px 10px 30px;
+        min-height: 400px;
+        border-radius: 4px;
+        .ant-tree-title {
+          max-width: 100%;
+          display: inline-block;
+          overflow: hidden;
+          white-space: nowrap;
+          text-overflow: ellipsis;
+        }
+      }
+      .empty {
+        border: 1px solid #e8e8e8;
+        padding: 100px 10px 30px;
+        min-height: 400px;
+        border-radius: 4px;
+      }
+    }
+  }
+  .ant-table-wrapper {
+    .ant-table-body {
+      border: 1px solid #e8e8e8;
+      border-bottom: 0;
+      border-radius: 4px;
+    }
+    .ant-table-tbody {
+      > tr.ant-table-row-selected td {
+        background: #bae7ff;
+      }
+    }
+  }
+  .app-action {
+    >button {
+      margin-bottom: 10px;
+      margin-right: 15px;
+    }
+    .ant-input-search {
+      width: 250px;
+      float: right;
+    }
+    .save {
+      float: right;
+      margin-right: 0px;
+    }
+  }
+}

--
Gitblit v1.8.0