king
2023-12-14 0eb129a9beddbb86ae74d7106a8e60823206b8d5
2023-12-14
160个文件已修改
5个文件已添加
8122 ■■■■■ 已修改文件
public/README.txt 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/manifest.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/media/excel.png 补丁 | 查看 | 原始文档 | blame | 历史
public/media/pdf.png 补丁 | 查看 | 原始文档 | blame | 历史
public/media/rar.png 补丁 | 查看 | 原始文档 | blame | 历史
public/media/txt.png 补丁 | 查看 | 原始文档 | blame | 历史
public/media/word.png 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/viewstyle.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.jsx 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkRadio/index.jsx 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkSelect/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/action.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/options.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/double-data-card/options.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/doublecardcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/doublecardcomponent/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-G6/chartcompile/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-X6/chartcompile/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx 452 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/index.jsx 757 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/index.scss 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/index.jsx 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/chartcompile/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-scatter/chartcompile/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/code/sandbox/editorcode/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/dragtitle/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/actionform/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/formconfig.jsx 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/options.jsx 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.jsx 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/options.jsx 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.jsx 56 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 117 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/markcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/index.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/options.jsx 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/options.jsx 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/timeline/normal-timeline/options.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/customscript/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/versions/index.jsx 190 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/versions/index.scss 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.jsx 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.scss 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/prop-card/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 585 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-pie/index.jsx 232 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/code/sand-box/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/editor/braft-editor/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/simple-form/index.jsx 106 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/step-form/index.jsx 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/step-form/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/tab-form/index.jsx 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.jsx 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx 73 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.jsx 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.scss 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/tabs/antv-tabs/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/tabs/antv-tabs/index.scss 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/timeline/normal-timeline/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/timeline/normal-timeline/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtabtable/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/excelInbutton/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/newpagebutton/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 675 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/tabbutton/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/fileupload/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/fileupload/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 104 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkInput/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkNumberInput/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkSelect/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkVercode/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/mkSelect/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 750 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 214 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 40 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/chartcomponent/chartcompile/formconfig.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 589 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/treepageconfig/index.jsx 444 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/codemirror/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/baseform/index.jsx 125 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/billcodeform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/callbackcustomscript/index.jsx 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/contrastform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/fullScripts/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/fullScripts/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 87 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/uniqueform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 65 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-datamanage.js 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/billprint/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/interface/history/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/menuform/index.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rolemanage/index.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rolemanage/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/index.jsx 31 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/README.txt
@@ -17,4 +17,5 @@
probation         -- 试用期(YYYY-MM-DD),在正式系统中,试用期内调用系统接口的脚本会记录下来
transfer          -- 是否使用转接口,使用转接口时请设置为 true, 使用转接口时,外部接口调用前不会做登录验证
keepPassword      -- 记住密码,默认开启,当值为 false 时禁用
updateStatus      -- 是否更新开发状态,默认开启,当值为 false 时禁用
platforms         -- 移动端可使用的平台类型,默认为 ["H5", "wechat", "android", "ios", "wxMiniProgram"] 分别代表H5页面、微信公众号、安卓APP、苹果APP、微信小程序
public/manifest.json
@@ -6,5 +6,5 @@
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "mk_version": "20230712"
  "mk_version": "20231201"
}
public/media/excel.png
public/media/pdf.png
public/media/rar.png
public/media/txt.png
public/media/word.png
src/api/index.js
@@ -420,7 +420,7 @@
  }
  /**
   * @description 获取系统版本信息,启用或更新websql
   * @description 获取系统版本信息
   */
  getAppVersion (reload) {
    if (!window.GLOB.IndexDB) {
@@ -918,9 +918,6 @@
      param.fullname = sessionStorage.getItem('Full_Name') || ''
    }
    let login = false
    let rduri = null
    if (param.rduri && /\s|\n/.test(param.rduri)) {
      param.rduri = param.rduri.replace(/\s|\n/g, '')
      if (!param.rduri) {
@@ -928,31 +925,32 @@
      }
    }
    if (param.$login && !window.GLOB.transfer) {
      login = true
      rduri = param.rduri || ''
    }
    delete param.$login
    if (param.$login) {
      let rduri = param.rduri || ''
    let url = '/webapi/dostars'
    if (param.rduri && !window.GLOB.transfer && /\/dostars/.test(param.rduri) && param.func !== 'webapi_ChangeUser') {
      url = param.rduri
      delete param.$login
      delete param.rduri
    }
    param = this.encryptParam(param)
      param = this.encryptParam(param)
    if (login) {
      let time = +sessionStorage.getItem(rduri)
      let c_time = Math.round(new Date().getTime() / 1000)
      if (time && c_time - time <= 1800) {
        sessionStorage.setItem(rduri, c_time)
        return axios({
          url: `${url}${param.func ? '/' + param.func : ''}`,
          method: 'post',
          data: JSON.stringify(param)
        return new Promise((resolve, reject) => {
          axios({
            url: `${rduri}${param.func ? '/' + param.func : ''}`,
            method: 'post',
            data: JSON.stringify(param)
          }).then(result => {
            if (result && result.ErrCode === 'LoginError') {
              sessionStorage.removeItem(rduri)
            }
            resolve(result)
          }, () => {
            reject()
          })
        })
      }
@@ -961,11 +959,13 @@
          if (res.status) {
            sessionStorage.setItem(rduri, c_time)
            axios({
              url: `${url}${param.func ? '/' + param.func : ''}`,
              url: `${rduri}${param.func ? '/' + param.func : ''}`,
              method: 'post',
              data: JSON.stringify(param)
            }).then(result => {
              resolve(result)
            }, () => {
              reject()
            })
          } else {
            resolve(res)
@@ -984,6 +984,14 @@
        })
      })
    } else {
      let url = '/webapi/dostars'
      if (param.rduri && !window.GLOB.transfer && /\/dostars/.test(param.rduri) && param.func !== 'webapi_ChangeUser') {
        url = param.rduri
        delete param.rduri
      }
      param = this.encryptParam(param)
      return axios({
        url: `${url}${param.func ? '/' + param.func : ''}`,
        method: 'post',
src/assets/css/main.scss
@@ -535,9 +535,19 @@
    background: var(--mk-sys-color5);
  }
  .ant-calendar-today .ant-calendar-date {
    color: var(--mk-sys-color);
    border-color: var(--mk-sys-color);
  .ant-calendar-today:not(.ant-calendar-disabled-cell) {
    .ant-calendar-date {
      color: var(--mk-sys-color);
      border-color: var(--mk-sys-color4);
    }
  }
  .ant-calendar-today.ant-calendar-disabled-cell {
    .ant-calendar-date {
      color: var(--mk-sys-color);
    }
    .ant-calendar-date::before {
      border-color: var(--mk-sys-color4);
    }
  }
  .ant-calendar-header a:hover {
@@ -727,6 +737,10 @@
.ant-col.ant-col-0 {
  display: inline-block;
}
.mk-cell-btn.ant-col-0 {
  width: auto;
  float: left;
}
.ant-dropdown {
  .ant-dropdown-menu-item:hover, .ant-dropdown-menu-submenu-title:hover {
src/assets/css/viewstyle.scss
@@ -41,6 +41,17 @@
        }
      }
    }
    .data-zoom.radio.deepBackFont, .data-zoom.checkbox.deepBackFont {
      .mk-card:hover, .mk-card.active, .mk-card.selected {
        > .card-item-box {
          border-color: $color6!important;
          background-color: $color6!important;
          .ant-mk-text:not(.sign-font) {
            color: #ffffff;
          }
        }
      }
    }
    .data-zoom.radio.font, .data-zoom.checkbox.font {
      .mk-card:hover, .mk-card.active, .mk-card.selected {
        > .card-item-box {
src/components/normalform/modalform/index.jsx
@@ -7,6 +7,7 @@
import asyncComponent from '@/utils/asyncComponent'
import MKEInput from './mkInput'
import MKNumberInput from './mkNumberInput'
import MKEmitter from '@/utils/events.js'
import MKSelect from './mkSelect'
import './index.scss'
@@ -17,14 +18,16 @@
const MKCheckbox = asyncComponent(() => import('./mkCheckbox'))
const StyleInput = asyncComponent(() => import('./styleInput'))
const MKFileUpload = asyncComponent(() => import('@/tabviews/zshare/fileupload'))
const MKColor = asyncComponent(() => import('@/tabviews/zshare/mutilform/mkColor'))
const MKColor = asyncComponent(() => import('@/mob/colorsketch'))
// const MKColor = asyncComponent(() => import('@/tabviews/zshare/mutilform/mkColor'))
const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
class ModalForm extends Component {
  static propTpyes = {
    formlist: PropTypes.array,   // 表单列表
    inputSubmit: PropTypes.func  // input回车提交
    formlist: PropTypes.array,
    inputSubmit: PropTypes.func,
    transVals: PropTypes.func,
  }
  state = {
@@ -70,7 +73,7 @@
          required: item.required,
          message: item.label + '不可为空!'
        }, {
          validator: (rule, value, callback) => this.handleConfirmPassword(rule, value, callback, item)
          validator: (rule, value, callback) => this.checkNumber(rule, value, callback, item)
        }]
      } else if (item.type === 'textarea') {
        item.rules = [
@@ -108,7 +111,7 @@
      let supItem = fieldMap.get(key)
      let supval = supItem.initval
      if (supItem.initval && supItem.type !== 'checkbox' && JSON.stringify(supItem.initval) === '[]') {
      if (supval && JSON.stringify(supval) === '[]') {
        supval = ''
      }
@@ -124,13 +127,13 @@
        } else if (supItem.hidden) {
          cell.hidden = true
        } else if (supItem.type === 'checkbox') {
          let vals = [...supval, ...item.values]
        } else if (item.notNull) {
          cell.hidden = !supval
        } else if (supItem.type === 'checkbox' || supItem.type === 'multiselect') {
          let vals = [...(supval || []), ...item.values]
          if (vals.length === new Set(vals).size) {
            cell.hidden = true
          }
        } else if (item.notNull) {
          cell.hidden = !supval
        } else if (!item.values.includes(supval)) {
          cell.hidden = true
        }
@@ -162,7 +165,7 @@
    this.setState({ formlist })
  }
  handleConfirmPassword = (rule, value, callback, item) => {
  checkNumber = (rule, value, callback, item) => {
    let val = parseFloat(value)
    if (!isNaN(val)) {
@@ -179,6 +182,10 @@
    this.record = {...this.record, ...values}
    if (!item) return
    if (item.$trans) {
      this.props.transVals && this.props.transVals(values, item.field)
    }
    
    if (item.controlFields) {
      let map = new Map()
@@ -190,7 +197,7 @@
      let reset = (current) => {
        let val = this.record[current.field]
        if (val && current.type !== 'checkbox' && JSON.stringify(val) === '[]') {
        if (val && JSON.stringify(val) === '[]') {
          val = ''
        }
@@ -199,15 +206,15 @@
          if (current.hidden) {
            m.hidden = true
          } else if (current.type === 'checkbox') {
            let vals = [...val, ...cell.values]
          } else if (cell.notNull) {
            m.hidden = !val
          } else if (current.type === 'checkbox' || current.type === 'multiselect') {
            let vals = [...(val || []), ...cell.values]
            if (vals.length !== new Set(vals).size) {
              m.hidden = false
            } else {
              m.hidden = true
            }
          } else if (cell.notNull) {
            m.hidden = !val
          } else {
            m.hidden = !cell.values.includes(val)
          }
@@ -248,7 +255,7 @@
        map.set(cell.field, cell)
      })
      item.callback(map, this.record)
      item.callback(map, this.record, MKEmitter)
      this.setState({
        formlist: this.state.formlist.map(cell => {
@@ -281,7 +288,7 @@
      } else if (item.type === 'select' || item.type === 'multiselect') {
        content = (<MKSelect config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} />)
      } else if (item.type === 'color') {
        content = (<MKColor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
        content = (<MKColor config={item} allowClear={item.allowClear} onChange={(val) => this.recordChange({[item.field]: val})}/>)
      } else if (item.type === 'styleInput') {
        content = (<StyleInput config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
      } else if (item.type === 'radio') {
src/components/normalform/modalform/index.scss
@@ -42,6 +42,7 @@
    overflow: hidden;
    .color-sketch-block-box {
      min-width: 50px;
      max-width: 100px;
      .color-sketch-block-inner {
        box-shadow: 0 0 0 1px rgba(0, 0, 0, .1) inset;
      }
src/components/normalform/modalform/mkRadio/index.jsx
@@ -19,10 +19,22 @@
  componentDidMount () {
    MKEmitter.addListener('mkFP', this.mkFormHandle)
    MKEmitter.addListener('mkFC', this.mkFormControl)
  }
  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 () {
@@ -30,6 +42,16 @@
      return
    }
    MKEmitter.removeListener('mkFP', this.mkFormHandle)
    MKEmitter.removeListener('mkFC', this.mkFormControl)
  }
  mkFormControl = (type, field, value) => {
    if (field !== this.props.config.field) return
    if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, {})
    }
  }
  mkFormHandle = (field, parentId) => {
@@ -45,7 +67,7 @@
      value: val
    })
    this.props.onChange(val)
    this.props.onChange(val, {})
    config.linkFields && config.linkFields.forEach((m, i) => {
      setTimeout(() => {
src/components/normalform/modalform/mkSelect/index.jsx
@@ -159,8 +159,8 @@
        filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
        onChange={this.mutilselectChange}
      >
        {options.map(option =>
          <Select.Option key={option.value} disabled={option.disabled} value={option.value}>{option.label || option.text}</Select.Option>
        {options.map((option, i) =>
          <Select.Option key={i} disabled={option.disabled} value={option.value || option.field}>{option.label || option.text}</Select.Option>
        )}
      </Select>)
    }
src/index.js
@@ -70,6 +70,7 @@
    GLOB.mkHS = false
    GLOB.debugger = false
    GLOB.dataFormat = false
    GLOB.upStatus = false
    GLOB.navBar = 'shutter' // 默认为百叶窗
    GLOB.style = 'bg_black_style_blue'
@@ -107,6 +108,7 @@
      GLOB.probation = true
      GLOB.debugger = true
      GLOB.systemType = ''
      GLOB.upStatus = config.updateStatus + '' !== 'false'
      GLOB.mainSystemApi = 'https://cloud.positecgroup.com/webapi/dostars'
src/menu/components/card/balcony/index.jsx
@@ -249,6 +249,9 @@
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
        _card.setting = { interType: 'system' }
        _card.scripts = []
      }
    }
src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -79,7 +79,7 @@
    _style_ = {float: 'right'}
  }
  let className = card.width || ''
  let className = card.width || 0
  if (card.hidden === 'true') {
    className += ' mk-hidden'
  }
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -60,6 +60,7 @@
  let linkTypes = [
    { value: 'tel', text: '电话' },
    { value: 'email', text: '邮箱' },
    { value: 'download', text: '下载' },
    { value: 'other', text: '其他' }
  ]
@@ -69,6 +70,7 @@
      { value: 'email', text: '邮箱' },
      { value: 'qywx', text: '企业微信' },
      { value: 'linkmenu', text: '关联菜单' },
      { value: 'download', text: '下载' },
      { value: 'other', text: '其他' }
    ]
  } else if (appType === 'pc') {
@@ -76,6 +78,7 @@
      { value: 'tel', text: '电话' },
      { value: 'email', text: '邮箱' },
      { value: 'linkmenu', text: '关联菜单' },
      { value: 'download', text: '下载' },
      { value: 'other', text: '其他' }
    ]
  }
src/menu/components/card/cardcellcomponent/index.jsx
@@ -311,7 +311,7 @@
      }
    }
    let modules = MenuUtils.getSubModules(window.GLOB.customMenu.components, cards.uuid, supId)
    let modules = MenuUtils.getSubModules(window.GLOB.customMenu.components, cards.uuid, supId, true)
    if (cards.subtype === 'basetable') {
      this.setState({
@@ -449,21 +449,36 @@
              res.style = {}
            }
          } else if (res.class !== cell.class || res.show !== cell.show || !res.style) {
            let cl = res.class.replace('border-', '')
            let style = {}
            if (res.class === 'default') {
              style.color = 'rgba(0, 0, 0, 0.65)'
              style.backgroundColor = '#fff'
              style.borderColor = '#d9d9d9'
            } else if (res.class.indexOf('border') > -1) {
              style.color = color[cl]
              style.backgroundColor = '#fff'
              style.borderColor = color[cl]
            if (res.class) {
              let cl = res.class.replace('border-', '')
              let style = {}
              if (res.class === 'default') {
                style.color = 'rgba(0, 0, 0, 0.65)'
                style.backgroundColor = 'transparent'
                style.borderColor = '#d9d9d9'
              } else if (res.class.indexOf('border') > -1) {
                style.color = color[cl]
                style.backgroundColor = 'transparent'
                style.borderColor = color[cl]
              } else {
                style.color = '#ffffff'
                style.backgroundColor = color[cl]
              }
              res.style = {...res.style, ...style}
            } else {
              style.color = '#ffffff'
              style.backgroundColor = color[cl]
              res.style = res.style || {}
            }
            res.style = {...res.style, ...style}
          }
          if (res.width === 0 && cell.width !== 0) {
            res.style = res.style || {}
            res.style.paddingLeft = '15px'
            res.style.paddingRight = '15px'
            res.style.marginRight = '15px'
            res.style.width = 'auto'
            delete res.style.marginLeft
          }
          res.updateTime = moment().format('YYYY-MM-DD HH:mm')
src/menu/components/card/cardcomponent/index.jsx
@@ -157,7 +157,7 @@
    const { card, side } = this.state
    let _style = null
    let options = ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear']
    let options = ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'clear', 'overflow']
    if (side === 'front') {
      _style = card.style ? fromJS(card.style).toJS() : {}
    } else if (side === 'back') {
src/menu/components/card/cardcomponent/options.jsx
@@ -258,7 +258,7 @@
      field: 'btnControl',
      label: '按钮控制',
      initval: setting.btnControl || 'show',
      tooltip: '可设置按钮显示规则,一直显示或鼠标悬浮时显示。',
      tooltip: '可设置按钮显示规则,始终显示或鼠标悬浮时显示。',
      required: false,
      options: [
        {value: 'show', label: '正常显示'},
src/menu/components/card/data-card/options.jsx
@@ -267,7 +267,8 @@
      options: [
        {value: 'none', label: '无'},
        {value: 'active', label: '外阴影'},
        {value: 'backFont', label: '背景+文字'},
        {value: 'backFont', label: '背景(浅)+文字(深)'},
        {value: 'deepBackFont', label: '背景(深)+文字(浅)'},
        {value: 'font', label: '文字'},
        {value: 'tabs', label: '标签页'},
        ...(subtype === 'datacard' ? [
@@ -607,6 +608,19 @@
      forbid: !!appType || isprint
    },
    {
      type: 'radio',
      field: 'shifting',
      label: '按钮偏移',
      initval: wrap.shifting || 'false',
      tooltip: '启用时,工具栏按钮将显示在标题栏右上角。',
      required: false,
      options: [
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !!appType || subtype !== 'datacard' || isprint
    },
    {
      type: 'multiselect',
      field: 'blacklist',
      label: '黑名单',
src/menu/components/card/double-data-card/options.jsx
@@ -251,6 +251,19 @@
      forbid: !!appType || isprint
    },
    {
      type: 'radio',
      field: 'shifting',
      label: '按钮偏移',
      initval: wrap.shifting || 'false',
      tooltip: '启用时,工具栏按钮将显示在标题栏右上角。',
      required: false,
      options: [
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !!appType || isprint
    },
    {
      type: 'multiselect',
      field: 'blacklist',
      label: '黑名单',
src/menu/components/card/doublecardcomponent/index.jsx
@@ -122,7 +122,7 @@
    const { card } = this.state
    let _style = null
    let options = ['height', 'background', 'border', 'padding', 'margin', 'shadow']
    let options = ['height', 'background', 'border', 'padding', 'margin', 'shadow', 'overflow']
    if (type === 'sub') {
      _style = fromJS(card.backStyle).toJS()
src/menu/components/card/doublecardcomponent/options.jsx
@@ -191,7 +191,7 @@
      field: 'btnControl',
      label: '按钮控制',
      initval: setting.btnControl || 'show',
      tooltip: '可设置按钮显示规则,一直显示或鼠标悬浮时显示。',
      tooltip: '可设置按钮显示规则,始终显示或鼠标悬浮时显示。',
      required: false,
      options: [
        {value: 'show', label: '正常显示'},
src/menu/components/card/prop-card/index.jsx
@@ -330,6 +330,9 @@
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
        _card.setting = { interType: 'system' }
        _card.scripts = []
      }
    }
src/menu/components/chart/antv-G6/chartcompile/index.jsx
@@ -19,7 +19,7 @@
  }
  state = {
    view: 'normal',
    view: 'base',
    visible: false,
    plot: null,
    formlist: null,
@@ -31,7 +31,7 @@
    this.setState({
      visible: true,
      view: 'normal',
      view: 'base',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot, config.columns),
      formlist: getOptionForm(config.plot, config.columns)
src/menu/components/chart/antv-X6/chartcompile/index.jsx
@@ -19,7 +19,7 @@
  }
  state = {
    view: 'normal',
    view: 'base',
    visible: false,
    plot: null,
    formlist: null,
@@ -31,7 +31,7 @@
    this.setState({
      visible: true,
      view: 'normal',
      view: 'base',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot, config.columns),
      formlist: getOptionForm(config.plot, config.uuid)
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
@@ -46,78 +46,77 @@
  return [
    {
      type: 'text',
      key: 'title',
      field: 'title',
      label: '标题',
      initVal: card.title,
      initval: card.title,
      required: false
    },
    {
      type: 'text',
      key: 'name',
      field: 'name',
      label: '组件名称',
      initVal: card.name,
      initval: card.name,
      tooltip: '用于组件间的区分。',
      required: true
    },
    {
      type: 'number',
      key: 'width',
      field: 'width',
      label: '宽度',
      initVal: card.width,
      initval: card.width,
      tooltip: '栅格布局,每行等分为24列。',
      min: 1,
      max: 24,
      decimal: 0,
      precision: 0,
      required: true
    },
    {
      type: 'styleInput',
      key: 'height',
      field: 'height',
      label: '图表高度',
      initVal: card.height,
      initval: card.height,
      tooltip: '图表绘图区域的高度,不包括标题及内外边距。',
      required: true,
      options: ['px', 'vh', 'vw']
    },
    {
      type: 'radio',
      key: 'permission',
      field: 'permission',
      label: '权限验证',
      initVal: card.permission || 'false',
      initval: card.permission || 'false',
      required: false,
      options: [
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType || ispop || isprint
    },
    {
      type: 'radio',
      key: 'cacheLocal',
      field: 'cacheLocal',
      label: '本地缓存',
      initVal: card.cacheLocal || 'true',
      initval: card.cacheLocal || 'true',
      required: false,
      options: [
        {value: 'true', text: '继承菜单'},
        {value: 'false', text: '禁用'},
        {value: 'true', label: '继承菜单'},
        {value: 'false', label: '禁用'},
      ],
      forbid: ispop || isprint
    },
    {
      type: 'select',
      key: 'blacklist',
      type: 'multiselect',
      field: 'blacklist',
      label: '黑名单',
      initVal: card.blacklist || [],
      multi: true,
      initval: card.blacklist || [],
      required: false,
      options: roleList,
      forbid: !!appType || isprint
    },
    {
      type: 'radio',
      key: 'click',
      field: 'click',
      label: '点击事件',
      initVal: card.click || '',
      initval: card.click || '',
      tooltip: '点击柱子时触发的事件,启用自定义设置时无效。',
      required: false,
      forbid: appType === 'mob' || card.chartType !== 'bar',
@@ -125,13 +124,20 @@
        {value: '', label: '数据切换'},
        {value: 'menu', label: '菜单'},
        {value: 'menus', label: '菜单组'}
      ],
      controlFields: [
        {field: 'menu', values: ['menu']},
        {field: 'open', values: ['menu', 'menus']},
        {field: 'joint', values: ['menu', 'menus']},
        {field: 'menuType', values: ['menus']},
        {field: 'menus', values: ['menus']},
      ]
    },
    {
      type: appType === '' ? 'cascader' : 'select',
      key: 'menu',
      field: 'menu',
      label: '关联菜单',
      initVal: card.menu || (appType === '' ? [] : ''),
      initval: card.menu || (appType === '' ? [] : ''),
      tooltip: '在使用柱形图且未启用自定义设置时有效。',
      required: true,
      forbid: appType === 'mob' || card.chartType !== 'bar',
@@ -140,9 +146,9 @@
    },
    {
      type: 'select',
      key: 'menuType',
      field: 'menuType',
      label: '菜单类型',
      initVal: card.menuType || '',
      initval: card.menuType || '',
      required: true,
      forbid: appType === 'mob' || card.chartType !== 'bar',
      hidden: card.click !== 'menus',
@@ -150,9 +156,9 @@
    },
    {
      type: 'radio',
      key: 'open',
      field: 'open',
      label: '打开方式',
      initVal: card.open || 'blank',
      initval: card.open || 'blank',
      required: false,
      options: [
        {value: 'blank', label: '新窗口'},
@@ -163,9 +169,9 @@
    },
    {
      type: 'radio',
      key: 'joint',
      field: 'joint',
      label: '参数拼接',
      initVal: card.joint || 'true',
      initval: card.joint || 'true',
      required: false,
      options: [
        {value: 'true', label: '是'},
@@ -176,9 +182,9 @@
    },
    {
      type: 'table',
      key: 'menus',
      field: 'menus',
      label: '菜单组',
      initVal: card.menus || [],
      initval: card.menus || [],
      required: true,
      span: 24,
      actions: ['view'],
@@ -234,10 +240,11 @@
    shapes = [
      { field: 'rect', label: 'rect(矩形)' },
      { field: 'hollow-rect', label: 'hollow-rect(空心矩形)' },
      { field: 'line', label: 'line(线条)' },
      { field: 'tick', label: 'tick(波动)' },
      // { field: 'funnel', label: 'funnel' },
      { field: 'pyramid', label: 'pyramid(角锥)' }
      // { field: 'hollow', label: 'hollow(空心矩形)' },
      // { field: 'line', label: 'line(线条)' },
      // { field: 'tick', label: 'tick(波动)' },
      // { field: 'funnel', label: 'funnel(漏斗图)' },
      { field: 'pyramid', label: 'pyramid(金字塔)' }
    ]
  }
@@ -246,68 +253,92 @@
  let labelOptions = [{
    value: 'false',
    text: '隐藏'
    label: '隐藏'
  }, {
    value: 'true',
    text: '显示'
    label: '显示'
  }]
  if (card.chartType === 'bar') {
    labelOptions[1].text = '外部'
    labelOptions[1].label = '外部'
    labelOptions.push(...[{
      value: 'top',
      text: '顶部'
      label: '顶部'
    }, {
      value: 'middle',
      text: '中间'
      label: '中间'
    }, {
      value: 'bottom',
      text: '底部'
      label: '底部'
    }])
  }
  let _label = card.label || 'false'
  let axis = []
  if (card.grid !== 'hidden') {
    axis.push('grid')
  }
  if (card.x_line !== 'hidden') {
    axis.push('x_line')
  }
  if (card.y_line !== 'hidden') {
    axis.push('y_line')
  }
  if (card.tick !== 'hidden') {
    axis.push('tick')
  }
  let tickVals = []
  if (card.x_label !== 'hidden') {
    tickVals.push('x_label')
  }
  if (card.y_label !== 'hidden') {
    tickVals.push('y_label')
  }
  return [
    {
      type: 'radio',
      key: 'datatype',
      field: 'datatype',
      label: '数据类型',
      initVal: card.datatype || 'query',
      initval: card.datatype || 'query',
      tooltip: '统计图表适用于展示数据类型为动态值。',
      required: false,
      $trans: true,
      options: [
        { value: 'query', text: '查询' },
        { value: 'statistics', text: '统计' }
        { value: 'query', label: '查询' },
        { value: 'statistics', label: '统计' }
      ],
      controlFields: [
        {field: 'InfoType', values: ['statistics']},
        {field: 'InfoValue', values: ['statistics']},
        {field: 'Yaxis', values: ['query']},
      ]
    }, {
      type: 'select',
      key: 'Xaxis',
      field: 'Xaxis',
      label: 'X-轴',
      initVal: card.Xaxis || '',
      initval: card.Xaxis || '',
      required: true,
      options: xfields
    }, {
      type: 'select',
      key: 'InfoType',
      field: 'InfoType',
      label: '类型',
      initVal: card.InfoType || '',
      hidden: card.datatype !== 'statistics',
      initval: card.InfoType || '',
      required: true,
      options: xfields
    }, {
      type: 'select',
      key: 'InfoValue',
      field: 'InfoValue',
      label: '值',
      initVal: card.InfoValue || '',
      hidden: card.datatype !== 'statistics',
      initval: card.InfoValue || '',
      required: true,
      options: yfields
    }, {
      type: 'select',
      key: 'legend',
      field: 'legend',
      label: '图例位置',
      initVal: card.legend || 'bottom',
      initval: card.legend || 'bottom',
      required: false,
      options: [
        { field: 'bottom', label: '下' },
@@ -325,310 +356,325 @@
        { field: 'hidden', label: '隐藏' }
      ]
    }, {
      type: 'select',
      key: 'Yaxis',
      type: 'multiselect',
      field: 'Yaxis',
      label: 'Y-轴',
      initVal: card.Yaxis || [],
      multi: true, // 多选
      hidden: card.datatype === 'statistics',
      initval: card.Yaxis || [],
      required: true,
      options: yfields
    }, {
      type: 'select',
      key: 'shape',
      field: 'shape',
      label: '形状',
      initVal: card.shape || (shapes[0] && shapes[0].field),
      initval: card.shape || (shapes[0] && shapes[0].field),
      required: false,
      options: shapes
    }, {
      type: 'radio',
      key: 'tooltip',
      field: 'tooltip',
      label: '悬浮提示',
      initVal: card.tooltip || 'true',
      initval: card.tooltip || 'true',
      required: false,
      options: [{
        value: 'true',
        text: '显示'
        label: '显示'
      }, {
        value: 'false',
        text: '隐藏'
        label: '隐藏'
      }]
    }, {
      type: 'radio',
      key: 'point',
      field: 'point',
      label: '点图',
      initVal: card.point || 'false',
      initval: card.point || 'false',
      required: false,
      forbid: !['line'].includes(card.chartType),
      options: [{
        value: 'true',
        text: '显示'
        label: '显示'
      }, {
        value: 'false',
        text: '隐藏'
        label: '隐藏'
      }]
    }, {
      type: 'radio',
      key: 'transpose',
      field: 'transpose',
      label: '变换',
      initVal: card.transpose || 'false',
      initval: card.transpose || 'false',
      tooltip: '横纵坐标轴交换',
      forbid: card.chartType === 'line',
      required: false,
      options: [{
        value: 'true',
        text: '是'
        label: '是'
      }, {
        value: 'false',
        text: '否'
        label: '否'
      }]
    }, {
      type: 'radio',
      key: 'show',
      field: 'show',
      label: '显示',
      initVal: card.show || 'value',
      initval: card.show || 'value',
      tooltip: '当使用自定义设置时,可在显示(值/%)处单独设置显示类型。注:自定义为空时使用此处设置。',
      required: false,
      options: [{
        value: 'value',
        text: '数值'
        label: '数值'
      }, {
        value: 'percent',
        text: '百分比'
        label: '百分比'
      }, {
        value: 'thdSeparator',
        label: '千分位'
      }]
    }, {
      type: labelOptions.length > 20 ? 'select' : 'radio',
      key: 'label',
      type: 'radio',
      field: 'label',
      label: '标注',
      initVal: _label,
      initval: card.label || 'false',
      tooltip: '图形节点处的数值。',
      required: false,
      options: labelOptions
      options: labelOptions,
      controlFields: [
        {field: 'labelColor', values: ['true']}
      ]
    }, {
      type: 'radio',
      key: 'labelColor',
      field: 'labelColor',
      label: '标注颜色',
      initVal: card.labelColor || 'system',
      initval: card.labelColor || 'system',
      tooltip: '使用系统色时,使用色系选项设置的系统颜色,使用自定义为颜色设置中定义的图形颜色。',
      required: false,
      hidden: _label !== 'true',
      options: [{
        value: 'system',
        text: '系统'
        label: '系统'
      }, {
        value: 'custom',
        text: '自定义'
        label: '自定义'
      }]
    // }, {
    //   type: 'radio',
    //   field: 'labelValue',
    //   label: '标注值',
    //   initval: card.labelValue || 'default',
    //   tooltip: '标注值的显示规则。',
    //   required: false,
    //   options: [{
    //     value: 'default',
    //     label: '默认'
    //   }, {
    //     value: 'zero',
    //     label: '隐藏 0 值'
    //   }],
    }, {
      type: 'radio',
      key: 'labelValue',
      label: '标注值',
      initVal: card.labelValue || 'default',
      tooltip: '标注值的显示规则。',
      required: false,
      hidden: _label === 'false',
      options: [{
        value: 'default',
        text: '默认'
      }, {
        value: 'zero',
        text: '隐藏 0 值'
      }],
    }, {
      type: 'radio',
      key: 'adjust',
      field: 'adjust',
      label: '多柱排列',
      initVal: card.adjust || 'dodge',
      initval: card.adjust || 'dodge',
      required: false,
      forbid: !['bar'].includes(card.chartType),
      options: [{
        value: 'dodge',
        text: '分组'
        label: '分组'
      }, {
        value: 'stack',
        text: '堆叠'
        label: '堆叠'
      }]
    }, {
      type: 'radio',
      key: 'area',
      field: 'area',
      label: '面积图',
      initVal: card.area || 'false',
      // tooltip: '仅在形状为smooth时有效。',
      initval: card.area || 'false',
      required: false,
      forbid: ['bar'].includes(card.chartType),
      options: [{
        value: 'true',
        text: '显示'
        label: '显示'
      }, {
        value: 'false',
        text: '不显示'
        label: '不显示'
      }]
    }, {
      type: 'radio',
      key: 'repeat',
      label: '重复数据',
      initVal: card.repeat || 'unrepeat',
      required: false,
      options: [{
        value: 'unrepeat',
        text: '去重'
      }, {
        value: 'average',
        text: '平均'
      }, {
        value: 'cumsum',
        text: '累加'
      }]
    }, {
      type: 'radio',
      key: 'coordinate',
      field: 'coordinate',
      label: '坐标',
      initVal: card.coordinate || 'angle',
      initval: card.coordinate || 'angle',
      required: false,
      forbid: card.chartType === 'line',
      options: [{
        value: 'angle',
        text: '二维坐标'
        label: '二维坐标'
      }, {
        value: 'polar',
        text: '极坐标'
        label: '极坐标'
      }]
    }, {
      type: 'radio',
      key: 'grid',
      label: '网格线',
      initVal: card.grid || 'show',
      type: 'checkbox',
      field: 'axis',
      label: '坐标轴',
      initval: axis,
      required: false,
      options: [{
        value: 'show',
        text: '显示'
        value: 'grid',
        label: '网格线'
      }, {
        value: 'hidden',
        text: '隐藏'
      }]
        value: 'x_line',
        label: 'X轴'
      }, {
        value: 'y_line',
        label: 'Y轴'
      }, {
        value: 'tick',
        label: '刻度线'
      }],
      controlFields: [
        {field: 'lineColor', notNull: true},
      ]
    }, {
      type: 'radio',
      key: 'y_line',
      label: 'y轴边线',
      initVal: card.y_line || 'hidden',
      tooltip: '图形左侧或右侧的边线。',
      type: 'checkbox',
      field: 'tickVals',
      label: '刻度值',
      initval: tickVals,
      required: false,
      options: [{
        value: 'show',
        text: '显示'
        value: 'x_label',
        label: 'X轴'
      }, {
        value: 'hidden',
        text: '隐藏'
      }]
        value: 'y_label',
        label: 'Y轴'
      }],
      controlFields: [
        {field: 'color', notNull: true},
      ]
    // }, {
    //   type: 'radio',
    //   field: 'grid',
    //   label: '网格线',
    //   initval: card.grid || 'show',
    //   required: false,
    //   options: [{
    //     value: 'show',
    //     label: '显示'
    //   }, {
    //     value: 'hidden',
    //     label: '隐藏'
    //   }]
    // }, {
    //   type: 'radio',
    //   field: 'y_line',
    //   label: 'y轴边线',
    //   initval: card.y_line || 'hidden',
    //   tooltip: '图形左侧或右侧的边线。',
    //   required: false,
    //   options: [{
    //     value: 'show',
    //     label: '显示'
    //   }, {
    //     value: 'hidden',
    //     label: '隐藏'
    //   }]
    }, {
      type: 'radio',
      key: 'download',
      field: 'download',
      label: '导出图片',
      initVal: card.download || 'forbid',
      initval: card.download || 'forbid',
      required: false,
      forbid: appType === 'mob',
      options: [{
        value: 'forbid',
        text: '禁用'
        label: '禁用'
      }, {
        value: 'enable',
        text: '启用'
        label: '启用'
      }]
    }, {
      type: 'radio',
      key: 'empty',
      field: 'empty',
      label: '空值隐藏',
      initVal: card.empty || 'show',
      initval: card.empty || 'show',
      tooltip: '当查询数据为空时,隐藏该组件。',
      required: false,
      options: [
        {value: 'show', text: '否'},
        {value: 'hidden', text: '是'},
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
    }, {
      type: 'number',
      key: 'barSize',
      field: 'barSize',
      label: '柱形宽度',
      tooltip: '空值时,宽度自适应。',
      min: 5,
      max: 100,
      decimal: 0,
      initVal: card.barSize,
      max: 200,
      precision: 0,
      initval: card.barSize,
      forbid: !['bar'].includes(card.chartType),
      required: false
    }, {
      type: 'number',
      key: 'barRadius',
      field: 'barRadius',
      label: '柱形圆角',
      tooltip: '柱形图上端圆角。',
      min: 0,
      max: 200,
      decimal: 0,
      initVal: card.barRadius || 0,
      precision: 0,
      initval: card.barRadius || 0,
      forbid: !['bar'].includes(card.chartType),
      required: false
    }, {
      type: 'number',
      key: 'min',
      field: 'min',
      label: '最小值',
      tooltip: 'y轴最小值,为空时自适应。',
      initVal: card.min,
      initval: card.min,
      required: false
    }, {
      type: 'number',
      key: 'max',
      field: 'max',
      label: '最大值',
      tooltip: 'y轴最大值,为空时自适应。',
      initVal: card.max,
      initval: card.max,
      required: false
    }, {
      type: 'number',
      key: 'XLimit',
      field: 'XLimit',
      min: 2,
      label: '字符限制',
      tooltip: 'X轴最大字符限制。',
      initVal: card.XLimit || 11,
      initval: card.XLimit || 11,
      forbid: appType === 'mob',
      required: false
    }, {
      type: 'color',
      key: 'color',
      label: '色系',
      initVal: card.color || 'rgba(0, 0, 0, 0.65)',
      tooltip: '坐标轴提示文字及示例的颜色。',
      required: false
    }, {
      type: 'color',
      key: 'lineColor',
      label: '轴线颜色',
      initVal: card.lineColor,
      tooltip: '坐标轴线的颜色,包括x轴、y轴及网格线。',
      field: 'lineColor',
      label: '坐标轴颜色',
      initval: card.lineColor || '',
      tooltip: '坐标轴线的颜色,包括x轴、y轴、网格线、刻度线。',
      allowClear: true,
      required: false
    }, {
      type: 'color',
      key: 'selectColor',
      label: '选中颜色',
      initVal: card.selectColor || '',
      tooltip: '选中柱形图的颜色,在交互效果《元素选中(多选)》和《元素选中(单选)》中有效,启用自定义设置时无效。',
      forbid: !['bar'].includes(card.chartType),
      field: 'color',
      label: '刻度值颜色',
      initval: card.color || '',
      allowClear: true,
      required: false
    }, {
      type: 'number',
      key: 'rotate',
      field: 'rotate',
      label: '旋转',
      tooltip: '坐标轴标注文本的旋转角度。',
      min: 0,
      max: 360,
      decimal: 0,
      initVal: card.rotate,
      precision: 0,
      initval: card.rotate,
      forbid: appType !== 'mob',
      required: false
    }, {
      type: 'select',
      key: 'interaction',
      type: 'multiselect',
      field: 'interaction',
      label: '交互效果',
      initVal: card.interaction || [],
      multi: true,
      initval: card.interaction || [],
      required: false,
      forbid: appType === 'mob',
      options: [
@@ -644,7 +690,19 @@
        { value: 'legend-active', label: '图例聚焦' },
        { value: 'legend-highlight', label: '图例高亮' },
        { value: 'brush', label: '选框过滤' },
      ],
      controlFields: [
        {field: 'selectColor', values: ['element-selected', 'element-single-selected']},
      ]
    }, {
      type: 'color',
      field: 'selectColor',
      label: '选中颜色',
      initval: card.selectColor || '',
      tooltip: '选中柱形图的颜色,启用自定义设置时无效。',
      forbid: !['bar'].includes(card.chartType),
      allowClear: true,
      required: false
    }
  ]
}
src/menu/components/chart/antv-bar/chartcompile/index.jsx
@@ -1,19 +1,18 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
import { QuestionCircleOutlined, EditOutlined, PlusOutlined } from '@ant-design/icons'
import { fromJS } from 'immutable'
import { Modal, Form, Col, Radio, notification, Tabs, Button } from 'antd'
import { EditOutlined, PlusOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
import { chartColors } from '@/utils/option.js'
import { getBaseForm, getOptionForm } 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'))
const ModalForm = asyncComponent(() => import('@/components/normalform/modalform'))
class LineChartDrawerForm extends Component {
  static propTpyes = {
@@ -23,8 +22,7 @@
  }
  state = {
    view: 'normal',
    ramp: 'false',
    view: 'base',
    visible: false,
    datatype: '',
    plot: null,
@@ -137,12 +135,89 @@
        }
      },
    ],
    cusColumns: [
    cusColumns: []
  }
  showDrawer = () => {
    const { config } = this.props
    let fieldName = {}
    config.columns.forEach(col => {
      if (col.field) {
        fieldName[col.field] = col.label
      }
    })
    let plot = fromJS(config.plot).toJS()
    if (plot.datatype !== 'statistics') {
      if (plot.colors) {
        plot.colors = plot.colors.map(item => {
          if (fieldName[item.type]) {
            item.label = fieldName[item.type]
          }
          return item
        })
      }
      if (plot.customs) {
        plot.customs = plot.customs.map(item => {
          if (fieldName[item.type]) {
            item.name = fieldName[item.type]
          }
          return item
        })
      }
    }
    if (!plot.zoomYaxis && plot.customs) {
      plot.customs.forEach(item => {
        if (item.min || item.min === 0) {
          plot.zoomYaxis = 'custom'
        } else if (item.max || item.max === 0) {
          plot.zoomYaxis = 'custom'
        }
      })
    }
    plot.zoomYaxis = plot.zoomYaxis || 'default'
    this.setState({
      visible: true,
      view: 'base',
      datatype: plot.datatype || 'query',
      fieldName: fieldName,
      plot: plot,
      baseFormlist: getBaseForm(plot, config.columns),
      formlist: getOptionForm(plot, config.columns),
      cusColumns: this.getCusColumns(plot.zoomYaxis)
    })
  }
  optionChange = (val, key) => {
    let _plot = {...this.state.plot, [key]: val}
    if (key === 'ramp' && val === 'true') {
      _plot.colors = _plot.colors || []
      _plot.colors = _plot.colors.map(item => {
        item.color1 = item.color1 || item.color
        return item
      })
    }
    this.setState({plot: _plot}, () => {
      if (key === 'zoomYaxis') {
        this.setState({cusColumns: this.getCusColumns(val)})
      }
    })
  }
  getCusColumns = (zoomYaxis) => {
    let cusColumns = [
      {
        title: '指标',
        dataIndex: 'name',
        editable: false,
        width: '14%'
        width: '12%'
      },
      {
        title: '形状',
@@ -158,26 +233,26 @@
            value: 'line',
            label: '折线',
            children: [
              { value: 'smooth', label: 'smooth' },
              { value: 'line', label: 'line' },
              { value: 'dot', label: 'dot' },
              { value: 'dash', label: 'dash' },
              { value: 'hv', label: 'hv' },
              { value: 'vh', label: 'vh' },
              { value: 'hvh', label: 'hvh' },
              { value: 'vhv', label: 'vhv' }
              { value: 'smooth', label: 'smooth(平滑线)' },
              { value: 'line', label: 'line(直线)' },
              { value: 'dot', label: 'dot(点状线)' },
              { value: 'dash', label: 'dash(虚线)' },
              { value: 'hv', label: 'hv(水平-垂直线)' },
              { value: 'vh', label: 'vh(垂直-水平线)' },
              { value: 'hvh', label: 'hvh(水平-垂直-水平线)' },
              { value: 'vhv', label: 'vhv(垂直-水平-垂直线)' }
            ]
          },
          {
            value: 'bar',
            label: '柱形',
            children: [
              { value: 'rect', label: 'rect' },
              { value: 'hollow-rect', label: 'hollow-rect' },
              { value: 'line', label: 'line' },
              { value: 'tick', label: 'tick' },
              { value: 'funnel', label: 'funnel' },
              { value: 'pyramid', label: 'pyramid' }
              { value: 'rect', label: 'rect(矩形)' },
              { value: 'hollow-rect', label: 'hollow-rect(空心矩形)' },
              // { value: 'line', label: 'line(线条)' },
              // { value: 'tick', label: 'tick(波动)' },
              // { value: 'funnel', label: 'funnel(漏斗图)' },
              { value: 'pyramid', label: 'pyramid(金字塔)' }
            ],
          }
        ]
@@ -209,7 +284,7 @@
        ],
        render: (text, record) => {
          let trans = {'true': '显示', 'false': '隐藏'}
          return trans[text] || '隐藏'
          return trans[text] || ''
        }
      },
      {
@@ -237,10 +312,11 @@
        width: '12%',
        options: [
          { value: 'value', text: '数值'},
          { value: 'percent', text: '百分比'}
          { value: 'percent', text: '百分比'},
          { value: 'thdSeparator', text: '千分位'}
        ],
        render: (text, record) => {
          let trans = {'value': '数值', 'percent': '百分比'}
          let trans = {value: '数值', percent: '百分比', thdSeparator: '千分位'}
          return trans[text] || ''
        }
      },
@@ -249,6 +325,7 @@
        dataIndex: 'min',
        inputType: 'number',
        editable: true,
        max: 9999999999,
        required: false,
        width: '12%'
      },
@@ -257,267 +334,21 @@
        dataIndex: 'max',
        inputType: 'number',
        editable: true,
        max: 9999999999,
        required: false,
        width: '12%'
      },
    ]
  }
  showDrawer = () => {
    const { config } = this.props
    let fieldName = {}
    config.columns.forEach(col => {
      if (col.field) {
        fieldName[col.field] = col.label
      }
    })
    let plot = fromJS(config.plot).toJS()
    if (plot.correction) {
      delete plot.correction // 数据修正(已弃用)
      plot.barSize = 35
    }
    if (plot.datatype !== 'statistics') {
      if (plot.colors) {
        plot.colors = plot.colors.map(item => {
          if (fieldName[item.type]) {
            item.label = fieldName[item.type]
          }
          return item
        })
      }
      if (plot.customs) {
        plot.customs = plot.customs.map(item => {
          if (fieldName[item.type]) {
            item.name = fieldName[item.type]
          }
          return item
        })
      }
    }
    this.setState({
      visible: true,
      view: 'normal',
      ramp: plot.ramp || 'false',
      datatype: plot.datatype || 'query',
      fieldName: fieldName,
      plot: plot,
      baseFormlist: getBaseForm(plot, config.columns),
      formlist: getOptionForm(plot, config.columns)
    })
  }
  radioChange = (e, key) => {
    const { formlist } = this.state
    let val = e.target.value
    if (key === 'datatype') {
      this.setState({
        datatype: val,
        formlist: fromJS(formlist).toJS().map(item => {
          if (['Yaxis'].includes(item.key)) {
            item.hidden = val === 'statistics'
          } else if (['InfoType', 'InfoValue'].includes(item.key)) {
            item.hidden = val !== 'statistics'
          }
          return item
        })
      })
    } else if (key === 'label') {
      this.setState({formlist: fromJS(formlist).toJS().map(cell => {
        if (!['labelColor', 'labelValue'].includes(cell.key)) return cell
        if (cell.key === 'labelColor') {
          if (val !== 'true') {
            cell.hidden = true
          } else {
            cell.hidden = false
          }
        } else {
          if (val === 'false') {
            cell.hidden = true
          } else {
            cell.hidden = false
          }
        }
        return cell
      })})
    }
  }
  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}>
                <QuestionCircleOutlined className="mk-form-tip" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: '请输入' + 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}>
                <QuestionCircleOutlined className="mk-form-tip" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: '请输入' + 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}>
                <QuestionCircleOutlined className="mk-form-tip" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: '请选择' + 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}>
                <QuestionCircleOutlined className="mk-form-tip" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [
                  {
                    required: !!item.required,
                    message: '请选择' + item.label + '!'
                  }
                ]
              })(
                <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>
                    )
                  })}
                </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}>
                <QuestionCircleOutlined className="mk-form-tip" />
                {item.label}
              </Tooltip> : item.label
            }>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal
              })(
                <ColorSketch allowClear={item.allowClear} />
              )}
            </Form.Item>
          </Col>
        )
      }
    })
    return fields
  }
  enabledChange = (e) => {
    const { plot } = this.state
    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
    if (zoomYaxis !== 'custom') {
      cusColumns.pop()
      cusColumns.pop()
      cusColumns.forEach(item => {
        item.width = '16%'
      })
    }
    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}})
    return cusColumns
  }
  onSubmit = () => {
@@ -525,90 +356,26 @@
    const { plot, view } = this.state
    if (view === 'normal') {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let _plot = {...plot, ...values}
      this.normalRef.handleConfirm().then(values => {
        let _plot = {...plot, ...values}
          if (values.datatype !== plot.datatype) {
            _plot.colors = null
          }
          if (values.datatype === 'statistics') {
            _plot.enabled = 'false'
            _plot.customs = []
            delete _plot.Yaxis
          } else if (!is(fromJS(values.Yaxis), fromJS(plot.Yaxis || []))) {
            _plot.enabled = 'false'
            _plot.colors = null
            let labels = {}
            config.columns.forEach(col => {
              labels[col.field] = col.label
            })
            let cus = {}
            _plot.customs && _plot.customs.forEach(m => {
              cus[m.type] = m
            })
            _plot.customs = _plot.Yaxis.map((item, i) => {
              if (cus[item]) return cus[item]
              return {
                uuid: Utils.getuuid(),
                type: item,
                name: labels[item] || item,
                axis: i === 0 ? 'true' : 'false',
                label: 'false',
                title: 'true',
                shape: _plot.chartType === 'bar' && i === 0 ? ['bar', 'rect'] : ['line', 'smooth']
              }
            })
          }
          this.setState({
            plot: _plot,
            visible: false
          })
          this.props.plotchange({...config, plot: _plot})
        if (_plot.datatype !== plot.datatype) {
          _plot.colors = null
        }
        this.resetPlot(_plot)
        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}
        if (res.click === 'menu') {
          delete _plot.menus
        } else if (res.click === 'menus') {
          delete _plot.menu
        } else {
          delete _plot.menus
          delete _plot.menu
        }
        delete _plot.MenuID
        delete _plot.MenuName
        delete _plot.MenuNo
        delete _plot.tabType
        if (_plot.click === 'menu' && sessionStorage.getItem('appType') === '' && _plot.menu) {
          let list = null
          try {
            list = JSON.parse(sessionStorage.getItem('thdMenuList')) || []
          } catch (e) {
            list = []
          }
          let id = _plot.menu[_plot.menu.length - 1]
          list.forEach(item => {
            if (item.MenuID === id) {
              _plot.MenuID = id
              _plot.MenuName = item.MenuName
              _plot.MenuNo = item.MenuNo
              _plot.tabType = item.type
            }
          })
        }
        this.resetBase(_plot)
        this.setState({
          plot: _plot,
@@ -626,109 +393,40 @@
  }
  changeTab = (tab) => {
    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.normalRef.handleConfirm().then(values => {
        let _plot = {...plot, ...values}
          let labels = {}
          config.columns.forEach(col => {
            labels[col.field] = col.label
          })
          if (values.datatype !== plot.datatype) {
            _plot.colors = null
          }
          if (values.datatype === 'statistics') {
            _plot.enabled = 'false'
            _plot.customs = []
            delete _plot.Yaxis
          } else if (!is(fromJS(values.Yaxis), fromJS(plot.Yaxis || []))) {
            _plot.enabled = 'false'
            _plot.colors = null
            let cus = {}
            _plot.customs && _plot.customs.forEach(m => {
              cus[m.type] = m
            })
            _plot.customs = _plot.Yaxis.map((item, i) => {
              if (cus[item]) return cus[item]
              return {
                uuid: Utils.getuuid(),
                type: item,
                name: labels[item] || item,
                axis: i === 0 ? 'true' : 'false',
                label: 'false',
                title: 'true',
                shape: _plot.chartType === 'bar' && i === 0 ? ['bar', 'rect'] : ['line', 'smooth']
              }
            })
          }
          if (!_plot.colors) {
            _plot.colors = []
            if (_plot.datatype === 'query') {
              let limit = chartColors.length
              _plot.colors = _plot.Yaxis.map((item, i) => {
                return {
                  uuid: Utils.getuuid(),
                  type: item,
                  label: labels[item] || item,
                  color: chartColors[i % limit],
                  color1: chartColors[i % limit]
                }
              })
            }
          }
          this.setState({
            datatype: _plot.datatype,
            plot: _plot,
            view: tab
          })
        if (_plot.datatype !== plot.datatype) {
          _plot.colors = null
        }
        this.resetPlot(_plot)
        this.setState({
          plot: _plot,
          view: tab
        })
      })
    } else if (view === 'base') {
      this.baseRef.handleConfirm().then(res => {
        let _plot = {...plot, ...res}
        if (res.click === 'menu') {
          delete _plot.menus
        } else if (res.click === 'menus') {
          delete _plot.menu
        } else {
          delete _plot.menus
          delete _plot.menu
        }
        this.resetBase(_plot)
        delete _plot.MenuID
        delete _plot.MenuName
        delete _plot.MenuNo
        delete _plot.tabType
        if (_plot.click === 'menu' && sessionStorage.getItem('appType') === '' && _plot.menu) {
          let list = null
          try {
            list = JSON.parse(sessionStorage.getItem('thdMenuList')) || []
          } catch (e) {
            list = []
          }
          let id = _plot.menu[_plot.menu.length - 1]
          list.forEach(item => {
            if (item.MenuID === id) {
              _plot.MenuID = id
              _plot.MenuName = item.MenuName
              _plot.MenuNo = item.MenuNo
              _plot.tabType = item.type
            }
        if (!plot.Xaxis && (tab === 'color' || tab === 'custom')) {
          this.setState({
            plot: _plot,
            view: 'normal'
          })
          notification.warning({
            top: 92,
            message: '请添加图表设置。',
            duration: 3
          })
          return
        }
        this.setState({
@@ -741,6 +439,130 @@
        view: tab
      })
    }
  }
  resetBase = (_plot) => {
    if (_plot.click === 'menu') {
      delete _plot.menus
      delete _plot.menuType
    } else if (_plot.click === 'menus') {
      delete _plot.menu
    } else {
      delete _plot.menus
      delete _plot.menu
      delete _plot.menuType
    }
    delete _plot.MenuID
    delete _plot.MenuName
    delete _plot.MenuNo
    delete _plot.tabType
    if (_plot.click === 'menu' && sessionStorage.getItem('appType') === '' && _plot.menu) {
      let list = null
      try {
        list = JSON.parse(sessionStorage.getItem('thdMenuList')) || []
      } catch (e) {
        list = []
      }
      let id = _plot.menu[_plot.menu.length - 1]
      list.forEach(item => {
        if (item.MenuID === id) {
          _plot.MenuID = id
          _plot.MenuName = item.MenuName
          _plot.MenuNo = item.MenuNo
          _plot.tabType = item.type
        }
      })
    }
  }
  resetPlot = (_plot) => {
    const { config } = this.props
    if (_plot.axis) {
      _plot.grid = _plot.axis.includes('grid') ? 'show' : 'hidden'
      _plot.x_line = _plot.axis.includes('x_line') ? 'show' : 'hidden'
      _plot.y_line = _plot.axis.includes('y_line') ? 'show' : 'hidden'
      _plot.tick = _plot.axis.includes('tick') ? 'show' : 'hidden'
      delete _plot.axis
    }
    if (_plot.tickVals) {
      _plot.x_label = _plot.tickVals.includes('x_label') ? 'show' : 'hidden'
      _plot.y_label = _plot.tickVals.includes('y_label') ? 'show' : 'hidden'
      delete _plot.tickVals
    }
    if (_plot.datatype === 'statistics') {
      _plot.enabled = 'false'
      _plot.customs = []
      _plot.colors = _plot.colors || []
      delete _plot.Yaxis
    } else if (_plot.Yaxis) {
      delete _plot.InfoType
      delete _plot.InfoValue
      let yaxis = JSON.parse(JSON.stringify(_plot.Yaxis))
      let caxis = _plot.customs ? _plot.customs.map(m => m.type) : []
      yaxis.sort()
      caxis.sort()
      if (JSON.stringify(yaxis) !== JSON.stringify(caxis)) {
        let labels = {}
        config.columns.forEach(col => {
          labels[col.field] = col.label
        })
        let cus = {}
        _plot.customs && _plot.customs.forEach(m => {
          cus[m.type] = m
        })
        _plot.customs = _plot.Yaxis.map((item, i) => {
          if (cus[item]) return cus[item]
          return {
            uuid: Utils.getuuid(),
            type: item,
            name: labels[item] || item,
            axis: i === 0 ? 'true' : 'false',
            label: _plot.label === 'false' ? 'false' : true,
            title: 'true',
            shape: _plot.chartType === 'bar' && i === 0 ? ['bar', 'rect'] : ['line', 'smooth']
          }
        })
        let cusColor = {}
        let limit = chartColors.length
        _plot.colors && _plot.colors.forEach(m => {
          cusColor[m.type] = m
        })
        _plot.colors = _plot.Yaxis.map((item, i) => {
          if (cusColor[item]) return cusColor[item]
          return {
            uuid: Utils.getuuid(),
            type: item,
            label: labels[item] || item,
            color: chartColors[i % limit],
            color1: chartColors[i % limit]
          }
        })
      }
    }
  }
  transVals = (values, key) => {
    if (key !== 'datatype') return
    this.setState({
      datatype: values.datatype
    })
  }
  addColor = () => {
@@ -789,7 +611,7 @@
  render() {
    const { config } = this.props
    const { view, visible, datatype, plot, ramp, colorColumns, barColorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist } = this.state
    const { view, visible, datatype, plot, colorColumns, barColorColumns, rampColorColumns, statColorColumns, rampStatColorColumns, cusColumns, baseFormlist, formlist } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -807,28 +629,26 @@
        <Modal
          wrapClassName="mk-pop-modal"
          visible={visible}
          width={1000}
          width={1200}
          maskClosable={false}
          onOk={this.onSubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          {config.name ? <div className="mk-com-name">{config.name} - 编辑</div> : null}
          <Tabs activeKey={view} className="menu-chart-edit-box" onChange={this.changeTab}>
          <Tabs activeKey={view} className="menu-chart-line-edit-box" onChange={this.changeTab}>
            <TabPane tab="组件设置" key="base">
              <NormalForm formlist={baseFormlist} inputSubmit={this.onSubmit} wrappedComponentRef={(inst) => this.baseRef = inst}/>
              <ModalForm formlist={baseFormlist} inputSubmit={this.onSubmit} wrappedComponentRef={(inst) => this.baseRef = inst}/>
            </TabPane>
            <TabPane tab="图表设置" key="normal">
              <Form {...formItemLayout}>
                <Row gutter={16}>{this.getFields()}</Row>
              </Form>
              <ModalForm formlist={formlist} inputSubmit={this.onSubmit} transVals={this.transVals} wrappedComponentRef={(inst) => this.normalRef = inst}/>
            </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.Group value={plot.ramp || 'false'} onChange={(e) => this.optionChange(e.target.value, 'ramp')}>
                        <Radio value="false">不使用</Radio>
                        <Radio value="true">使用</Radio>
                      </Radio.Group>
@@ -838,7 +658,7 @@
                {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.Group value={plot.rampDirection || 'horizontal'} onChange={(e) => this.optionChange(e.target.value, 'rampDirection')}>
                        <Radio value="horizontal">水平</Radio>
                        <Radio value="vertical">垂直</Radio>
                      </Radio.Group>
@@ -846,30 +666,30 @@
                  </Form>
                </Col> : null}
                {datatype === 'statistics' ? <Button className="color-add mk-green" onClick={this.addColor}>添加</Button> : null}
                {datatype === 'statistics' ? <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={ramp ==='true' ? rampStatColorColumns : statColorColumns} onChange={this.changeColor}/> : null}
                {datatype !== 'statistics' ? <EditTable actions={['edit']} data={plot.colors || []} columns={ramp ==='true' ? rampColorColumns : colorColumns} onChange={this.changeColor}/> : null}
                {datatype === 'statistics' ? <EditTable actions={['edit', 'move', 'del']} data={plot.colors || []} columns={plot.ramp ==='true' ? rampStatColorColumns : statColorColumns} onChange={this.changeColor}/> : null}
                {datatype !== 'statistics' ? <EditTable actions={['edit']} data={plot.colors || []} columns={plot.ramp ==='true' ? rampColorColumns : colorColumns} onChange={this.changeColor}/> : null}
                {plot.chartType === 'bar' && plot.datatype === 'query' ? <div className="mk-bar-colors">
                  <p>柱形颜色:可根据柱图序号设置颜色(请设置柱形宽度)。注:使用自定义图形设置或多根柱图时无效。</p>
                  <p>柱形颜色:可根据柱图序号设置颜色。注:使用自定义图形设置或多根柱图时无效。</p>
                  <div className="bar-color-add"><PlusOutlined onClick={this.addbarColor}/></div>
                  <EditTable actions={['edit', 'move', 'del']} data={plot.barcolors || []} columns={barColorColumns} onChange={this.changebarColor}/>
                </div> : null}
              </div>
            </TabPane> : null}
            {plot ? <TabPane tab="自定义图形设置" disabled={datatype === 'statistics'} key="custom">
              <Col span={12}>
              <Col span={8}>
                <Form {...formItemLayout}>
                  <Form.Item label="是否启用" style={{marginBottom: 10}}>
                    <Radio.Group value={plot.enabled || 'false'} onChange={this.enabledChange}>
                    <Radio.Group value={plot.enabled || 'false'} onChange={(e) => this.optionChange(e.target.value, 'enabled')}>
                      <Radio value="true">是</Radio>
                      <Radio value="false">否</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Form>
              </Col>
              <Col span={12}>
              <Col span={8}>
                <Form {...formItemLayout}>
                  <Form.Item label="多柱排列" style={{marginBottom: 10}}>
                    <Radio.Group value={plot.mutilBar || 'dodge'} onChange={this.mutilBarChange}>
                    <Radio.Group value={plot.mutilBar || 'dodge'} onChange={(e) => this.optionChange(e.target.value, 'mutilBar')}>
                      <Radio value="dodge">分组</Radio>
                      <Radio value="stack">堆叠</Radio>
                      <Radio value="overlap">重叠</Radio>
@@ -877,6 +697,17 @@
                  </Form.Item>
                </Form>
              </Col>
              <Col span={8}>
                <Form {...formItemLayout}>
                  <Form.Item label="Y轴区间" style={{marginBottom: 10}}>
                    <Radio.Group value={plot.zoomYaxis} onChange={(e) => this.optionChange(e.target.value, 'zoomYaxis')}>
                      <Radio value="default">默认</Radio>
                      <Radio value="custom">自定义</Radio>
                      <Radio value="adjust">自适应</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Form>
              </Col>
              <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>注:使用自定义设置时,显示的坐标轴第一个在左侧,第二个在右侧,多余的不生效。</Col>
              <EditTable indexShow={false} actions={['edit', 'move']} data={plot.customs || []} columns={cusColumns} onChange={this.changeCustom}/>
            </TabPane> : null}
src/menu/components/chart/antv-bar/chartcompile/index.scss
@@ -4,14 +4,9 @@
    color: #1890ff;
  }
}
.menu-chart-edit-box {
.menu-chart-line-edit-box {
  .ant-radio-wrapper {
    margin-right: 5px;
  }
  .color-sketch-block {
    position: relative;
    top: 5px;
    width: 240px;
  }
  .color-add {
    float: right;
src/menu/components/chart/antv-bar/index.jsx
@@ -87,8 +87,14 @@
      this.updateComponent(_card, true)
    } else {
      let _card = fromJS(card).toJS()
      if (_card.plot.correction) {
        delete _card.plot.correction // 数据修正(已弃用)
        _card.plot.barSize = 35
      }
      this.setState({
        card: fromJS(card).toJS()
        card: _card
      })
    }
  }
@@ -550,7 +556,8 @@
      })
    }
    if (!plot.legend || plot.legend === 'hidden') {
    let noLegend = !plot.legend || plot.legend === 'hidden'
    if (noLegend) {
      chart.legend(false)
    } else {
      chart.legend({
@@ -580,6 +587,29 @@
        fill: '#fff'
      }
    }
    let label = plot.label
    if (Bar_axis.length) {
      if (label === 'false') {
        plot.customs.forEach(item => {
          if (!Bar_axis.includes(item.type)) return
          if (item.label === 'true') {
            label = 'true'
          }
        })
      } else {
        let reset = true
        plot.customs.forEach(item => {
          if (!Bar_axis.includes(item.type)) return
          if (item.label === 'true') {
            reset = false
          }
        })
        if (reset) {
          label = 'false'
        }
      }
    }
    if (plot.label === 'top') {
      lablecfg.offset = -5
@@ -604,6 +634,10 @@
      })
      const dst = new DataSet()
      const dvt = dst.createView().source(data)
      // if (plot.mutilBar === 'stack') {
      //   Bar_axis.reverse()
      // }
  
      dvt.transform({
        type: 'fold',
@@ -643,7 +677,9 @@
      }
      view1.axis('value', yc)
  
      // view1.legend(false)
      if (!noLegend) {
        view1.legend(false)
      }
  
      if (plot.mutilBar !== 'stack') {
        let _chart = view1
@@ -679,13 +715,13 @@
        } else {
          _chart.color('key')
        }
        if (plot.label !== 'false') {
        if (label !== 'false') {
          _chart.label('value*key', (value, key) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
            if (label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
              lablecfg.style.fill = colors.get(key)
            }
            return {
@@ -695,7 +731,7 @@
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.barRadius) {
@@ -730,13 +766,13 @@
        } else {
          _chart.color('key')
        }
        if (plot.label !== 'false') {
        if (label !== 'false') {
          _chart.label('value*key', (value, key) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            if (plot.label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
            if (label === 'true' && plot.labelColor === 'custom' && colors.has(key)) {
              lablecfg.style.fill = colors.get(key)
            }
@@ -747,7 +783,7 @@
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.barRadius) {
@@ -770,7 +806,9 @@
    view2.data(dv.rows)
    // view2.legend(false)
    if (!noLegend && Bar_axis.length) {
      view2.legend(false)
    }
    fields.forEach(item => {
      if (item.chartType === 'bar' && !Bar_axis.length) {
@@ -1093,7 +1131,7 @@
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.selectColor) {
@@ -1153,7 +1191,7 @@
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.selectColor) {
@@ -1307,6 +1345,21 @@
    this.updateComponent(_card)
  }
  plotchange = (card) => {
    if (card.plot.enabled === 'true' && card.plot.zoomYaxis !== 'custom' && card.plot.customs) {
      card.plot.customs.forEach(item => {
        item.min = ''
        item.max = ''
      })
    }
    if (card.plot.barcolors && (card.plot.enabled === 'true' || card.plot.datatype === 'statistics')) {
      card.plot.barcolors = null
    }
    this.updateComponent(card)
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
@@ -1331,7 +1384,7 @@
          <div className="mk-popover-control">
            {appType !== 'mob' ? <PlusCircleOutlined className="plus" title="添加搜索" onClick={this.addSearch}/> : null}
            {appType !== 'mob' ? <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton}/> : null}
            <ChartCompileForm config={card} plotchange={this.updateComponent}/>
            <ChartCompileForm config={card} plotchange={this.plotchange}/>
            <CopyComponent type="line" card={card}/>
            <PasteComponent config={card} options={['action', 'search']} updateConfig={this.updateComponent} />
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
src/menu/components/chart/antv-dashboard/chartcompile/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, InputNumber, notification, Tabs, Button } from 'antd'
import { QuestionCircleOutlined, EditOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
@@ -27,7 +27,7 @@
    plot: null,
    formlist: null,
    baseFormlist: null,
    view: 'normal',
    view: 'base',
    colorColumns: [
      {
        title: '指标',
@@ -54,7 +54,7 @@
    this.setState({
      visible: true,
      view: 'normal',
      view: 'base',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot),
      formlist: config.subtype === 'ratioboard' ? getRadioOptionForm(config.plot, config.columns) : getOptionForm(config.plot, config.columns)
@@ -250,6 +250,18 @@
      this.baseRef.handleConfirm().then(res => {
        let _plot = {...plot, ...res}
        if (!plot.valueField && tab === 'color') {
          this.setState({
            plot: _plot,
            view: 'normal'
          })
          notification.warning({
            top: 92,
            message: '请添加图表设置。',
            duration: 3
          })
          return
        }
        this.setState({
          plot: _plot,
          view: tab
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
@@ -292,22 +292,6 @@
      }],
    }, {
      type: 'radio',
      key: 'repeat',
      label: '重复数据',
      initVal: card.repeat || 'unrepeat',
      required: false,
      options: [{
        value: 'unrepeat',
        text: '去重'
      }, {
        value: 'average',
        text: '平均'
      }, {
        value: 'cumsum',
        text: '累加'
      }]
    }, {
      type: 'radio',
      key: 'download',
      label: '导出图片',
      initVal: card.download || 'forbid',
src/menu/components/chart/antv-pie/chartcompile/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, InputNumber, Tabs, Button } from 'antd'
import { Modal, Form, Row, Col, Select, Radio, Tooltip, Input, notification, InputNumber, Tabs, Button } from 'antd'
import { QuestionCircleOutlined, EditOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
@@ -27,7 +27,7 @@
    plot: null,
    formlist: null,
    baseFormlist: null,
    view: 'normal',
    view: 'base',
    colorColumns: [
      {
        title: '指标',
@@ -54,7 +54,7 @@
    this.setState({
      visible: true,
      view: 'normal',
      view: 'base',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot),
      formlist: getOptionForm(config.plot, config.columns)
@@ -276,6 +276,18 @@
      this.baseRef.handleConfirm().then(res => {
        let _plot = {...plot, ...res}
        if (!plot.Xaxis && tab === 'color') {
          this.setState({
            plot: _plot,
            view: 'normal'
          })
          notification.warning({
            top: 92,
            message: '请添加图表设置。',
            duration: 3
          })
          return
        }
        this.setState({
          plot: _plot,
          view: tab
src/menu/components/chart/antv-scatter/chartcompile/index.jsx
@@ -20,7 +20,7 @@
  }
  state = {
    view: 'normal',
    view: 'base',
    visible: false,
    plot: null,
    formlist: null,
@@ -32,7 +32,7 @@
    this.setState({
      visible: true,
      view: 'normal',
      view: 'base',
      plot: fromJS(config.plot).toJS(),
      baseFormlist: getBaseForm(config.plot),
      formlist: getOptionForm(config.plot, config.columns)
src/menu/components/code/sandbox/editorcode/index.jsx
@@ -34,7 +34,7 @@
      visible: true,
      html: config.html || '',
      css: config.css || '',
      js: config.js || '',
      js: config.js || '// Function(data, result, Api, notification, systemType) data-数据列表,result-查询接口返回结果,Api-接口,notification-信息提示控件(移动端为Toast),systemType-系统类型(正式为 production,测试为空)',
    })
  }
src/menu/components/form/dragtitle/options.jsx
@@ -51,7 +51,7 @@
    {
      type: 'select',
      field: 'focus',
      label: '焦点',
      label: '初始焦点',
      initval: group.setting.focus || '',
      required: false,
      options: fields
src/menu/components/form/formaction/actionform/index.jsx
@@ -57,10 +57,12 @@
    } else if (this.record.type === 'close' || this.record.type === 'reset') {
      shows = ['typeName', 'label']
    } else {
      shows = ['typeName', 'label', 'intertype', 'Ot', 'execSuccess', 'syncComponent', 'anchors', 'linkmenu', 'output', 'reload'] // 选项列表
      shows = ['typeName', 'label', 'intertype', 'Ot', 'execSuccess', 'syncComponent', 'anchors', 'linkmenu', 'output', 'reload', 'preButton'] // 选项列表
      if (this.record.execSuccess === 'never') {
        shows.push('resetForms')
      }
      if (this.record.intertype === 'custom') {
        shows.pop()
        shows.push('procMode', 'interface', 'callbackType', 'proInterface', 'method', 'cross', 'stringify', 'ContentType', 'outerBlacklist')
        if (this.record.procMode === 'system') {
          shows.push('sql', 'sqlType')
@@ -282,14 +284,15 @@
              })(
                <Select
                  showSearch
                  mode={item.mode || ''}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(value) => {this.optionChange(item.key, value)}}
                  getPopupContainer={() => document.getElementById('winter')}
                  allowClear={item.allowClear}
                >
                  {item.options.map((option, index) =>
                    <Select.Option id={`${index}`} title={option.text} key={`${index}`} value={option.value}>
                      {option.text}
                    <Select.Option title={option.text || option.label} key={index} value={option.value}>
                      {option.text || option.label}
                    </Select.Option>
                  )}
                </Select>
@@ -380,6 +383,9 @@
          if (values.outerBlacklist) {
            values.outerBlacklist = values.outerBlacklist.replace(/\s/ig, '')
          }
          if (values.resetForms && values.resetForms.length === 0) {
            values.resetForms = null
          }
          resolve(values)
        } else {
          reject(err)
src/menu/components/form/formaction/formconfig.jsx
@@ -4,7 +4,7 @@
 * @param {*} type           按钮类型,用于区分可选的打开方式
 */
export function getActionForm (card, functip, tableName, usefulFields, modules, anchors) {
export function getActionForm (card, functip, tableName, usefulFields, modules, anchors, uuid, fields) {
  const appType = sessionStorage.getItem('appType')
  let viewType = sessionStorage.getItem('editMenuType') // 弹窗 popview
  let _type = '提交'
@@ -45,6 +45,72 @@
    }
  }
  let linkButtons = []
  let filterComponent = (components) => {
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          filterComponent(tab.components)
        })
      } else if (item.type === 'group') {
        filterComponent(item.components)
      } else {
        item.action && item.action.forEach(cell => {
          if (cell.hidden === 'true' || cell.uuid === uuid) return
          if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
          linkButtons.push({
            value: cell.uuid,
            label: cell.label + '(' + item.name + ')'
          })
        })
        if (item.type === 'card' && item.subcards) {
          item.subcards.forEach(m => {
            if ((item.subtype === 'datacard' || item.subtype === 'dualdatacard') && m.$cardType !== 'extendCard') return
            m.elements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.uuid === uuid) return
              if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
              linkButtons.push({
                value: cell.uuid,
                label: cell.label + '(' + item.name + ')'
              })
            })
          })
        } else if (item.type === 'balcony') {
          item.elements.forEach(cell => {
            if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.uuid === uuid) return
            if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
            linkButtons.push({
              value: cell.uuid,
              label: cell.label + '(' + item.name + ')'
            })
          })
        } else if (item.type === 'form') {
          item.subcards.forEach(group => {
            if(group.uuid === uuid) return
            if (item.subcards.length > 1) {
              linkButtons.push({
                value: group.uuid,
                label: group.subButton.label + '(' + item.name + '-' + group.setting.title + ')'
              })
            } else {
              linkButtons.push({
                value: group.uuid,
                label: group.subButton.label + '(' + item.name + ')'
              })
            }
          })
        }
      }
    })
  }
  filterComponent(window.GLOB.customMenu.components)
  let refresh = []
  if (viewType === 'popview') { // 弹窗标签
    refresh.push({
@@ -56,6 +122,16 @@
      text: '刷新源组件'
    })
  }
  let resets = []
  fields.forEach(item => {
    if (item.type !== 'text' && item.type !== 'number') return
    resets.push({
      value: item.field,
      text: item.label
    })
  })
  return [
    {
@@ -400,6 +476,26 @@
      options: anchors
    },
    {
      type: 'select',
      key: 'preButton',
      label: '前置按钮',
      tooltip: '当前按钮执行前,需要执行的按钮。',
      initVal: card.preButton || '',
      required: false,
      allowClear: true,
      options: linkButtons
    },
    {
      type: 'select',
      key: 'resetForms',
      label: '重置表单',
      tooltip: '按钮执行成功后需要重置的表单,表单会恢复默认值并聚焦。',
      initVal: card.resetForms || [],
      required: false,
      mode: 'multiple',
      options: resets
    },
    {
      type: 'radio',
      key: 'reload',
      label: '上一页',
src/menu/components/form/formaction/index.jsx
@@ -76,7 +76,7 @@
   * @description 按钮编辑,获取按钮表单信息
   */
  handleAction = (card) => {
    const { config } = this.props
    const { config, group } = this.props
    let usefulFields = sessionStorage.getItem('permFuncField')
    if (usefulFields) {
@@ -110,7 +110,7 @@
    this.setState({
      visible: true,
      card: card,
      formlist: getActionForm(card, functip, config.setting.tableName, usefulFields, modules, anchors)
      formlist: getActionForm(card, functip, config.setting.tableName, usefulFields, modules, anchors, group.uuid, group.fields)
    })
  }
@@ -143,6 +143,7 @@
        res.enable = group.prevButton.enable || 'true'
        group.prevButton = res
      } else if (res.type === 'submit') {
        res.enable = group.subButton.enable || 'true'
        group.subButton = res
      } else if (res.type === 'next') {
        res.enable = group.nextButton.enable || 'true'
src/menu/components/form/simple-form/index.jsx
@@ -69,7 +69,7 @@
          setting: {title: '', align: 'left_right', enable: 'true'},
          style: {},
          fields: [],
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
        }]
      }
@@ -80,6 +80,10 @@
        card: _card
      })
    }
  }
  componentDidMount () {
    MKEmitter.addListener('mkUpdateInter', this.mkUpdateInter)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -93,6 +97,21 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkUpdateInter', this.mkUpdateInter)
  }
  mkUpdateInter = (inter, split) => {
    const { card } = this.state
    if (card.wrap.datatype === 'public' && card.wrap.publicId === inter.uuid) {
      let _card = {...card, columns: fromJS(inter.columns).toJS()}
      split.delay = split.delay + 10
      setTimeout(() => {
        this.updateComponent(_card)
      }, split.delay)
    }
  }
  /**
@@ -104,7 +123,7 @@
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
    if (card.wrap.datatype === 'dynamic') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
      if (supModule === 'empty') {
        supModule = ''
@@ -118,6 +137,9 @@
      }
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
@@ -128,16 +150,22 @@
        })
      })
    } else {
      let supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      let supModule = ''
      if (card.wrap.datatype === 'static') {
        supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      }
      card.$tables = getTables(card)
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
          if (m.type === 'linkMain' && !supModule && card.wrap.datatype === 'static') {
            card.errors.push({ level: 1, detail: `请检查关联主表“${m.label}”是否有效`})
          }
        })
@@ -497,6 +525,17 @@
      } else {
        _card.setting.supModule = ''
      }
    } else if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
        _card.setting = { interType: 'system' }
        _card.scripts = []
      }
    }
    _card.subcards[0].setting.focus = _card.wrap.focus
@@ -563,8 +602,7 @@
            <PasteForms config={card.subcards[0]} update={this.pasteForm} />
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/> : null}
            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/>}
          </div>
        } trigger="hover">
          <ToolOutlined />
src/menu/components/form/simple-form/options.jsx
@@ -45,6 +45,18 @@
    }
  }
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  }
  let buttons = []
  if (!wrap.enable || wrap.enable === 'true') {
@@ -94,21 +106,39 @@
      options: [
        {value: 'dynamic', label: '动态'},
        {value: 'static', label: '静态'},
        {value: 'public', label: '公共数据源'},
      ],
      controlFields: [
        {field: 'empty', values: ['dynamic']},
        {field: 'supModule', values: ['static']},
        {field: 'publicId', values: ['public']},
      ]
    },
    {
      type: 'select',
      field: 'publicId',
      label: '数据源',
      initval: wrap.publicId || '',
      required: true,
      options: interfaces
    },
    {
      type: 'select',
      field: 'focus',
      label: '焦点',
      label: '初始焦点',
      initval: wrap.focus || '',
      required: false,
      options: fields
    },
    {
      type: 'select',
      field: 'refocus',
      label: '刷新焦点',
      initval: wrap.refocus || '',
      required: false,
      options: fields
    },
    {
      type: 'radio',
      field: 'cache',
      label: '选项查询',
src/menu/components/form/step-form/index.jsx
@@ -89,6 +89,10 @@
    }
  }
  componentDidMount () {
    MKEmitter.addListener('mkUpdateInter', this.mkUpdateInter)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
@@ -99,6 +103,21 @@
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkUpdateInter', this.mkUpdateInter)
  }
  mkUpdateInter = (inter, split) => {
    const { card } = this.state
    if (card.wrap.datatype === 'public' && card.wrap.publicId === inter.uuid) {
      let _card = {...card, columns: fromJS(inter.columns).toJS()}
      split.delay = split.delay + 10
      setTimeout(() => {
        this.updateComponent(_card)
      }, split.delay)
    }
  }
@@ -111,7 +130,7 @@
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
    if (card.wrap.datatype === 'dynamic') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
      if (supModule === 'empty') {
        supModule = ''
@@ -125,6 +144,9 @@
      }
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
@@ -135,16 +157,22 @@
        })
      })
    } else {
      let supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      let supModule = ''
      if (card.wrap.datatype === 'static') {
        supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      }
      card.$tables = getTables(card)
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
          if (m.type === 'linkMain' && !supModule && card.wrap.datatype === 'static') {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
        })
@@ -196,7 +224,7 @@
      style: {},
      fields: [],
      prevButton: {label: '上一步', type: 'prev', enable: 'false', style: {marginRight: '15px', paddingTop: '5px', paddingBottom: '5px'}},
      subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
      subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
      nextButton: {label: '跳过', type: 'next', enable: 'false', style: {paddingTop: '5px', paddingBottom: '5px'}}
    }
@@ -586,6 +614,17 @@
      } else {
        _card.setting.supModule = ''
      }
    } else if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
        _card.setting = { interType: 'system' }
        _card.scripts = []
      }
    }
    this.updateComponent(_card)
@@ -670,8 +709,7 @@
            <PasteComponent config={card} options={['formgroup', 'simpleform']} updateConfig={this.pasteForm} />
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/> : null}
            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/>}
          </div>
        } trigger="hover">
          <ToolOutlined />
src/menu/components/form/step-form/options.jsx
@@ -29,6 +29,18 @@
    }
  }
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  }
  const wrapForm = [
    {
      type: 'text',
@@ -59,14 +71,44 @@
      options: [
        {value: 'dynamic', label: '动态'},
        {value: 'static', label: '静态'},
        {value: 'public', label: '公共数据源'}
      ],
      controlFields: [
        {field: 'empty', values: ['dynamic']},
        {field: 'supModule', values: ['static']},
        {field: 'publicId', values: ['public']},
      ]
    },
    {
      type: 'select',
      field: 'publicId',
      label: '数据源',
      initval: wrap.publicId || '',
      required: true,
      options: interfaces,
      reset_source: config.subtype !== 'tabform',
      callback: (map, record) => {
        if (!record.publicId) return
        let interfaces = window.GLOB.customMenu.interfaces || []
        let d = interfaces.filter(m => m.uuid === record.publicId && m.status === 'true')[0]
        if (!d || !d.columns) return
        let columns = JSON.parse(JSON.stringify(d.columns))
        let _sCtrl = map.get('statusControl')
        if (_sCtrl && !_sCtrl.forbid) {
          _sCtrl.options = columns
          _sCtrl.oriOptions = columns
          map.set('statusControl', _sCtrl)
        }
      }
    },
    {
      type: 'select',
      field: 'statusControl',
      label: '状态控制',
      initval: wrap.statusControl || '',
src/menu/components/form/tab-form/index.jsx
@@ -70,21 +70,21 @@
          sort: 1,
          style: {},
          fields: [],
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
        }, {
          uuid: Utils.getuuid(),
          setting: {title: '分组2', align: 'left_right'},
          sort: 1,
          style: {},
          fields: [],
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
        }, {
          uuid: Utils.getuuid(),
          setting: {title: '分组3', align: 'left_right'},
          sort: 1,
          style: {},
          fields: [],
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
          subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
        }]
      }
@@ -101,6 +101,10 @@
    }
  }
  componentDidMount () {
    MKEmitter.addListener('mkUpdateInter', this.mkUpdateInter)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
@@ -111,6 +115,21 @@
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkUpdateInter', this.mkUpdateInter)
  }
  mkUpdateInter = (inter, split) => {
    const { card } = this.state
    if (card.wrap.datatype === 'public' && card.wrap.publicId === inter.uuid) {
      let _card = {...card, columns: fromJS(inter.columns).toJS()}
      split.delay = split.delay + 10
      setTimeout(() => {
        this.updateComponent(_card)
      }, split.delay)
    }
  }
@@ -123,7 +142,7 @@
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
    if (card.wrap.datatype === 'dynamic') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
      if (supModule === 'empty') {
        supModule = ''
@@ -137,6 +156,9 @@
      }
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
@@ -147,16 +169,22 @@
        })
      })
    } else {
      let supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      let supModule = ''
      if (card.wrap.datatype === 'static') {
        supModule = card.wrap.supModule ? card.wrap.supModule[card.wrap.supModule.length - 1] : ''
      }
      card.$tables = getTables(card)
      card.subcards.forEach(item => {
        if (item.subButton.intertype === 'system' && !item.subButton.sqlType) {
          card.errors.push({ level: 0, detail: `${item.subButton.label} 按钮请设置操作类型`})
        }
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
          if (m.type === 'linkMain' && !supModule && card.wrap.datatype === 'static') {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
        })
@@ -207,7 +235,7 @@
      sort: card.subcards.length + 1,
      style: {},
      fields: [],
      subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: 'update', sql: '', Ot: 'notRequired', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
      subButton: {label: '提交', type: 'submit', intertype: 'system', reload: 'false', sqlType: '', sql: '', Ot: 'notRequired', execSuccess: 'never', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
    }
    card.subcards.push(newcard)
@@ -587,6 +615,17 @@
      } else {
        _card.setting.supModule = ''
      }
    } else if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
        _card.setting = { interType: 'system' }
        _card.scripts = []
      }
    }
    this.updateComponent(_card)
@@ -671,8 +710,7 @@
            <PasteComponent config={card} options={['formgroup', 'simpleform']} updateConfig={this.pasteForm} />
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/> : null}
            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}}/>}
          </div>
        } trigger="hover">
          <ToolOutlined />
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -14,9 +14,9 @@
const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
const MKTable = asyncComponent(() => import('@/components/normalform/modalform/mkTable'))
const acTyOptions = {
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hidden'],
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden', 'preButton'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'position', 'tipTitle', 'hidden', 'preButton'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hidden', 'preButton'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
  excelOut: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
@@ -874,7 +874,7 @@
            getPopupContainer={() => document.getElementById('winter')}
          >
            {item.options.map((option, index) =>
              <Select.Option key={index} title={option.text || option.label} value={(option.value || option.field)}>
              <Select.Option key={index} title={option.text || option.label} disabled={option.$disabled || false} value={(option.value || option.field)}>
                {(option.text || option.label)}
              </Select.Option>
            )}
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -7,7 +7,6 @@
 * @param {*} functip        生成存储过程提示
 * @param {*} setting        组件配置
 * @param {*} usefulFields   存储过程可用的开始字段
 * @param {*} type           按钮类型,用于区分可选的打开方式
 */
export function getActionForm (card, functip, config, usefulFields, modules = [], anchors = [], side) {
  let appType = sessionStorage.getItem('appType')
@@ -17,6 +16,7 @@
  let appMenus = []
  let menulist = []
  let type = ''
  let alltype = config.type + '_' + config.subtype
  if (card.eleType === 'button') {
    type = 'card'
@@ -82,7 +82,73 @@
    return _list
  }
  let tabs = getTabs(JSON.parse(JSON.stringify(window.GLOB.customMenu.components)))
  let tabs = getTabs(window.GLOB.customMenu.components)
  let linkButtons = []
  let filterComponent = (components) => {
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          filterComponent(tab.components)
        })
      } else if (item.type === 'group') {
        filterComponent(item.components)
      } else {
        item.action && item.action.forEach(cell => {
          if (cell.hidden === 'true' || cell.uuid === card.uuid) return
          if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
          linkButtons.push({
            value: cell.uuid,
            label: cell.label + '(' + item.name + ')'
          })
        })
        if (item.type === 'card' && item.subcards) {
          item.subcards.forEach(m => {
            if ((item.subtype === 'datacard' || item.subtype === 'dualdatacard') && m.$cardType !== 'extendCard') return
            m.elements.forEach(cell => {
              if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.uuid === card.uuid) return
              if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
              linkButtons.push({
                value: cell.uuid,
                label: cell.label + '(' + item.name + ')'
              })
            })
          })
        } else if (item.type === 'balcony') {
          item.elements.forEach(cell => {
            if (cell.eleType !== 'button' || cell.hidden === 'true' || cell.uuid === card.uuid) return
            if (!['exec', 'prompt', 'pop'].includes(cell.OpenType)) return
            linkButtons.push({
              value: cell.uuid,
              label: cell.label + '(' + item.name + ')'
            })
          })
        } else if (item.type === 'form') {
          item.subcards.forEach(group => {
            if(group.uuid === card.uuid) return
            if (item.subcards.length > 1) {
              linkButtons.push({
                value: group.uuid,
                label: group.subButton.label + '(' + item.name + '-' + group.setting.title + ')'
              })
            } else {
              linkButtons.push({
                value: group.uuid,
                label: group.subButton.label + '(' + item.name + ')'
              })
            }
          })
        }
      }
    })
  }
  filterComponent(window.GLOB.customMenu.components)
  let pageTemps = [
    { value: 'billprint', text: '单据打印' },
@@ -603,17 +669,22 @@
      key: 'execSuccess',
      label: '成功后',
      initVal: card.execSuccess || 'grid',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新表格。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      required: true,
      options: [{
        value: 'never',
        text: '不刷新'
      }, {
        value: 'line',
        text: '刷新行'
        text: '刷新行',
        $disabled: !['table_normaltable', 'table_editable', 'table_basetable', 'card_datacard', 'card_dualdatacard'].includes(alltype)
      }, {
        value: 'grid',
        text: '刷新当前组件'
      }, {
        value: 'line_grid',
        text: '刷新行 / 组件',
        $disabled: !['table_normaltable', 'table_editable', 'table_basetable', 'card_datacard', 'card_dualdatacard'].includes(alltype)
      }, {
        value: 'mainline',
        text: '刷新上级组件 - 行'
@@ -626,17 +697,22 @@
      key: 'execError',
      label: '失败后',
      initVal: card.execError || 'never',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。' : '选择刷新行时,如果选择多条数据会刷新表格,注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。',
      required: true,
      options: [{
        value: 'never',
        text: '不刷新'
      }, {
        value: 'line',
        text: '刷新行'
        text: '刷新行',
        $disabled: !['table_normaltable', 'table_editable', 'table_basetable', 'card_datacard', 'card_dualdatacard'].includes(alltype)
      }, {
        value: 'grid',
        text: '刷新当前组件'
      }, {
        value: 'line_grid',
        text: '刷新行 / 组件',
        $disabled: !['table_normaltable', 'table_editable', 'table_basetable', 'card_datacard', 'card_dualdatacard'].includes(alltype)
      }, {
        value: 'mainline',
        text: '刷新上级组件 - 行'
@@ -677,12 +753,12 @@
    {
      type: 'number',
      key: 'width',
      min: 1,
      min: 0,
      max: 24,
      precision: 0,
      label: '宽度',
      initVal: card.width || 12,
      tooltip: '栅格布局,每行等分为24列。',
      initVal: card.width || (card.width === 0 ? 0 : 12),
      tooltip: '栅格布局,每行等分为24列。为 0 时宽度自适应。',
      forbid: type !== 'card',
      required: true
    },
@@ -712,9 +788,6 @@
      required: false,
      forbid: (type !== 'datacard' || appType !== 'mob'),
      options: [{
      //   value: 'false',
      //   text: '否'
      // }, {
        value: 'left',
        text: '左滑'
      }, {
@@ -869,6 +942,16 @@
      allowClear: true,
      options: appType === 'mob' || appType === 'pc' ? appMenus : menulist,
      forbid: viewType === 'popview'
    },
    {
      type: 'select',
      key: 'preButton',
      label: '前置按钮',
      tooltip: '当前按钮执行前,需要执行的按钮。',
      initVal: card.preButton || '',
      required: false,
      allowClear: true,
      options: linkButtons
    },
    {
      type: 'text',
@@ -1713,7 +1796,7 @@
      key: 'execSuccess',
      label: '成功后',
      initVal: card.execSuccess || 'grid',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新表格。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      required: true,
      options: [{
        value: 'never',
@@ -1724,6 +1807,9 @@
      }, {
        value: 'grid',
        text: '刷新当前组件'
      }, {
        value: 'line_grid',
        text: '刷新行 / 组件',
      }, {
        value: 'mainline',
        text: '刷新上级组件 - 行'
@@ -1735,7 +1821,7 @@
      key: 'execError',
      label: '失败后',
      initVal: card.execError || 'never',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新哪一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。' : '选择刷新行时,如果选择多条数据会刷新表格,注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮中设置关闭后刷新哪一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用)。',
      required: true,
      options: [{
        value: 'never',
@@ -1747,6 +1833,9 @@
        value: 'grid',
        text: '刷新当前组件'
      }, {
        value: 'line_grid',
        text: '刷新行 / 组件',
      }, {
        value: 'mainline',
        text: '刷新上级组件 - 行'
      },
src/menu/components/share/actioncomponent/index.jsx
@@ -207,7 +207,7 @@
      }
    }
    
    let modules = MenuUtils.getSubModules(window.GLOB.customMenu.components, config.uuid, supId)
    let modules = MenuUtils.getSubModules(window.GLOB.customMenu.components, config.uuid, supId, config.subtype !== 'basetable')
    if (config.subtype === 'basetable') {
      delete card.eleType // 区分按钮位置
src/menu/components/share/markcomponent/index.jsx
@@ -430,7 +430,7 @@
        >
          <MarkForm field={this.props.field} signs={signs} columns={options} markChange={this.markChange}/>
          <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>注:从上到下,匹配第一个符合条件的标记。</Col>
          <EditTable actions={['edit', 'move', 'del']} data={marks} columns={markColumns} onChange={(marks) => this.setState({marks})}/>
          <EditTable actions={['edit', 'move', 'del', 'copy']} type="marks" data={marks} columns={markColumns} onChange={(marks) => this.setState({marks})}/>
        </Modal>
      </div>
    )
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -88,6 +88,11 @@
    })
  })
  editCols.push({
    field: '$next_' + card.uuid,
    label: card.label + '(下一行)'
  })
  return [
    {
      type: 'text',
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
@@ -6,7 +6,7 @@
import Api from '@/api'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
// import './index.scss'
class CustomForm extends Component {
  static propTpyes = {
@@ -316,7 +316,7 @@
              </Select>
            </Form.Item>
          </Col> : null}
          <Col span={5} style={{paddingTop: '3px', whiteSpace: 'nowrap'}}>
          <Col span={5} className="add" style={{paddingTop: '3px', whiteSpace: 'nowrap'}}>
            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 15}}>
              {type === 'fullscreen' && !editItem ? '添加' : '保存'}
            </Button>
@@ -324,7 +324,7 @@
              取消
            </Button>
          </Col>
          <Col span={3} style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
            强制保存:
            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
          </Col>
src/menu/components/table/edit-table/columns/tableIn/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Tabs, Row, Col, Input, Button, Popconfirm, notification, Modal, message, Cascader, Tooltip, InputNumber, Radio, Typography } from 'antd'
import { Form, Tabs, Row, Col, Input, Button, Popconfirm, notification, Modal, message, Select, Cascader, Tooltip, InputNumber, Radio, Typography } from 'antd'
import { StopTwoTone, CheckCircleTwoTone, EditOutlined, SwapOutlined, DeleteOutlined, QuestionCircleOutlined } from '@ant-design/icons'
import moment from 'moment'
@@ -498,6 +498,7 @@
  }
  render() {
    const { config } = this.props
    const { verify, scriptsColumns, uniqueColumns, activeKey, fields, modules } = this.state
    const formItemLayout = {
      labelCol: {
@@ -552,25 +553,34 @@
                  </Form.Item>
                </Col> : null}
                <Col span={8}>
                  <Form.Item label={'成功后'}>
                    <Radio.Group style={{whiteSpace: 'nowrap'}} value={verify.execSuccess} onChange={(e) => this.onOptionChange(e.target.value, 'execSuccess')}>
                      <Radio value="never">不刷新</Radio>
                      <Radio value="grid">刷新表格</Radio>
                      <Radio value="mainline">上级(行)</Radio>
                    </Radio.Group>
                  <Form.Item label={
                    <Tooltip placement="topLeft" title="《刷新行》与《刷新行 / 组件》只在数据提交为 修改项 时有效。">
                      <QuestionCircleOutlined className="mk-form-tip" />
                      成功后
                    </Tooltip>
                  }>
                    <Select value={verify.execSuccess} onChange={(val) => this.onOptionChange(val, 'execSuccess')}>
                      <Select.Option value="never">不刷新</Select.Option>
                      <Select.Option value="line" disabled={config.wrap.commit !== 'change'}>刷新行</Select.Option>
                      <Select.Option value="grid">刷新组件</Select.Option>
                      <Select.Option value="line_grid" disabled={config.wrap.commit !== 'change'}>刷新行 / 组件</Select.Option>
                      <Select.Option value="mainline">上级(行)</Select.Option>
                    </Select>
                  </Form.Item>
                </Col>
                <Col span={8}>
                  <Form.Item label={'失败后'}>
                    <Radio.Group style={{whiteSpace: 'nowrap'}} value={verify.execError} onChange={(e) => this.onOptionChange(e.target.value, 'execError')}>
                      <Radio value="never">不刷新</Radio>
                      <Radio value="grid">刷新表格</Radio>
                      <Radio value="mainline">上级(行)</Radio>
                    </Radio.Group>
                  <Form.Item label="失败后">
                    <Select value={verify.execError} onChange={(val) => this.onOptionChange(val, 'execError')}>
                      <Select.Option value="never">不刷新</Select.Option>
                      <Select.Option value="line" disabled={config.wrap.commit !== 'change'}>刷新行</Select.Option>
                      <Select.Option value="grid">刷新组件</Select.Option>
                      <Select.Option value="line_grid" disabled={config.wrap.commit !== 'change'}>刷新行 / 组件</Select.Option>
                      <Select.Option value="mainline">上级(行)</Select.Option>
                    </Select>
                  </Form.Item>
                </Col>
                {isPop ? <Col span={8}>
                  <Form.Item label={'成功后'}>
                  <Form.Item label="成功后">
                    <Radio.Group style={{whiteSpace: 'nowrap'}} value={verify.closetab || 'false'} onChange={(e) => this.onOptionChange(e.target.value, 'closetab')}>
                      <Radio value="false">标签不关闭</Radio>
                      <Radio value="true">标签关闭</Radio>
@@ -606,7 +616,7 @@
            </span>
          } key="scripts">
            <FullScripts
              verify={verify}
              scripts={verify.scripts}
              getScriptsFullForm={() => this.scriptsFullForm}
              getScriptsForm={() => this.scriptsForm}
              handleStatus={this.handleStatus}
src/menu/components/table/edit-table/options.jsx
@@ -54,17 +54,33 @@
      required: false
    },
    {
      type: 'radio',
      type: 'select',
      field: 'commit',
      label: '数据提交',
      initval: wrap.commit || 'all',
      tooltip: '设置为修改项时,在失去焦点且不存在必填项为空时触发提交。设置为修改项(全)时,在点击提交按钮时触发提交。',
      tooltip: '设置为修改项时,在失去焦点且不存在必填项为空时触发提交。设置为修改项(全)时,在点击提交按钮时触发提交。设置为勾选项时,只提交选中的数据,未选中数据时不可提交。',
      required: false,
      options: [
        {value: 'all', label: '全部'},
        {value: 'change', label: '修改项'},
        {value: 'amend', label: '修改项(全)'},
      ]
        {value: 'check', label: '勾选项'},
      ],
      reset_source: true,
      callback: (map, record, MKEmitter) => {
        let _tableType = map.get('tableType')
        _tableType.options[0].disabled = record.commit === 'check'
        _tableType.oriOptions[0].disabled = record.commit === 'check'
        map.set('tableType', _tableType)
        if (record.commit === 'check' && !record.tableType) {
          setTimeout(() => {
            MKEmitter.emit('mkFC', 'input', 'tableType', 'radio')
          }, 50)
        }
      }
    },
    {
      type: 'radio',
@@ -97,7 +113,7 @@
      initval: wrap.tableType || '',
      required: false,
      options: [
        {value: '', label: '不可选'},
        {value: '', label: '不可选', disabled: wrap.commit === 'check'},
        {value: 'radio', label: '单选'},
        {value: 'checkbox', label: '多选'},
      ]
src/menu/components/tabs/antv-tabs/index.jsx
@@ -265,6 +265,14 @@
      delete res.controlVals
    }
    res.tabStyle = res.tabStyle || 'line'
    res.cusClass = ''
    if (!['line', 'card'].includes(res.tabStyle)) {
      res.cusClass = res.tabStyle
      res.tabStyle = 'line'
    }
    tabs.setting = res
    this.updateComponent(tabs)
@@ -280,7 +288,7 @@
    let _style = resetStyle(tabs.style)
    return (
      <div className={'menu-tabs-edit-box ' + (tabs.setting.display || '')} style={_style} id={tabs.uuid}>
      <div className="menu-tabs-edit-box" style={_style} id={tabs.uuid}>
        <DraggableTabs defaultActiveKey={defaultActiveKey} tabBarStyle={{background: tabs.setting.backgroundColor || 'transparent'}} tabPosition={tabs.setting.position} type={tabs.setting.tabStyle} tabsMove={this.moveSwitch} onChange={this.onChange}>
          {tabs.subtabs.map(tab => (
            <TabPane tab={
src/menu/components/tabs/antv-tabs/options.jsx
@@ -107,6 +107,8 @@
  let controlVals = subtabs.map(item => ({uuid: item.uuid, label: item.label, value: item.controlVal}))
  let tabStyle = setting.cusClass || setting.tabStyle
  const tabForm = [
    {
      type: 'text',
@@ -140,21 +142,36 @@
        {value: 'right', label: 'right'},
      ],
      controlFields: [
        {field: 'display', values: ['top', 'bottom']},
        // {field: 'cusClass', values: ['top']},
        {field: 'tabStyle', values: ['top']},
      ]
    },
    {
      type: 'radio',
      type: 'select',
      field: 'tabStyle',
      label: '页签样式',
      initval: setting.tabStyle || 'line',
      tooltip: '标签位置为top时有效,默认值为line。',
      initval: tabStyle || 'line',
      tooltip: '按钮样式在运行时可见',
      required: true,
      options: [
        {value: 'line', label: 'line'},
        {value: 'card', label: 'card'},
        {value: 'mk-tab-button', label: '按钮(左)'},
        {value: 'mk-tab-button tab-right', label: '按钮(右)'},
      ],
    },
    // {
    //   type: 'select',
    //   field: 'cusClass',
    //   label: '自定义样式',
    //   initval: setting.cusClass || '',
    //   required: false,
    //   options: [
    //     {value: '', label: '无'},
    //     {value: 'mk-tab-button', label: '按钮(左)'},
    //     {value: 'mk-tab-button tab-right', label: '按钮(右)'},
    //   ]
    // },
    {
      type: 'radio',
      field: 'autoSwitch',
src/menu/components/timeline/normal-timeline/options.jsx
@@ -164,6 +164,19 @@
    },
    {
      type: 'radio',
      field: 'btnControl',
      label: '按钮控制',
      initval: wrap.btnControl || 'show',
      tooltip: '可设置按钮显示规则,始终显示或鼠标悬浮时显示。',
      required: false,
      options: [
        {value: 'show', label: '正常显示'},
        {value: 'hover', label: '悬浮显示'},
      ],
      forbid: appType === 'mob'
    },
    {
      type: 'radio',
      field: 'permission',
      label: '权限验证',
      initval: wrap.permission || (!appType ? 'true' : 'false'),
src/menu/datasource/index.jsx
@@ -212,6 +212,9 @@
      if (config.subtype !== 'dualdatacard') {
        delete res.subColumns
        if (config.type === 'interface') {
          res.setting.laypage = 'false'
        }
      } else {
        res.subColumns = res.subColumns.map(item => {
          if (/int/ig.test(item.datatype)) {
src/menu/datasource/verifycard/customscript/index.jsx
@@ -45,9 +45,16 @@
  getSearchField = (searches) => {
    let _usefulFields = []
    searches.forEach(item => {
      if (['dateweek', 'datemonth'].includes(item.type)) {
      if (item.type === 'dateweek') {
        _usefulFields.push(item.key)
        _usefulFields.push(item.key + '1')
      } else if (item.type === 'datemonth') {
        if (item.match === '=') {
          _usefulFields.push(item.key)
        } else {
          _usefulFields.push(item.key)
          _usefulFields.push(item.key + '1')
        }
      } else if (item.type === 'daterange') {
        let _skey = item.key
        let _ekey = item.key + '1'
src/menu/datasource/verifycard/index.jsx
@@ -59,6 +59,7 @@
        dataIndex: 'label',
        inputType: 'input',
        editable: true,
        searchable: true,
        width: '28%'
      },
      {
@@ -68,6 +69,7 @@
        editable: true,
        unique: true,
        strict: true,
        searchable: true,
        copy: true,
        rules: [{
          pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
@@ -390,6 +392,7 @@
    if (values.uuid) {
      scripts = scripts.map(item => {
        if (item.uuid === values.uuid) {
          values.$index = item.$index || ''
          return values
        } else {
          return item
@@ -658,16 +661,24 @@
      let r = SettingUtils.getDebugSql(setting, _scripts, _columns, searches, config.type)
      let _debugId = md5(r.sql)
      if (r.custompage && setting.laypage === 'true' && _columns.findIndex(col => col.field === 'mk_total') === -1) {
        Modal.warning({
          title: `数据源或自定义脚本中使用自定义分页排序时,请在字段集中添加 mk_total。`,
          okText: '知道了',
          onOk: () => {
            reject()
          }
        })
        return
        if (config.subtype !== 'basetable') {
          Modal.warning({
            title: `数据源或自定义脚本中使用自定义分页排序时,请在字段集中添加 mk_total。`,
            okText: '知道了',
            onOk: () => {
              reject()
            }
          })
          return
        } else {
          notification.warning({
            top: 92,
            message: '数据源或自定义脚本中使用自定义分页排序时,请在显示列中添加 mk_total。',
            duration: 5
          })
        }
      }
      if (debugId === _debugId) {
src/menu/datasource/verifycard/utils.jsx
@@ -195,13 +195,19 @@
      })
      arr.forEach(item => {
        if (/@time_id@/ig.test(item)) return
        let reg = new RegExp(item, 'i')
        if (reg.test(_dataresource)) {
          errors.push(`数据源中存在未替换值${item}`)
        }
        _scripts.forEach(script => {
          if (reg.test(script.sql)) {
            errors.push(`自定义脚本(${script.$index || ''})存在未替换值${item}`)
            if (script.$index) {
              errors.push(`自定义脚本(${script.$index})存在未替换值${item}`)
            } else {
              errors.push(`自定义脚本中存在未替换值${item}`)
            }
          }
        })
      })
src/menu/stylecontroller/index.jsx
@@ -29,7 +29,8 @@
  ArrowRightOutlined,
  SwapOutlined,
  EnterOutlined,
  DragOutlined
  DragOutlined,
  EyeOutlined
} from '@ant-design/icons'
import MKEmitter from '@/utils/events.js'
@@ -56,6 +57,7 @@
  }
  callback = null
  timer = null
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
@@ -96,6 +98,8 @@
    }
    this.callback = callback
    this.timer = null
    let card = fromJS(style).toJS()
    let borposition = 'outer'
@@ -163,7 +167,7 @@
    this.callback = null
  }
  updateStyle = (style) => {
  updateStyle = (style, delay) => {
    const { card } = this.state
    let _style = {
@@ -191,7 +195,15 @@
      card: _style,
    })
    this.callback && this.callback(_style)
    this.timer && clearTimeout(this.timer)
    if (delay) {
      this.timer = setTimeout(() => {
        this.callback && this.callback(_style)
      }, 300)
    } else {
      this.callback && this.callback(_style)
    }
  }
  /**
@@ -208,7 +220,7 @@
      value = 300
    }
    this.updateStyle({fontSize: `${value}px`})
    this.updateStyle({fontSize: `${value}px`}, true)
  }
  /**
@@ -219,7 +231,7 @@
    if (isNaN(value) || value < 1 || value > 10) return
    this.updateStyle({lineHeight: value})
    this.updateStyle({lineHeight: value}, true)
  }
  /**
@@ -230,7 +242,7 @@
    if (isNaN(value) || value < 0 || value > 100) return
    this.updateStyle({letterSpacing: `${value}px`})
    this.updateStyle({letterSpacing: `${value}px`}, true)
  }
  /**
@@ -241,7 +253,7 @@
    if (isNaN(value) || value < 0 || value > 100) return
    this.updateStyle({textIndent: `${value}px`})
    this.updateStyle({textIndent: `${value}px`}, true)
  }
  changeBackground = (val) => {
@@ -510,6 +522,8 @@
          delete style.right
        } else if (n === 'transform') {
          delete style.transform
        } else if (n === 'overflow') {
          delete style.overflow
        }
      })
    }
@@ -1064,6 +1078,20 @@
                  </Form.Item>
                </Col>
              </Panel> : null}
              {options.includes('overflow') ? <Panel header="溢出" key="overflow">
                <Col span={24}>
                  <Form.Item
                    colon={false}
                    label={<EyeOutlined title="溢出"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <Radio.Group style={{whiteSpace: 'nowrap'}} defaultValue={card.overflow || 'hidden'} onChange={(e) => this.changeNormalStyle(e.target.value, 'overflow')}>
                      <Radio value="hidden">隐藏</Radio>
                      <Radio value="visible">显示</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col>
              </Panel> : null}
              {options.includes('position') ? <Panel header="定位" key="position">
                <div style={{paddingLeft: '35px', fontSize: '12px'}}>注:定位效果请在运行环境中查看。</div>
                <Col span={24}>
src/menu/versions/index.jsx
@@ -1,8 +1,8 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Button, notification } from 'antd'
import { QuestionCircleOutlined, CalendarOutlined } from '@ant-design/icons'
import { Modal, Button, notification, Table, Spin } from 'antd'
import { CalendarOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
@@ -12,16 +12,30 @@
class Versions extends Component {
  static propTpyes = {
    MenuId: PropTypes.string,
    open_edition: PropTypes.string,
    Template: PropTypes.string,
    checklog: PropTypes.func,
    updateConfig: PropTypes.func
  }
  state = {
    visible: false,
    loadingTable: false,
    preconfirming: false,
    nextconfirming: false,
    tables: [],
    loading: false,
    logs: [],
    columns: [
      { title: '修改时间', dataIndex: 'createdate', key: 'createdate', align: 'center' },
      { title: '修改人', dataIndex: 'fullname', key: 'fullname', align: 'center' },
      {
        title: '操作',
        key: 'action',
        align: 'center',
        width: '230px',
        render: (text, record) => (
          <div>
            <Button type="link" onClick={() => this.change(record)} style={{color: '#1890ff'}}>切换</Button>
          </div>
        ),
      },
    ]
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -29,124 +43,162 @@
  }
  trigger = () => {
    this.setState({visible: true})
  }
  preVersion = () => {
    const { MenuId, open_edition, updateConfig } = this.props
    let param = {
      func: 's_spages_Param_ctrlzy',
      ctrlzy: 'z',
      MenuID: MenuId,
      func: 's_get_spages_param_log',
      MenuID: this.props.MenuId,
      TypeCharOne: sessionStorage.getItem('kei_no') || '',
      TypeName: sessionStorage.getItem('typename') || '',
      lang: sessionStorage.getItem('lang'),
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
      open_edition: open_edition,
      LText: MenuId + window.GLOB.appkey
      LText: this.props.MenuId + window.GLOB.appkey
    }
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    this.setState({preconfirming: true})
    this.setState({loading: true, visible: true, logs: []})
    Api.getCloudConfig(param).then(res => {
      this.setState({preconfirming: false})
      this.setState({loading: false})
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      } else {
        this.setState({visible: false})
        notification.success({
          top: 92,
          message: '执行成功。',
          duration: 1
        return
      } else if (!res.data || res.data.length === 0) {
        Modal.warning({
          title: '当前菜单无历史版本。',
          okText: '知道了'
        })
        if (updateConfig) {
          updateConfig()
        } else {
          setTimeout(() => {
            window.location.reload()
          }, 1000)
        }
        return
      }
      this.setState({logs: res.data})
    })
  }
  nextVersion = () => {
    const { MenuId, open_edition, updateConfig } = this.props
  change = (record) => {
    const { checklog } = this.props
    if (checklog()) {
      this.getpage(record)
    } else {
      const that = this
      Modal.confirm({
        title: '当前配置未保存,确定切换吗?',
        onOk: () => {
          that.getpage(record)
        },
        onCancel() {}
      })
    }
  }
  getpage = (record) => {
    const { Template } = this.props
    let param = {
      func: 's_spages_Param_ctrlzy',
      ctrlzy: 'y',
      MenuID: MenuId,
      func: 'sPC_Get_LongParam_page_id',
      id: record.id,
      TypeCharOne: sessionStorage.getItem('kei_no') || '',
      TypeName: sessionStorage.getItem('typename') || '',
      lang: sessionStorage.getItem('lang'),
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
      open_edition: open_edition,
      LText: MenuId + window.GLOB.appkey
    }
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    this.setState({nextconfirming: true})
    this.setState({loading: true})
    Api.getCloudConfig(param).then(res => {
      this.setState({nextconfirming: false})
      this.setState({loading: false})
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      } else {
        this.setState({visible: false})
        notification.success({
      } else if (!res.LongParam) {
        notification.warning({
          top: 92,
          message: '执行成功。',
          duration: 1
          message: '未获取到配置信息!',
          duration: 5
        })
        if (updateConfig) {
          updateConfig()
      } else {
        let config = null
        try {
          config = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
        } catch (e) {
          console.warn('Parse Failure')
          config = null
        }
        if (!config) {
          notification.warning({
            top: 92,
            message: '配置信息解析失败!',
            duration: 5
          })
        } else {
          setTimeout(() => {
            window.location.reload()
          }, 1000)
          if (Template !== config.Template) {
            notification.warning({
              top: 92,
              message: '菜单模板不一致,不可切换!',
              duration: 5
            })
          } else if (config.Template === 'CustomPage' && config.version !== 2.0) {
            notification.warning({
              top: 92,
              message: '历史配置版本过低,不可切换!',
              duration: 5
            })
          } else {
            this.setState({visible: false}, () => {
              this.props.updateConfig(config)
            })
            notification.success({
              top: 92,
              message: '版本切换成功,保存后生效!',
              duration: 5
            })
          }
        }
      }
    })
  }
  render() {
    const { visible, preconfirming, nextconfirming } = this.state
    const { visible, loading, logs, columns } = this.state
    return (
      <>
        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={this.trigger}><CalendarOutlined /> 版本管理</Button>
        <Modal
          title=""
          title="版本管理"
          wrapClassName="version-modal"
          visible={visible}
          width={500}
          closable={false}
          width={800}
          maskClosable={false}
          footer={[]}
          onCancel={() => { this.setState({ visible: false, logs: [] }) }}
          footer={[
            <Button key="cancel" onClick={() => this.setState({ visible: false, logs: [] })}>关闭</Button>
          ]}
          destroyOnClose
        >
          <div className="header"><QuestionCircleOutlined/>版本切换</div>
          <div className="detail">请选择需要切换的版本,或点击取消关闭弹窗。</div>
          <div className="footer">
            <Button key="pre" type="primary" loading={preconfirming} onClick={this.preVersion}>上一版本</Button>
            <Button key="next" type="primary" loading={nextconfirming} onClick={this.nextVersion}>下一版本</Button>
            <Button key="cancel" onClick={() => { this.setState({ visible: false })}}>取消</Button>
          </div>
          {loading ? <Spin size="large" /> : null}
          <Table
            rowKey="id"
            columns={columns}
            dataSource={logs}
            pagination={{
              pageSize: 10,
              total: logs.length,
              showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
            }}
          />
        </Modal>
      </>
    )
src/menu/versions/index.scss
@@ -1,30 +1,20 @@
.version-modal {
  .ant-modal-body {
    padding: 32px 32px 24px;
  }
  .ant-modal-footer {
    display: none;
  }
  .header {
    color: rgba(0, 0, 0, 0.85);
    font-weight: 500;
    font-size: 16px;
    .anticon {
      color: #faad14;
      margin-right: 16px;
      font-size: 22px;
  .ant-modal {
    top: 50px;
    .ant-modal-body {
      position: relative;
    }
  }
  .detail {
    margin-top: 8px;
    margin-bottom: 24px;
    color: rgba(0, 0, 0, 0.5);
    font-size: 14px;
  .ant-table-tbody > tr > td {
    padding: 5px 16px;
  }
  .footer {
    text-align: right;
    .ant-btn + .ant-btn {
      margin-left: 15px;
    }
  }
  .ant-spin {
    position: absolute;
    z-index: 2;
    top: 120px;
    left: calc(50% - 16px);
  }
}
src/tabviews/basetable/index.jsx
@@ -409,6 +409,11 @@
                  }
                }
              }
              if (cell.marks && cell.marks.length === 0) {
                cell.marks = null
              }
              return true
            })
@@ -422,6 +427,10 @@
            col.linkThdMenu = window.GLOB.mkThdMenus.get(menu_id) || ''
          } else {
            col.linkThdMenu = ''
          }
          if (col.marks && col.marks.length === 0) {
            col.marks = null
          }
          return true
@@ -481,6 +490,28 @@
        cell.errorType = 'error1'
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom' && item.setting.interType !== 'system') {
        cell.errorType = 'error2'
      }
    }
    if (cell.verify && cell.verify.invalid === 'true') {
      if (item.setting.maxScript && item.setting.maxScript >= 300) {
        cell.verify.invalid = 'false'
      } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
      } else if (cell.sqlType === 'insert') {
        cell.verify.invalid = 'false'
      } else if (cell.Ot === 'notRequired') {
        cell.verify.invalid = 'false'
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      try {
        // eslint-disable-next-line
        let func = new Function('btn', 'systemType', cell.verify.pre_func)
        func(cell, window.GLOB.systemType)
      } catch (e) {
        console.warn(e)
      }
    }
@@ -557,6 +588,7 @@
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.dataresource = ''
        component.setting.laypage = component.setting.laypage === 'true'
        return component
      }
src/tabviews/commontable/index.jsx
@@ -282,6 +282,8 @@
            config.setting.customScript = config.setting.customScript.replace(reg, val)
          })
        }
      } else {
        config.setting.dataresource = ''
      }
      let _arrField = []     // 字段集
@@ -310,6 +312,16 @@
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
          if (item.sqlType === 'insert') {
            item.verify.invalid = 'false'
          } else if (item.Ot === 'notRequired') {
            item.verify.invalid = 'false'
          } else if (item.intertype !== 'system' && item.procMode !== 'system') {
            item.verify.invalid = 'false'
          }
        }
        if (item.OpenType === 'funcbutton' && item.funcType === 'print' && item.verify) { // 打印机设置
          let _item = window.GLOB.UserCacheMap.get(this.props.MenuID + item.uuid)
src/tabviews/custom/components/card/balcony/index.jsx
@@ -252,7 +252,6 @@
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.setState({data: _data})
    }
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -185,7 +185,6 @@
            openid: res.thd_party_openid,
            key: key
          })))
          window.open(href)
        } else {
          notification.warning({
@@ -197,26 +196,37 @@
      })
      return
    }
    let Id = ''
    if (cards.subtype === 'propcard' && cardCell) {
      Id = cardCell.setting.primaryId || ''
    } else {
      Id = data[cards.setting.primaryKey] || ''
    }
    
    if (card.joint === 'true') {
      let con = '?'
      if (/\?/ig.test(url)) {
        con = '&'
    if (/^http.+(.txt|.doc|.docx|.pdf|.xlsx|.xls|.zip|.rar|.ppt)$/i.test(url)) {
      let name = url.replace(/.+\//g, '').replace(/\.{1}[^.]*$/g, '')
      let d = document.createElement('a')
      d.href = url
      d.setAttribute('download', name)
      d.setAttribute('target', '_blank')
      document.body.appendChild(d)
      d.click()
      d.remove()
    } else {
      if (card.joint === 'true') {
        let Id = ''
        if (cards.subtype === 'propcard' && cardCell) {
          Id = cardCell.setting.primaryId || ''
        } else {
          Id = data[cards.setting.primaryKey] || ''
        }
        let con = '?'
        if (/\?/ig.test(url)) {
          con = '&'
        }
        url = url + `${con}id=${Id}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}`
      }
      url = url + `${con}id=${Id}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}`
      window.open(url)
    }
    window.open(url)
  }
  getColor = (marks) => {
@@ -294,39 +304,39 @@
  
        if (card.datatype === 'static') {
          val = card.value || ''
          if (/@username@|@fullName@|@mk_city@|@appname@|@bid@/ig.test(val)) {
            let userName = sessionStorage.getItem('User_Name') || ''
            let fullName = sessionStorage.getItem('Full_Name') || ''
            let city = sessionStorage.getItem('city') || ''
            let appname = sessionStorage.getItem('appname') || ''
            let bid = data.$$BID || ''
            val = val.replace(/@username@/ig, userName).replace(/@fullName@/ig, fullName).replace(/@mk_city@/ig, city).replace(/@appname@/ig, appname).replace(/@bid@/ig, bid)
          } else if (/@month@/ig.test(val)) {
            val = val.replace(/@month@/ig, new Date().toLocaleString('en-US', { month: 'long' }))
          } else if (/@week@/ig.test(val)) {
            val = val.replace(/@week@/ig, (() => {
              let day = new Date().getDay()
              let weeks = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
              return weeks[day]
            })())
          } else if (/@day@/ig.test(val)) {
            val = val.replace(/@day@/ig, (() => {
              let day = new Date().getDate()
              return day < 10 ? '0' + day : day
            })())
          if (/@.+@/g.test(val)) {
            if (/@username@|@fullName@|@mk_city@|@appname@|@bid@/ig.test(val)) {
              let userName = sessionStorage.getItem('User_Name') || ''
              let fullName = sessionStorage.getItem('Full_Name') || ''
              let city = sessionStorage.getItem('city') || ''
              let appname = sessionStorage.getItem('appname') || ''
              let bid = data.$$BID || ''
              val = val.replace(/@username@/ig, userName).replace(/@fullName@/ig, fullName).replace(/@mk_city@/ig, city).replace(/@appname@/ig, appname).replace(/@bid@/ig, bid)
            } else if (/@month@/ig.test(val)) {
              val = val.replace(/@month@/ig, new Date().toLocaleString('en-US', { month: 'long' }))
            } else if (/@week@/ig.test(val)) {
              val = val.replace(/@week@/ig, (() => {
                let day = new Date().getDay()
                let weeks = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六']
                return weeks[day]
              })())
            } else if (/@day@/ig.test(val)) {
              val = val.replace(/@day@/ig, (() => {
                let day = new Date().getDate()
                return day < 10 ? '0' + day : day
              })())
            }
          }
        } else if (data.hasOwnProperty(card.field)) {
          val = data[card.field]
          val = data[card.field] + ''
        }
  
        if (!val && card.noValue === 'hide') { // 空值隐藏
          return null
        }
        if (val !== '' && card.format) {
        if (val && card.format && card.format !== 'encryption') {
          let _val = null
  
          if (card.format === 'calendar1') {
          if (val < '1949-10-02') {
            val = ''
          } else if (card.format === 'calendar1') {
            _val = moment(val).calendar(null, {
              sameDay: '[今天] ahh:mm',
              nextDay: '[明天] ahh:mm',
@@ -373,17 +383,43 @@
          } else {
            _val = moment(val).format(card.format)
          }
          // if (card.format === 'YYYY-MM-DD' && /^[1-9]\d{3}(-|\/)(0[1-9]|1[0-2])(-|\/)(0[1-9]|[1-2][0-9]|3[0-1])/.test(val)) {
          //   val = `${val.substr(0, 4)}-${val.substr(5, 2)}-${val.substr(8, 2)}`
          // }
          if (_val && _val !== 'Invalid date') {
            val = _val
          }
        }
        if (!val && card.noValue === 'hide') { // 空值隐藏
          return null
        }
  
        if (val !== '') {
          let orival = val
          if (card.linkType === 'download') {
            let url = ''
            if (card.link === 'static') {
              url = card.linkurl
            } else {
              url = data[card.linkurl]
            }
            if (/^http.+(.txt|.doc|.docx|.pdf|.xlsx|.xls|.zip|.rar)$/i.test(url)) {
              if (/pdf$/i.test(url)) {
                val = <><img src="./media/pdf.png" className="file-image" alt=""/> {val}</>
              } else if (/(.doc|.docx)$/i.test(url)) {
                val = <><img src="./media/word.png" className="file-image" alt=""/> {val}</>
              } else if (/(.xlsx|.xls)$/i.test(url)) {
                val = <><img src="./media/excel.png" className="file-image" alt=""/> {val}</>
              } else if (/(.zip|.rar)$/i.test(url)) {
                val = <><img src="./media/rar.png" className="file-image" alt=""/> {val}</>
              } else {
                val = <><img src="./media/txt.png" className="file-image" alt=""/> {val}</>
              }
            }
          }
          if (card.format === 'encryption') {
            val = <Encrypts value={val} />
          }
@@ -654,6 +690,10 @@
        if (card.link) {
          _style.cursor = 'pointer'
        }
        if (_style.position === 'absolute') {
          _style.width = '100%'
        }
  
        let scale = url && card.scale === 'true'
        let urls = url ? url.split(',').filter(Boolean) : ['']
src/tabviews/custom/components/card/cardcellList/index.scss
@@ -6,6 +6,11 @@
  .ant-btn {
    padding: 0;
  }
  .file-image {
    max-height: 100%;
    vertical-align: top;
    margin-right: 2px;
  }
  .ant-typography {
    margin: 0;
    padding: 0;
src/tabviews/custom/components/card/data-card/index.jsx
@@ -38,7 +38,7 @@
    loading: false,
    card: null,
    data: [],
    total: null,
    total: 0,
    precards: [],
    nextcards: [],
    selected: 'false',
@@ -135,6 +135,12 @@
    _config.wrap.layout = (_config.wrap.layout || 'grid') + '-layout float-' + (_config.wrap.cardFloat || 'left')
    _config.wrap.wrapClass = `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale}`
    if (_config.wrap.shifting === 'true') {
      _config.wrap.shifting = 'shifting'
    } else {
      _config.wrap.shifting = ''
    }
    let pageOptions = ['10', '25', '50', '100', '500', '1000']
@@ -398,9 +404,9 @@
          }, i * 10)
        })
      } else {
        if (position === 'line') {
        if (position === 'line' || position === 'line_grid') {
          if (lines && lines.length === 1) {
            this.loadLinedata(lines[0].$$uuid)
            this.loadLinedata(lines[0].$$uuid, position)
          } else {
            this.loadData(id)
          }
@@ -417,9 +423,9 @@
    } else {
      let supModule = config.setting.supModule
      if (position === 'line') {
      if (position === 'line' || position === 'line_grid') {
        if (lines && lines.length === 1) {
          this.loadLinedata(lines[0].$$uuid)
          this.loadLinedata(lines[0].$$uuid, position)
        } else {
          this.loadData(id)
        }
@@ -870,7 +876,7 @@
  /**
   * @description 获取单行数据
   */ 
  async loadLinedata (id) {
  async loadLinedata (id, position) {
    const { config, pageIndex, pageSize, search, BID, BData, orderBy } = this.state
    if (config.forbidLine) {
@@ -902,6 +908,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (position === 'line_grid' && (!result.data || !result.data[0])) {
        this.loadData()
        return
      }
      let data = fromJS(this.state.data).toJS()
      let selectedData = fromJS(this.state.selectedData).toJS()
      let selectKeys = fromJS(this.state.selectKeys).toJS()
@@ -1173,7 +1184,7 @@
    }
    return (
      <div className="custom-data-card-box" id={'anchor' + config.uuid} style={config.style}>
      <div className={'custom-data-card-box ' + config.wrap.shifting} id={'anchor' + config.uuid} style={config.style}>
        {loading ?
          <div className="loading-mask">
            {data.length ? <div className="ant-spin-blur"></div> : null}
src/tabviews/custom/components/card/data-card/index.scss
@@ -251,6 +251,23 @@
    }
  }
}
.custom-data-card-box.shifting {
  .normal-header:not(.header-search) + .toolbar-button {
    position: absolute;
    top: 0px;
    right: 0px;
    z-index: 1;
    button {
      margin-bottom: 0px!important;
    }
  }
  .normal-header:not(.header-search) + .toolbar-button + .pickup-wrap{
    position: relative;
    button {
      position: relative;
    }
  }
}
.custom-data-card-box::-webkit-scrollbar {
  width: 7px;
  height: 7px;
src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -36,7 +36,7 @@
    loading: false,            // 数据加载状态
    card: null,                // 卡片设置
    data: [],                // 数据
    total: null,
    total: 0,
    precards: [],
    nextcards: [],
    selected: 'false',
@@ -129,6 +129,12 @@
    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''}`
    if (_config.wrap.shifting === 'true') {
      _config.wrap.shifting = 'shifting'
    } else {
      _config.wrap.shifting = ''
    }
    let wrapStyle = null
    let subcard = fromJS(_card).toJS()
    let subconfig = fromJS(_config).toJS()
@@ -336,9 +342,9 @@
    let supModule = config.setting.supModule
    if (position === 'line') {
    if (position === 'line' || position === 'line_grid') {
      if (lines && lines.length === 1) {
        this.loadLinedata(lines[0].$$parentId || lines[0].$$uuid)
        this.loadLinedata(lines[0].$$parentId || lines[0].$$uuid, position)
      } else {
        this.loadData(id)
      }
@@ -771,7 +777,7 @@
  /**
   * @description 获取单行数据
   */ 
  async loadLinedata (id) {
  async loadLinedata (id, position) {
    const { config, pageIndex, pageSize, search, BID, BData, orderBy } = this.state
    if (config.forbidLine) {
@@ -803,6 +809,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (position === 'line_grid' && (!result.data || !result.data[0])) {
        this.loadData()
        return
      }
      let data = fromJS(this.state.data).toJS()
      let selectedData = fromJS(this.state.selectedData).toJS()
      let selectKeys = fromJS(this.state.selectKeys).toJS()
@@ -1130,7 +1141,7 @@
    }
    return (
      <div className="double-data-card-box" id={'anchor' + config.uuid} style={config.style}>
      <div className={'double-data-card-box ' + config.wrap.shifting} id={'anchor' + config.uuid} style={config.style}>
        {loading ?
          <div className="loading-mask">
            {data.length ? <div className="ant-spin-blur"></div> : null}
src/tabviews/custom/components/card/double-data-card/index.scss
@@ -305,6 +305,23 @@
    background: rgba(0, 0, 0, 0);
  }
}
.double-data-card-box.shifting {
  .normal-header:not(.header-search) + .toolbar-button {
    position: absolute;
    top: 0px;
    right: 0px;
    z-index: 1;
    button {
      margin-bottom: 0px!important;
    }
  }
  .normal-header:not(.header-search) + .toolbar-button + .pickup-wrap{
    position: relative;
    button {
      position: relative;
    }
  }
}
.double-data-card-box::-webkit-scrollbar {
  width: 7px;
  height: 7px;
src/tabviews/custom/components/card/prop-card/index.jsx
@@ -131,16 +131,14 @@
    MKEmitter.addListener('queryModuleParam', this.queryModuleParam)
    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
    if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.setting.sync === 'true') {
      MKEmitter.addListener('transferSyncData', this.transferSyncData)
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    } else if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.timer && config.wrap.datatype === 'dynamic') {
@@ -352,7 +350,6 @@
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.loaded = true
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -100,6 +100,15 @@
    _config.style.height = 'auto'
    _config.style.minHeight = _config.plot.height + 30
    if (_config.plot.correction) {
      delete _config.plot.correction // 数据修正(已弃用)
      _config.plot.barSize = 35
    }
    if (!_config.plot.legend || _config.plot.legend === 'hidden') {
      _config.plot.legend = false
    }
    if (_config.plot.title) {
      _config.style.minHeight = _config.style.minHeight + 45
    }
@@ -133,6 +142,38 @@
      if (_config.plot.mutilBar !== 'overlap' && Bar_axis.length > 1) {
        _config.plot.Bar_axis = Bar_axis
      }
      if (_config.plot.Bar_axis && _config.plot.Bar_axis.length) {
        let label = _config.plot.label
        if (label === 'false') {
          _config.plot.customs.forEach(item => {
            if (!Bar_axis.includes(item.type)) return
            if (item.label === 'true') {
              label = 'true'
            }
          })
        } else {
          let reset = true
          _config.plot.customs.forEach(item => {
            if (!Bar_axis.includes(item.type)) return
            if (item.label === 'true') {
              reset = false
            }
          })
          if (reset) {
            label = 'false'
          }
        }
        _config.plot.$label = label
      }
      if (_config.plot.zoomYaxis === 'adjust' && _config.plot.mutilBar === 'stack') {
        if (_config.plot.Bar_axis) {
          _config.plot.zoomFields = _config.plot.Yaxis.filter(cell => !_config.plot.Bar_axis.includes(cell))
        }
      }
    } else {
      _config.plot.enabled = 'false'
@@ -648,149 +689,43 @@
    }, 100)
  }
  /**
   * @description 图表数据预处理
   * 1、通过显示列进行数据类型转换
   * 2、重复数据:取平均值、累计、去重
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { plot, vFields, config } = this.state
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    } else {
      this.setState({empty: false})
    }
    let _data = []
    let _cdata = fromJS(this.data).toJS()
    return fromJS(this.data).toJS().map(item => {
      // 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]
      } else {
        item[plot.Xaxis] = '' + item[plot.Xaxis]
      }
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.Xaxis] && item[plot.Xaxis] !== 0) return
        vFields.forEach(col => {
          if (typeof(item[col.field]) !== 'number') {
            item[col.field] = parseFloat(item[col.field])
            if (isNaN(item[col.field])) {
              item[col.field] = 0
            }
      vFields.forEach(col => {
        if (typeof(item[col.field]) !== 'number') {
          item[col.field] = parseFloat(item[col.field])
          if (isNaN(item[col.field])) {
            item[col.field] = 0
          }
          if (col.show === 'percent') {
            item[col.field] = item[col.field] * 100
          }
        })
        // 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]
        } else {
          item[plot.Xaxis] = '' + item[plot.Xaxis]
        }
        if (col.show === 'percent') {
          item[col.field] = item[col.field] * 100
        }
        if (!_mdata.has(item[plot.Xaxis])) {
          item.$count = 1
          _mdata.set(item[plot.Xaxis], item)
        } else {
          let _item = _mdata.get(item[plot.Xaxis])
          _item.$count++
          vFields.forEach(col => {
            _item[col.field] += item[col.field]
          })
          _mdata.set(item[plot.Xaxis], _item)
        }
        item[col.field] = item[col.field].toFixed(col.decimal)
        item[col.field] = +item[col.field]
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        vFields.forEach(col => {
          item[col.field] = item[col.field] / item.$count
          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] && item[plot.Xaxis] !== 0) return
      item.$$uuid = item[config.setting.primaryKey] || ''
        vFields.forEach(col => {
          if (typeof(item[col.field]) !== 'number') {
            item[col.field] = parseFloat(item[col.field])
            if (isNaN(item[col.field])) {
              item[col.field] = 0
            }
          }
          if (col.show === 'percent') {
            item[col.field] = item[col.field] * 100
          }
        })
        if (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
        } else {
          item[plot.Xaxis] = '' + item[plot.Xaxis]
        }
        if (!_mdata.has(item[plot.Xaxis])) {
          _mdata.set(item[plot.Xaxis], item)
        } else {
          let _item = _mdata.get(item[plot.Xaxis])
          vFields.forEach(col => {
            _item[col.field] += item[col.field]
          })
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        vFields.forEach(col => {
          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] && item[plot.Xaxis] !== 0) 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]
        } else {
          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])
              if (isNaN(item[col.field])) {
                item[col.field] = 0
              }
            }
            if (col.show === 'percent') {
              item[col.field] = item[col.field] * 100
            }
            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)
        }
      })
      _data = [..._mdata.values()]
    }
    this.setState({empty: _data.length === 0})
    return _data
      return item
    })
  }
  /**
@@ -799,132 +734,36 @@
  getStaticMsg = () => {
    const { plot, vstFields } = this.state
    let percent = false
    let decimal = vstFields ? vstFields.decimal : 0
    if (plot.show === 'percent') {
      percent = true
    }
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    } else {
      this.setState({empty: false})
    }
    let _data = []
    let _cdata = fromJS(this.data).toJS()
    let decimal = vstFields ? vstFields.decimal : 0
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !item[plot.Xaxis]) return
    return fromJS(this.data).toJS().map(item => {
      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 (/^\d{4}-\d{2}-\d{2}(\s\d{2}:\d{2}:\d{2})?/.test(item[plot.Xaxis])) {
          item[plot.Xaxis] = ' ' + item[plot.Xaxis]
      if (typeof(item[plot.InfoValue]) !== 'number') {
        item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
        if (isNaN(item[plot.InfoValue])) {
          item[plot.InfoValue] = 0
        }
      }
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (typeof(item[plot.InfoValue]) !== 'number') {
          item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
          if (isNaN(item[plot.InfoValue])) {
            item[plot.InfoValue] = 0
          }
        }
        if (percent) {
          item[plot.InfoValue] = item[plot.InfoValue] * 100
        }
      if (plot.show === 'percent') {
        item[plot.InfoValue] = item[plot.InfoValue] * 100
      }
        if (!_mdata.has(item.$uuid)) {
          item.$count = 1
          _mdata.set(item.$uuid, item)
        } else {
          let _item = _mdata.get(item.$uuid)
          _item.$count++
          _item[plot.InfoValue] += item[plot.InfoValue]
          _mdata.set(item.$uuid, _item)
        }
      })
      item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
      item[plot.InfoValue] = +item[plot.InfoValue]
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.InfoValue] = item[plot.InfoValue] / item.$count
        item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
        item[plot.InfoValue] = +item[plot.InfoValue]
        return item
      })
    } else if (plot.repeat === 'cumsum') {
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !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]
        }
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (typeof(item[plot.InfoValue]) !== 'number') {
          item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
          if (isNaN(item[plot.InfoValue])) {
            item[plot.InfoValue] = 0
          }
        }
        if (percent) {
          item[plot.InfoValue] = item[plot.InfoValue] * 100
        }
        if (!_mdata.has(item.$uuid)) {
          _mdata.set(item.$uuid, item)
        } else {
          let _item = _mdata.get(item.$uuid)
          _item[plot.InfoValue] += item[plot.InfoValue]
          _mdata.set(item.$uuid, _item)
        }
      })
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
        item[plot.InfoValue] = +item[plot.InfoValue]
        return item
      })
    } else { // plot.repeat === 'unrepeat'
      let _mdata = new Map()
      _cdata.forEach(item => {
        if (!item[plot.InfoType] || !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]
        }
        item.$uuid = item[plot.InfoType] + item[plot.Xaxis]
        if (!_mdata.has(item.$uuid)) {
          if (typeof(item[plot.InfoValue]) !== 'number') {
            item[plot.InfoValue] = parseFloat(item[plot.InfoValue])
            if (isNaN(item[plot.InfoValue])) {
              item[plot.InfoValue] = 0
            }
          }
          if (percent) {
            item[plot.InfoValue] = item[plot.InfoValue] * 100
          }
          item[plot.InfoValue] = item[plot.InfoValue].toFixed(decimal)
          item[plot.InfoValue] = +item[plot.InfoValue]
          _mdata.set(item.$uuid, item)
        }
      })
      _data = [..._mdata.values()]
    }
    this.setState({empty: _data.length === 0})
    return _data
      return item
    })
  }
  /**
@@ -1018,7 +857,7 @@
    chart.axis(plot.Xaxis, plot.$xc)
    chart.axis(_valfield, plot.$yc)
    if (!plot.legend || plot.legend === 'hidden') {
    if (!plot.legend) {
      chart.legend(false)
    } else {
      chart.legend({
@@ -1051,9 +890,17 @@
      .position(`${plot.Xaxis}*${_valfield}`)
      .shape(plot.shape || 'smooth')
      .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
        let val = value
        if (plot.show === 'percent') {
          val = value + '%'
        } else if (plot.show === 'thdSeparator') {
          val = val + ''
          val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
        }
        return {
          name: type,
          value: plot.show === 'percent' ? value + '%' : value
          value: val
        }
      })
@@ -1075,14 +922,15 @@
    }
    if (plot.label !== 'false') {
      _chart.label(_valfield, (value) => {
        if (plot.labelValue === 'zero' && value === 0) {
          return null
        }
        let val = value
        if (plot.show === 'percent') {
          value = value + '%'
          val = value + '%'
        } else if (plot.show === 'thdSeparator') {
          val = val + ''
          val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
        }
        return {
          content: value,
          content: val,
          style: {
            fill: plot.color
          }
@@ -1153,6 +1001,41 @@
   */
  customrender = (data) => {
    const { plot, transfield } = this.state
    let max = 0
    if (plot.zoomYaxis === 'adjust') {
      data.forEach(item => {
        if (plot.zoomFields) {
          plot.zoomFields.forEach(f => {
            if (item[f] > max) {
              max = item[f]
            }
          })
          let sum = 0
          plot.Bar_axis.forEach(f => {
            sum += item[f]
          })
          if (sum > max) {
            max = sum
          }
        } else {
          plot.Yaxis.forEach(f => {
            if (item[f] > max) {
              max = item[f]
            }
          })
        }
      })
      if (!isNaN(max)) {
        max = Math.ceil(max)
        let s = max > 10 ? Math.pow(10, (max + '').length - 2) : 1
        max = Math.ceil(max / s) * s
      } else {
        max = 0
      }
    }
    const ds = new DataSet()
    const dv = ds.createView().source(data)
@@ -1187,7 +1070,7 @@
      })
    }
    if (!plot.legend || plot.legend === 'hidden') {
    if (!plot.legend) {
      chart.legend(false)
    } else {
      chart.legend({
@@ -1264,20 +1147,30 @@
        range: [0, 0.9]
      }
  
      if (plot.min || plot.min === 0) {
        c.min = plot.min
      }
      if (plot.max || plot.max === 0) {
        c.max = plot.max
      if (plot.zoomYaxis === 'adjust') {
        if (max) {
          c.min = 0
          c.max = max
        }
      } else {
        if (plot.min || plot.min === 0) {
          c.min = plot.min
        }
        if (plot.max || plot.max === 0) {
          c.max = plot.max
          c.min = c.min || 0
        }
      }
      view1.scale('value', c)
      view1.axis('value', plot.$yc)
  
      // view1.legend(false)
      if (plot.legend) {
        view1.legend(false)
      }
      let colorIndex = 0
  
      if (plot.adjust !== 'stack') {
      if (plot.mutilBar !== 'stack') {
        let _chart = view1
          .interval()
          .position(`${plot.Xaxis}*value`)
@@ -1289,12 +1182,16 @@
          ])
          .shape(plot.shape || 'rect')
          .tooltip(`${plot.Xaxis}*value*key`, (name, value, key) => {
            let val = value
            if (plot.show === 'percent') {
              value = value + '%'
              val = value + '%'
            } else if (plot.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            return {
              name: key,
              value: value
              value: val
            }
          })
@@ -1311,45 +1208,53 @@
        } else {
          _chart.color('key')
        }
        if (plot.label !== 'false') {
        if (plot.$label !== 'false') {
          _chart.label('value*key', (value, key) => {
            if (plot.labelValue === 'zero' && value === 0) {
            if (plot.$label !== 'true' && value === 0) {
              return null
            }
            let val = value
            if (plot.show === 'percent') {
              value = value + '%'
              val = value + '%'
            } else if (plot.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
            if (plot.$label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
              lablecfg.style.fill = plot.$colors.get(key)
            }
            return {
              content: value,
              content: val,
              ...lablecfg
            }
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.barRadius) {
          _chart.style({ radius: [plot.barRadius, plot.barRadius, 0, 0] })
        }
      } else if (plot.adjust === 'stack') {
      } 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) => {
            let val = value
            if (plot.show === 'percent') {
              value = value + '%'
              val = value + '%'
            } else if (plot.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            return {
              name: type,
              value: value
              value: val
            }
          })
  
@@ -1366,26 +1271,30 @@
        } else {
          _chart.color('key')
        }
        if (plot.label !== 'false') {
        if (plot.$label !== 'false') {
          _chart.label('value*key', (value, key) => {
            if (plot.labelValue === 'zero' && value === 0) {
            if (plot.$label !== 'true' && value === 0) {
              return null
            }
            let val = value
            if (plot.show === 'percent') {
              value = value + '%'
              val = value + '%'
            } else if (plot.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
            if (plot.$label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
              lablecfg.style.fill = plot.$colors.get(key)
            }
            return {
              content: value,
              content: val,
              ...lablecfg
            }
          })
        }
        if (plot.barSize || plot.correction) {
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (plot.barRadius) {
@@ -1407,7 +1316,10 @@
    }
    view2.data(dv.rows)
    // view2.legend(false)
    if (plot.legend && plot.Bar_axis) {
      view2.legend(false)
    }
    plot.customs.forEach(item => {
      if (item.chartType === 'bar' && !plot.Bar_axis) {
@@ -1418,11 +1330,18 @@
          range: [0, 0.9]
        }
    
        if (item.min || item.min === 0) {
          c.min = item.min
        }
        if (item.max || item.max === 0) {
          c.max = item.max
        if (plot.zoomYaxis === 'adjust') {
          if (max) {
            c.min = 0
            c.max = max
          }
        } else {
          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)
@@ -1432,9 +1351,16 @@
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${item.name}`, (value) => {
            let val = value
            if (item.show === 'percent') {
              val = value + '%'
            } else if (item.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            return {
              name: item.name,
              value: item.show === 'percent' ? value + '%' : value
              value: val
            }
          })
@@ -1443,18 +1369,22 @@
        }
        if (item.label !== 'false') {
          _chart.label(item.name, (value) => {
            if (plot.labelValue === 'zero' && value === 0) {
            if (plot.label !== 'true' && value === 0) {
              return null
            }
            let val = value
            if (item.show === 'percent') {
              value = value + '%'
              val = value + '%'
            } else if (item.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            if (plot.label === 'true' && plot.labelColor === 'custom' && item.color) {
              lablecfg.style.fill = item.color
            }
            return {
              content: value,
              content: val,
              ...lablecfg
            }
          })
@@ -1473,11 +1403,18 @@
          range: [0, 0.9]
        }
    
        if (item.min || item.min === 0) {
          c.min = item.min
        }
        if (item.max || item.max === 0) {
          c.max = item.max
        if (plot.zoomYaxis === 'adjust') {
          if (max) {
            c.min = 0
            c.max = max
          }
        } else {
          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)
@@ -1487,23 +1424,32 @@
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${item.name}`, (value) => {
            let val = value
            if (item.show === 'percent') {
              val = value + '%'
            } else if (item.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            return {
              name: item.name,
              value: item.show === 'percent' ? value + '%' : value
              value: val
            }
          })
        if (item.label === 'true') {
          _chart.label(item.name, (value) => {
            if (plot.labelValue === 'zero' && value === 0) {
              return null
            let val = value
            if (item.show === 'percent') {
              val = value + '%'
            } else if (item.show === 'thdSeparator') {
              val = val + ''
              val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
            }
            if (item.show === 'percent') {
              value = value + '%'
            }
            return {
              content: value,
              content: val,
              style: {
                fill: plot.color
              }
@@ -1611,13 +1557,14 @@
    }
    if (plot.max || plot.max === 0) {
      c.max = plot.max
      c.min = c.min || 0
    }
    chart.scale(_valfield, c)
    chart.axis(plot.Xaxis, plot.$xc)
    chart.axis(_valfield, plot.$yc)
    if (!plot.legend || plot.legend === 'hidden') {
    if (!plot.legend) {
      chart.legend(false)
    } else {
      chart.legend({
@@ -1694,9 +1641,16 @@
        ])
        .shape(plot.shape || 'rect')
        .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
          let val = value
          if (plot.show === 'percent') {
            val = value + '%'
          } else if (plot.show === 'thdSeparator') {
            val = val + ''
            val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
          }
          return {
            name: type,
            value: plot.show === 'percent' ? value + '%' : value
            value: val
          }
        })
@@ -1729,12 +1683,16 @@
      }
      if (plot.label !== 'false') {
        _chart.label(`${_valfield}*${_typefield}`, (value, key) => {
          if (plot.labelValue === 'zero' && value === 0) {
          if (plot.label !== 'true' && value === 0) {
            return null
          }
          let val = value
          if (plot.show === 'percent') {
            value = value + '%'
            val = value + '%'
          } else if (plot.show === 'thdSeparator') {
            val = val + ''
            val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
          }
          if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
@@ -1742,13 +1700,13 @@
          }
          return {
            content: value,
            content: val,
            ...lablecfg
          }
        })
      }
      if (plot.barSize || plot.correction) {
      if (plot.barSize) {
        _chart.size(plot.barSize || 35)
      }
      if (plot.selectColor) {
@@ -1770,9 +1728,16 @@
        .adjust('stack')
        .shape(plot.shape || 'rect')
        .tooltip(`${plot.Xaxis}*${_valfield}*${_typefield}`, (name, value, type) => {
          let val = value
          if (plot.show === 'percent') {
            val = value + '%'
          } else if (plot.show === 'thdSeparator') {
            val = val + ''
            val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
          }
          return {
            name: type,
            value: plot.show === 'percent' ? value + '%' : value
            value: val
          }
        })
@@ -1804,12 +1769,16 @@
      }
      if (plot.label !== 'false') {
        _chart.label(`${_valfield}*${_typefield}`, (value, key) => {
          if (plot.labelValue === 'zero' && value === 0) {
          if (plot.label !== 'true' && value === 0) {
            return null
          }
          let val = value
          if (plot.show === 'percent') {
            value = value + '%'
            val = value + '%'
          } else if (plot.show === 'thdSeparator') {
            val = val + ''
            val = val.replace(/\d{1,3}(?=(\d{3})+(\.\d*)?$)/g, '$&,')
          }
          if (plot.label === 'true' && plot.labelColor === 'custom' && plot.$colors && plot.$colors.has(key)) {
@@ -1817,13 +1786,13 @@
          }
          return {
            content: value,
            content: val,
            ...lablecfg
          }
        })
      }
      if (plot.barSize || plot.correction) {
      if (plot.barSize) {
        _chart.size(plot.barSize || 35)
      }
      if (plot.selectColor) {
src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -353,8 +353,6 @@
  /**
   * @description 图表数据预处理
   * 1、通过显示列进行数据类型转换
   * 2、重复数据:取平均值、累计、去重
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { plot } = this.state
@@ -362,91 +360,22 @@
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    } else {
      this.setState({empty: false})
    }
    let _data = []
    let _cdata = fromJS(this.data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
      _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]) {
          return
    return fromJS(this.data).toJS().map(item => {
      if (typeof(item[plot.Yaxis]) !== 'number') {
        item[plot.Yaxis] = parseFloat(item[plot.Yaxis])
        if (isNaN(item[plot.Yaxis])) {
          item[plot.Yaxis] = 0
        }
      }
        if (!_mdata.has(item[plot.Xaxis])) {
          item.$count = 1
          _mdata.set(item[plot.Xaxis], item)
        } else {
          let _item = _mdata.get(item[plot.Xaxis])
          _item.$count++
          _item[plot.Yaxis] += item[plot.Yaxis]
          _mdata.set(item[plot.Xaxis], _item)
        }
      })
      item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
      _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()
      _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]) {
          return
        }
        if (!_mdata.has(item[plot.Xaxis])) {
          _mdata.set(item[plot.Xaxis], item)
        } else {
          let _item = _mdata.get(item[plot.Xaxis])
          _item[plot.Yaxis] += item[plot.Yaxis]
          _mdata.set(item[plot.Xaxis], _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()
      _cdata.forEach(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
      return item
    })
  }
  getnestdata = () => {
@@ -458,127 +387,40 @@
    }
    let _data = []
    let _cdata = fromJS(this.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]) {
    let _mdata = new Map()
    let map = new Map()
    let sort = 1
    fromJS(this.data).toJS().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
        }
      }
        item.$type = item[plot.type]
        let sign = item.$type + item[plot.Xaxis]
      item.$type = item[plot.type]
        if (!_mdata.has(sign)) {
          let _sort = sort
          if (map.has(item.$type)) {
            _sort = map.get(item.$type)
          } else {
            map.set(item.$type, _sort)
            sort++
          }
      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)
        }
      })
      item.$sort = _sort
      item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
      _data = [..._mdata.values()]
      _data = _data.map(item => {
        item[plot.Yaxis] = item[plot.Yaxis] / item.$count
        item[plot.Yaxis] = +item[plot.Yaxis].toFixed(plot.$decimal)
      _mdata.set(sign, true)
        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
        }
        item.$type = item[plot.type]
        let sign = item.$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
          }
        }
        item.$type = item[plot.type]
        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()]
    }
      _data.push(item)
    })
    this.setState({empty: _data.length === 0})
src/tabviews/custom/components/code/sand-box/index.jsx
@@ -318,8 +318,8 @@
      if (js) {
        try {
          // eslint-disable-next-line
          let evalfunc = eval('(true && function (data, result, Api, notification) {' + js + '})')
          evalfunc(data, result, Api, notification)
          let evalfunc = eval('(true && function (data, result, Api, notification, systemType) {' + js + '})')
          evalfunc(data, result, Api, notification, window.GLOB.systemType)
        } catch (e) {
          console.warn(e)
        }
src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -72,16 +72,14 @@
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.setting.sync === 'true') {
      MKEmitter.addListener('transferSyncData', this.transferSyncData)
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    } else if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    this.initExec()
src/tabviews/custom/components/form/simple-form/index.jsx
@@ -57,6 +57,13 @@
  
        window.GLOB.SyncData.delete(_config.dataName)
      }
    } else if (_config.wrap.datatype === 'public') {
      if (window.GLOB.CacheData.has(_config.wrap.publicId)) {
        _data = window.GLOB.CacheData.get(_config.wrap.publicId)
        _data = fromJS(_data).toJS()
        _data.$$BID = BID || ''
        _data.$$BData = BData || ''
      }
    } else {
      _data = {$$empty: true}
    }
@@ -85,12 +92,14 @@
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
    if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.setting.sync === 'true') {
      MKEmitter.addListener('transferSyncData', this.transferSyncData)
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    } else if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    this.initExec()
@@ -105,6 +114,7 @@
      return
    }
    MKEmitter.removeListener('reloadData', this.reloadData)
    MKEmitter.removeListener('mkPublicData', this.mkPublicData)
    MKEmitter.removeListener('mkFormSubmit', this.mkFormSubmit)
    MKEmitter.removeListener('searchRefresh', this.searchRefresh)
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
@@ -138,6 +148,23 @@
    MKEmitter.removeListener('transferSyncData', this.transferSyncData)
  }
  mkPublicData = (publicId, data) => {
    const { config, BID, BData } = this.state
    if (config.wrap.datatype === 'public' && config.wrap.publicId === publicId) {
      let _data = fromJS(data).toJS()
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      this.setState({
        data: null
      }, () => {
        this.setState({data: _data})
      })
    }
  }
  searchRefresh = (searchId) => {
    const { config } = this.state
@@ -149,11 +176,39 @@
  }
  reloadData = (menuId, id) => {
    const { config } = this.state
    const { config, group } = this.state
    if (config.uuid !== menuId) return
    this.loadData()
    if (id === 'focus-refresh' && config.wrap.refocus) {
      let _group = fromJS(group).toJS()
      _group.setting.focus = config.wrap.refocus
      if (config.wrap.datatype === 'static') {
        this.setState({
          data: null,
          group: _group
        }, () => {
          this.setState({data: {$$empty: true}})
        })
      } else {
        this.setState({
          group: _group
        }, () => {
          this.loadData(true)
        })
      }
    } else if (id === 'focus-nofresh' && config.wrap.refocus) {
      let formId = ''
      group.fields.forEach(item => {
        if (item.field === config.wrap.refocus) {
          formId = item.uuid
        }
      })
      MKEmitter.emit('mkFC', 'focus', formId)
    } else {
      this.loadData()
    }
  }
  /**
@@ -165,7 +220,16 @@
  refreshByButtonResult = (menuId, position, btn, id) => {
    const { config, group, BID } = this.state
    if (group.uuid !== menuId) return
    if (config.uuid !== menuId) return
    if (position === 'grid' && config.wrap.refocus) {
      let _group = fromJS(group).toJS()
      _group.setting.focus = config.wrap.refocus
      this.setState({
        group: _group
      })
    }
    if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) {
      MKEmitter.emit('reloadData', config.setting.supModule, BID)
@@ -176,7 +240,7 @@
        this.setState({data: {$$empty: true}})
      })
    } else {
      this.loadData()
      this.loadData(position === 'grid')
    }
    if (id) {
@@ -226,10 +290,22 @@
    }
  }
  async loadData () {
    const { config, BID } = this.state
  async loadData (refocus) {
    const { config, BID, group } = this.state
    if (config.wrap.datatype === 'static') {
    if (config.wrap.refocus && !refocus && group.setting.focus === config.wrap.refocus) {
      let _group = fromJS(group).toJS()
      _group.setting.focus = config.wrap.focus
      this.setState({
        group: _group
      })
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.emit('reloadData', config.wrap.publicId)
      return
    } else if (config.wrap.datatype === 'static') {
      this.setState({
        data: {$$empty: true}
      })
@@ -308,13 +384,15 @@
    }
  }
  mkFormSubmit = (btnId) => {
  mkFormSubmit = (btnId, callback, formId) => {
    const { group } = this.state
    if (group.uuid !== btnId) return
    this.formRef.handleConfirm().then(res => {
    this.formRef.handleConfirm(formId).then(res => {
      MKEmitter.emit('triggerFormSubmit', {menuId: btnId, form: res})
    }, () => {
      callback && callback()
    })
  }
@@ -355,7 +433,7 @@
          data={data}
          action={group}
          unload={config.setting.supModule && !BID}
          inputSubmit={() => this.mkFormSubmit(group.uuid)}
          inputSubmit={(id) => this.mkFormSubmit(group.uuid, null, id)}
          wrappedComponentRef={(inst) => this.formRef = inst}
        /> : null}
        {data ? <div className={'mk-form-action ' + (group.$button || '')}>
src/tabviews/custom/components/form/step-form/index.jsx
@@ -57,6 +57,13 @@
  
        window.GLOB.SyncData.delete(_config.dataName)
      }
    } else if (_config.wrap.datatype === 'public') {
      if (window.GLOB.CacheData.has(_config.wrap.publicId)) {
        _data = window.GLOB.CacheData.get(_config.wrap.publicId)
        _data = fromJS(_data).toJS()
        _data.$$BID = BID || ''
        _data.$$BData = BData || ''
      }
    } else {
      _data = {$$empty: true}
    }
@@ -126,12 +133,14 @@
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
    if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.setting.sync === 'true') {
      MKEmitter.addListener('transferSyncData', this.transferSyncData)
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    } else if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    this.initExec()
@@ -146,6 +155,7 @@
      return
    }
    MKEmitter.removeListener('reloadData', this.reloadData)
    MKEmitter.removeListener('mkPublicData', this.mkPublicData)
    MKEmitter.removeListener('mkFormSubmit', this.mkFormSubmit)
    MKEmitter.removeListener('searchRefresh', this.searchRefresh)
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
@@ -187,6 +197,23 @@
    MKEmitter.removeListener('transferSyncData', this.transferSyncData)
  }
  mkPublicData = (publicId, data) => {
    const { config, BID, BData } = this.state
    if (config.wrap.datatype === 'public' && config.wrap.publicId === publicId) {
      let _data = fromJS(data).toJS()
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      this.setState({
        data: null
      }, () => {
        this.setState({data: _data})
      })
    }
  }
  searchRefresh = (searchId) => {
    const { config } = this.state
@@ -212,9 +239,9 @@
   * @param {*} btn        // 执行的按钮
   */
  refreshByButtonResult = (menuId, position, btn, id) => {
    const { config, group, BID } = this.state
    const { config, BID } = this.state
    if (group.uuid !== menuId) return
    if (config.uuid !== menuId) return
    if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) {
      MKEmitter.emit('reloadData', config.setting.supModule, BID)
@@ -290,7 +317,10 @@
  async loadData (type) {
    const { config, BID } = this.state
    if (config.wrap.datatype === 'static') {
    if (config.wrap.datatype === 'public') {
      MKEmitter.emit('reloadData', config.wrap.publicId)
      return
    } else if (config.wrap.datatype === 'static') {
      this.setState({
        data: {$$empty: true}
      })
@@ -388,13 +418,15 @@
    }
  }
  mkFormSubmit = (btnId) => {
  mkFormSubmit = (btnId, callback) => {
    const { group } = this.state
    if (group.uuid !== btnId) return
    this.formRef.handleConfirm().then(res => {
      MKEmitter.emit('triggerFormSubmit', {menuId: btnId, form: res})
    }, () => {
      callback && callback()
    })
  }
@@ -461,7 +493,7 @@
          inputSubmit={() => this.mkFormSubmit(group.uuid)}
          wrappedComponentRef={(inst) => this.formRef = inst}
        /> : null}
        {group && data ? <div className={'mk-form-action ' + (group.$button || '')}>
        {group && data ? <div className={'mk-form-action ' + (group.$button || '') + (group.nextButton.enable === 'true' ? ' has-skip' : '')}>
          {group.prevButton.enable === 'true' ? <Button type="link" className="prev" onClick={this.prevStep} style={group.prevButton.style}>{group.prevButton.label}</Button> : null}
          <NormalButton
            BID={BID}
src/tabviews/custom/components/form/step-form/index.scss
@@ -84,6 +84,9 @@
    padding: 0;
    height: 0;
  }
  .mk-form-action.has-skip {
    padding-right: 50px;
  }
  
  .loading-mask {
    position: absolute;
src/tabviews/custom/components/form/tab-form/index.jsx
@@ -56,6 +56,13 @@
  
        window.GLOB.SyncData.delete(_config.dataName)
      }
    } else if (_config.wrap.datatype === 'public') {
      if (window.GLOB.CacheData.has(_config.wrap.publicId)) {
        _data = window.GLOB.CacheData.get(_config.wrap.publicId)
        _data = fromJS(_data).toJS()
        _data.$$BID = BID || ''
        _data.$$BData = BData || ''
      }
    } else {
      _data = {$$empty: true}
    }
@@ -100,12 +107,14 @@
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult)
    if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    if (config.setting.sync === 'true') {
      MKEmitter.addListener('transferSyncData', this.transferSyncData)
    }
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    } else if (config.setting.useMSearch) {
      MKEmitter.addListener('searchRefresh', this.searchRefresh)
    }
    this.initExec()
@@ -120,6 +129,7 @@
      return
    }
    MKEmitter.removeListener('reloadData', this.reloadData)
    MKEmitter.removeListener('mkPublicData', this.mkPublicData)
    MKEmitter.removeListener('mkFormSubmit', this.mkFormSubmit)
    MKEmitter.removeListener('searchRefresh', this.searchRefresh)
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
@@ -153,6 +163,23 @@
    MKEmitter.removeListener('transferSyncData', this.transferSyncData)
  }
  mkPublicData = (publicId, data) => {
    const { config, BID, BData } = this.state
    if (config.wrap.datatype === 'public' && config.wrap.publicId === publicId) {
      let _data = fromJS(data).toJS()
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      this.setState({
        data: null
      }, () => {
        this.setState({data: _data})
      })
    }
  }
  searchRefresh = (searchId) => {
    const { config } = this.state
@@ -178,9 +205,9 @@
   * @param {*} btn        // 执行的按钮
   */
  refreshByButtonResult = (menuId, position, btn, id) => {
    const { config, group, BID } = this.state
    const { config, BID } = this.state
    if (group.uuid !== menuId) return
    if (config.uuid !== menuId) return
    if ((position === 'mainline' || position === 'popclose') && config.setting.supModule && BID) {
      MKEmitter.emit('reloadData', config.setting.supModule, BID)
@@ -243,7 +270,10 @@
  async loadData () {
    const { config, BID } = this.state
    if (config.wrap.datatype === 'static') {
    if (config.wrap.datatype === 'public') {
      MKEmitter.emit('reloadData', config.wrap.publicId)
      return
    } else if (config.wrap.datatype === 'static') {
      this.setState({
        data: {$$empty: true}
      })
@@ -322,13 +352,15 @@
    }
  }
  mkFormSubmit = (btnId) => {
  mkFormSubmit = (btnId, callback) => {
    const { group } = this.state
    if (group.uuid !== btnId) return
    this.formRef.handleConfirm().then(res => {
      MKEmitter.emit('triggerFormSubmit', {menuId: btnId, form: res})
    }, () => {
      callback && callback()
    })
  }
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -499,10 +499,6 @@
            } else if (_format && !Math.floor(Math.random() * radio)) {
              item.blur = true
            }
            if (item.marks && item.marks.length === 0) {
              item.marks = ''
            }
  
            if (item.field) {
              orderfields[item.uuid] = item.field
@@ -838,6 +834,8 @@
  onSelectChange = (selectedRowKeys, e) => {
    const { setting, MenuID, data } = this.props
    if (this.state.pickup) return
    let index = ''
    let _activeIndex = null
    if (selectedRowKeys.length > 0) {
src/tabviews/custom/components/share/normalTable/index.scss
@@ -1,11 +1,19 @@
.normal-custom-table {
  position: relative;
  padding: 0px;
  min-height: 40px;
  --mk-table-border-color: #e8e8e8;
  --mk-table-color: rgba(0, 0, 0, 0.65);
  --mk-table-font-size: 14px;
  --mk-table-font-weight: normal;
  .main-pickup {
    position: absolute;
    right: 5px;
    top: -22px;
    z-index: 2;
  }
  .normal-table-footer {
    padding: 10px 0px;
    color: rgba(0, 0, 0, 0.65);
@@ -95,6 +103,7 @@
        .card-cell-list {
          color: inherit;
          overflow: hidden;
        }
        .ant-mk-picture {
          position: relative;
src/tabviews/custom/components/table/base-table/index.jsx
@@ -261,7 +261,7 @@
  /**
   * @description 获取单行数据
   */ 
  async loadmainLinedata (id) {
  async loadLinedata (id, position) {
    const { setting, config, search, orderBy, BID, pageIndex, pageSize, BData } = this.state
    if (config.forbidLine) {
@@ -289,6 +289,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (position === 'line_grid' && (!result.data || !result.data[0])) {
        this.loadmaindata(true, 'false')
        return
      }
      let data = fromJS(this.state.data).toJS()
      let selectedData = fromJS(this.state.selectedData).toJS()
@@ -547,7 +552,7 @@
    if (!id) {
      this.reloadtable()
    } else {
      this.loadmainLinedata(id)
      this.loadLinedata(id)
    }
  }
@@ -578,9 +583,9 @@
    if (config.uuid !== menuId) return
    if (position === 'line') {
    if (position === 'line' || position === 'line_grid') {
      if (lines && lines.length === 1) {
        this.loadmainLinedata(lines[0].$$uuid)
        this.loadLinedata(lines[0].$$uuid, position)
      } else {
        this.reloadtable(btn, id)
      }
@@ -648,22 +653,20 @@
          columns={config.columns}
          selectedData={selectedData}
        /> : <div style={{height: '25px'}}></div>}
        <div className="main-table-box">
          <MainTable
            data={data}
            setting={setting}
            columns={columns}
            MenuID={config.uuid}
            fields={config.columns}
            total={this.state.total}
            autoMatic={config.autoMatic}
            lineMarks={config.lineMarks}
            loading={this.state.loading}
            refreshdata={this.refreshbytable}
            statFValue={this.state.statFValue}
            chgSelectData={(selects) => this.setState({selectedData: selects})}
          />
        </div>
        <MainTable
          data={data}
          setting={setting}
          columns={columns}
          MenuID={config.uuid}
          fields={config.columns}
          total={this.state.total}
          autoMatic={config.autoMatic}
          lineMarks={config.lineMarks}
          loading={this.state.loading}
          refreshdata={this.refreshbytable}
          statFValue={this.state.statFValue}
          chgSelectData={(selects) => this.setState({selectedData: selects})}
        />
      </div>
    )
  }
src/tabviews/custom/components/table/base-table/index.scss
@@ -12,17 +12,4 @@
  .button-list.toolbar-button {
    padding-right: 60px;
  }
  .main-table-box {
    position: relative;
    min-height: 40px;
    .main-pickup {
      position: absolute;
      right: 5px;
      top: -22px;
      z-index: 2;
    }
    >.async-spin {
      line-height: 150px!important;
    }
  }
}
src/tabviews/custom/components/table/edit-table/index.jsx
@@ -113,10 +113,6 @@
            item.type = 'text'
          }
          if (item.marks && item.marks.length === 0) {
            item.marks = ''
          }
          if (item.editable === 'true') {
            setting.hasSubmit = setting.commit !== 'change'
            item.$ctrl = setting.commit === 'change'
@@ -388,7 +384,7 @@
  /**
   * @description 获取单行数据
   */ 
  async loadmainLinedata (id) {
  async loadLinedata (id, position) {
    const { setting, config, search, orderBy, BID, pageIndex, pageSize, BData } = this.state
    if (config.forbidLine) {
@@ -416,11 +412,25 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (position === 'line_grid' && (!result.data || !result.data[0])) {
        this.loadmaindata(true, 'false')
        return
      }
      if (!result.data || !result.data[0]) {
        let data = fromJS(this.state.data).toJS()
        let selectedData = fromJS(this.state.selectedData).toJS()
        data = data.filter(item => item.$$uuid !== id)
        selectedData = selectedData.filter(item => item.$$uuid !== id)
        MKEmitter.emit('transferData' + setting.tableId, id, 'delete')
        this.setState({
          data,
          selectedData,
          loading: false
        })
        return
      }
@@ -560,7 +570,7 @@
    if (!id) {
      this.reloadtable()
    } else {
      this.loadmainLinedata(id)
      this.loadLinedata(id)
    }
  }
@@ -592,9 +602,9 @@
    if (config.uuid !== menuId) return
    if (position === 'line') {
    if (position === 'line' || position === 'line_grid') {
      if (lines && lines.length === 1) {
        this.loadmainLinedata(lines[0].$$uuid)
        this.loadLinedata(lines[0].$$uuid, position)
      } else {
        this.reloadtable(btn)
      }
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -1345,6 +1345,7 @@
  timer = null
  focusId = ''
  blurId = ''
  colId = ''
  UNSAFE_componentWillMount () {
    const { setting, fields, columns, BID, colsCtrls } = this.props
@@ -1562,8 +1563,9 @@
    }, 150)
  }
  colFocus = (lineId) => {
  colFocus = (lineId, colId) => {
    this.focusId = lineId
    this.colId = colId
  }
  checkLine = () => {
@@ -1705,9 +1707,11 @@
  }
  transferData = (data, type) => {
    const { edData } = this.state
    const { edData, tableId } = this.state
    if (type === 'line') {
    if (type === 'delete') {
    } else if (type === 'line') {
      let value = ''
      Object.keys(data).sort().forEach(key => {
        if (/^\$/.test(key)) return
@@ -1725,14 +1729,18 @@
      })
    }
    if (type !== 'line') {
      let index = edData.findIndex(item => !item.$origin && !item.$forbid)
    if (type === 'delete') {
      let _edData = this.state.edData.filter(item => item.$$uuid !== data)
      if (index > -1) {
        this.setState({visible: true, midData: data})
      } else {
        this.updateMutil(data)
      }
      this.setState({edData: _edData, reseting: true}, () => {
        this.setState({reseting: false})
        if (this.focusId) {
          setTimeout(() => {
            MKEmitter.emit('setFocus' + tableId, this.focusId, this.colId)
          }, 10)
        }
      })
    } else if (type === 'line') {
      let _edData = this.state.edData.map(item => {
        if (item.$$uuid === data.$$uuid) {
@@ -1744,7 +1752,21 @@
      this.setState({edData: _edData, reseting: true}, () => {
        this.setState({reseting: false})
        if (this.focusId) {
          setTimeout(() => {
            MKEmitter.emit('setFocus' + tableId, this.focusId, this.colId)
          }, 10)
        }
      })
    } else {
      let index = edData.findIndex(item => !item.$origin && !item.$forbid)
      if (index > -1) {
        this.setState({visible: true, midData: data})
      } else {
        this.updateMutil(data)
      }
    }
  }
@@ -1995,7 +2017,7 @@
      setTimeout(() => {
        this.plusLine(colId)
      }, 10)
    } else if (edData[index] && setting.commit !== 'change') {
    } else if (edData[index] && (setting.commit === 'all' || setting.commit === 'amend')) {
      setTimeout(() => {
        this.submit()
      }, 10)
@@ -2136,7 +2158,7 @@
  checkData = () => {
    const { setting } = this.props
    const { edData, forms, checkForms } = this.state
    const { edData, forms, checkForms, selectedRowKeys } = this.state
    let data = fromJS(edData).toJS()
@@ -2144,6 +2166,17 @@
    if (setting.commit === 'amend') {
      data = data.filter(item => !item.$origin)
    } else if (setting.commit === 'check') {
      data = data.filter(item => selectedRowKeys.includes(item.$$uuid))
      if (data.length === 0) {
        notification.warning({
          top: 92,
          message: '请选择需要提交的数据!',
          duration: 5
        })
        return null
      }
    }
    if (data.length === 0) {
@@ -2298,9 +2331,9 @@
      Api.genericInterface(param).then((res) => {
        if (res.status) {
          this.execSuccess(res)
          this.execSuccess(res, record)
        } else {
          this.execError(res)
          this.execError(res, record)
        }
      }, (error) => {
        if (error && error.ErrCode === 'LoginError') return
@@ -2317,9 +2350,9 @@
      Api.genericInterface(param).then((res) => {
        if (res.status) {
          this.execSuccess(res)
          this.execSuccess(res, record)
        } else {
          this.execError(res)
          this.execError(res, record)
        }
      }, (error) => {
        if (error && error.ErrCode === 'LoginError') return
@@ -2329,7 +2362,7 @@
    }
  }
  execSuccess = (res) => {
  execSuccess = (res, record) => {
    const { submit } = this.props
    const { edData } = this.state
@@ -2379,13 +2412,13 @@
    }
    if (submit.execSuccess !== 'never') {
      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit)
      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execSuccess, submit, '', record ? [record] : null)
    }
    submit.syncComponentId && MKEmitter.emit('reloadData', submit.syncComponentId)
  }
  execError = (res) => {
  execError = (res, record) => {
    const { submit } = this.props
    if (res.ErrCode === 'E') {
@@ -2414,7 +2447,7 @@
    })
    if (submit.execError !== 'never') {
      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit)
      MKEmitter.emit('refreshByButtonResult', submit.$menuId, submit.execError, submit, '', record ? [record] : null)
    }
  }
src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -65,6 +65,7 @@
        .card-cell-list {
          color: inherit;
          overflow: hidden;
        }
        .action-col {
          .ant-btn > .anticon + span {
src/tabviews/custom/components/table/normal-table/index.jsx
@@ -539,7 +539,7 @@
  /**
   * @description 获取单行数据
   */ 
  async loadmainLinedata (id) {
  async loadLinedata (id, position) {
    const { setting, config, search, orderBy, BID, pageIndex, pageSize, BData } = this.state
    if (config.forbidLine) {
@@ -567,6 +567,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (position === 'line_grid' && (!result.data || !result.data[0])) {
        this.loadmaindata(true, 'false')
        return
      }
      let data = fromJS(this.state.data).toJS()
      let selectedData = fromJS(this.state.selectedData).toJS()
@@ -743,7 +748,7 @@
    if (!id) {
      this.reloadtable()
    } else {
      this.loadmainLinedata(id)
      this.loadLinedata(id)
    }
  }
@@ -774,9 +779,9 @@
    if (config.uuid !== menuId) return
    if (position === 'line') {
    if (position === 'line' || position === 'line_grid') {
      if (lines && lines.length === 1) {
        this.loadmainLinedata(lines[0].$$uuid)
        this.loadLinedata(lines[0].$$uuid, position)
      } else {
        this.reloadtable(btn, id)
      }
@@ -830,7 +835,7 @@
    }
    let content = <>
      {config.search && config.search.length ?
      {config.search.length ?
        <MainSearch BID={BID} config={config} refreshdata={this.refreshbysearch}/> : null
      }
      {actions.length > 0 ? <MainAction
@@ -840,24 +845,22 @@
        BData={BData}
        columns={config.columns}
        selectedData={selectedData}
      /> : <div className="mk-action-space" style={{height: '25px'}}></div>}
      <div className={'main-table-box ' + (!actions || actions.length === 0 ? 'no-action' : '')}>
        <MainTable
          setting={setting}
          columns={columns}
          MenuID={config.uuid}
          allSearch={allSearch}
          data={this.state.data}
          fields={config.columns}
          total={this.state.total}
          colsCtrls={config.colsCtrls}
          lineMarks={config.lineMarks}
          loading={this.state.loading}
          refreshdata={this.refreshbytable}
          statFValue={this.state.statFValue}
          chgSelectData={(selects) => this.setState({selectedData: selects})}
        />
      </div>
      /> : (setting.tableType || config.search.length > 0 ? <div className="mk-action-space" style={{height: '25px'}}></div> : null)}
      <MainTable
        setting={setting}
        columns={columns}
        MenuID={config.uuid}
        allSearch={allSearch}
        data={this.state.data}
        fields={config.columns}
        total={this.state.total}
        colsCtrls={config.colsCtrls}
        lineMarks={config.lineMarks}
        loading={this.state.loading}
        refreshdata={this.refreshbytable}
        statFValue={this.state.statFValue}
        chgSelectData={(selects) => this.setState({selectedData: selects})}
      />
    </>
    return (
src/tabviews/custom/components/table/normal-table/index.scss
@@ -12,19 +12,6 @@
  .button-list.toolbar-button {
    padding-right: 60px;
  }
  .main-table-box {
    position: relative;
    min-height: 40px;
    .main-pickup {
      position: absolute;
      right: 5px;
      top: -22px;
      z-index: 2;
    }
    >.async-spin {
      line-height: 150px!important;
    }
  }
  .ant-collapse {
    background-color: transparent;
    border-radius: 0px;
src/tabviews/custom/components/tabs/antv-tabs/index.jsx
@@ -146,7 +146,7 @@
    if (!tabs.subtabs.length) return null
    return (
      <div className={'menu-antv-tabs-wrap ' + (tabs.setting.tabLabel || '')} id={'anchor' + tabs.uuid} style={tabs.style}>
      <div className={`menu-antv-tabs-wrap ${tabs.setting.tabLabel || ''} ${tabs.setting.cusClass || ''}`} id={'anchor' + tabs.uuid} style={tabs.style}>
        <Tabs defaultActiveKey="1" tabBarStyle={{background: tabs.setting.backgroundColor || 'transparent'}} tabPosition={tabs.setting.position} type={tabs.setting.tabStyle}>
          {tabs.subtabs.map(tab => (
            <TabPane tab={<span id={'tab' + tab.uuid}>{tab.icon ? <MkIcon type={tab.icon} /> : null}{tab.label}</span>} style={{backgroundColor: tab.backgroundColor || 'transparent'}} key={tab.uuid}>
src/tabviews/custom/components/tabs/antv-tabs/index.scss
@@ -28,3 +28,35 @@
.menu-antv-tabs-wrap.hide >.ant-tabs >.ant-tabs-bar{
  display: none;
}
.menu-antv-tabs-wrap.mk-tab-button >.ant-tabs >.ant-tabs-bar {
  border-bottom: 0px;
  .ant-tabs-nav-scroll {
    margin-bottom: 2px;
    .ant-tabs-ink-bar {
      display: none!important;
    }
    .ant-tabs-tab {
      margin-right: 10px;
      border: 1px solid var(--mk-sys-color3);
      padding: 8px 35px;
      border-radius: 40px;
      color: var(--mk-sys-color);
      background: #ffffff;
      transition: all 0.2s;
    }
    .ant-tabs-tab.ant-tabs-tab-active {
      border: 1px solid var(--mk-sys-color);
      background: var(--mk-sys-color);
      color: #ffffff;
    }
    .ant-tabs-tab:last-child {
      margin-right: 0px;
    }
  }
}
.menu-antv-tabs-wrap.mk-tab-button.tab-right >.ant-tabs >.ant-tabs-bar {
  .ant-tabs-nav-scroll {
    text-align: right;
  }
}
src/tabviews/custom/components/timeline/normal-timeline/index.jsx
@@ -559,7 +559,7 @@
    if (config.wrap.empty === 'hidden' && (!data || data.length === 0)) return null
    
    return (
      <div className="normal-timeline-box" id={'anchor' + config.uuid} style={{...config.style}}>
      <div className={'normal-timeline-box ' + (config.wrap.btnControl || '')} id={'anchor' + config.uuid} style={{...config.style}}>
        {loading ?
          <div className="loading-mask">
            {data ? <div className="ant-spin-blur"></div> : null}
src/tabviews/custom/components/timeline/normal-timeline/index.scss
@@ -251,6 +251,14 @@
    }
  }
}
.normal-timeline-box.hover {
 .card-item-box:not(:hover) {
    button {
      opacity: 0;
      transition: opacity 0.3s;
    }
  }
}
.normal-timeline-box::after {
  content: ' ';
src/tabviews/custom/index.jsx
@@ -554,6 +554,7 @@
            item.wrap.datatype = 'static'
          } else {
            item.setting = {...inter.setting}
            item.$searchId = inter.$searchId
          }
        }
      }
@@ -658,6 +659,10 @@
              col.linkThdMenu = window.GLOB.mkThdMenus.get(menu_id) || ''
            } else {
              col.linkThdMenu = ''
            }
            if (col.marks && col.marks.length === 0) {
              col.marks = null
            }
            return true
@@ -771,34 +776,17 @@
      } else if (item.type === 'form') {
        item.subcards = item.subcards.map(group => {
          group.subButton.uuid = group.uuid
          group.subButton.$menuId = group.uuid
          group.subButton.$MenuID = this.props.MenuID
          // group.subButton.$forbid = true // 不声明数据源变量
          group.subButton.OpenType = 'formSubmit'
          group.subButton.execError = 'never'
          group.subButton.logLabel = item.$menuname + '-' + group.subButton.label
          if (!group.subButton.Ot) {
            group.subButton.Ot = item.wrap.datatype === 'static' ? 'notRequired' : 'requiredSgl'
          }
          if (item.$process) {
            group.subButton.$process = true
            group.subButton.$flowId = 'flow' + this.props.MenuID
          }
          group.subButton = this.resetButton(item, group.subButton)
          if (item.$cache && item.$time) {
          if (item.$cache && item.$time) { // 表单缓存
            group.$cache = item.$cache
            group.$time = item.$time
          }
          group.subButton.syncComponentId = group.subButton.syncComponent ? (group.subButton.syncComponent.pop() || '') : ''
          if (group.subButton.syncComponentId && group.subButton.syncComponentId === item.setting.supModule) {
            group.subButton.syncComponentId = ''
            if (group.subButton.execSuccess === 'grid') {
              group.subButton.execSuccess = 'mainline'
            }
          }
          group.fields = group.fields.map(cell => {
@@ -916,6 +904,30 @@
      cell.modal.uuid = cell.uuid + 'pop'
    }
    if (cell.verify && cell.verify.invalid === 'true') {
      if (item.wrap && (item.wrap.datatype === 'static' || item.wrap.datatype === 'public')) {
        cell.verify.invalid = 'false'
      } else if (item.setting && item.setting.maxScript && item.setting.maxScript >= 300) {
        cell.verify.invalid = 'false'
      } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
      } else if (cell.sqlType === 'insert') {
        cell.verify.invalid = 'false'
      } else if (cell.Ot === 'notRequired') {
        cell.verify.invalid = 'false'
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      try {
        // eslint-disable-next-line
        let func = new Function('btn', 'systemType', cell.verify.pre_func)
        func(cell, window.GLOB.systemType)
      } catch (e) {
        console.warn(e)
      }
    }
    if (cell.syncComponentId) {
      if (cell.syncComponentId === item.setting.supModule) {
        cell.syncComponentId = ''
@@ -950,6 +962,10 @@
    if (cell.style.display === 'inline-block') {
      cell.style.verticalAlign = 'top'
    }
    if (cell.marks && cell.marks.length === 0) {
      cell.marks = null
    }
    if (['text', 'number', 'formula'].includes(cell.eleType)) {
@@ -1022,9 +1038,6 @@
        component.components = this.formatSetting(component.components, params, null, regs, balMap)
        return component
      } else if (component.wrap && component.wrap.datatype === 'public') {
        component.setting.useMSearch = false
        component.setting.sync = 'false'
        return component
      } else if (component.wrap && component.wrap.datatype === 'static') {
        component.format = ''
@@ -1039,6 +1052,8 @@
      component.setting.arr_field = component.columns ? component.columns.map(col => col.field).join(',') : ''
      component.setting.useMSearch = component.setting.useMSearch === 'true'
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (component.setting.useMSearch) {
        if (!window.GLOB.SearchBox.has(component.$searchId)) {
          component.setting.useMSearch = false
@@ -1051,9 +1066,14 @@
        component.setting.sync = 'false'
      }
      if (component.format === 'object') {
        component.setting.laypage = false
        component.setting.$top = true
      }
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.laypage = component.setting.laypage === 'true'
        component.setting.dataresource = ''
        return component
      }
@@ -1074,8 +1094,7 @@
      delete component.scripts
      component.setting.$name = component.$menuname || ''
      component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (!component.setting.execute) {
        component.setting.dataresource = ''
      }
@@ -1191,6 +1210,8 @@
        inter.setting.onload = 'false'
      }
      inter.setting.laypage = false
      inter.setting.$top = true
      inter.setting.useMSearch = inter.setting.useMSearch === 'true'
      inter.setting.arr_field = inter.columns.map(col => col.field).join(',')
@@ -1214,7 +1235,6 @@
      inter.setting.$name = '公共数据源-' + inter.setting.name
      inter.setting.execute = inter.setting.execute !== 'false'
      inter.setting.laypage = true
      if (!inter.setting.execute) {
        inter.setting.dataresource = ''
src/tabviews/custom/popview/index.jsx
@@ -405,6 +405,10 @@
              col.linkThdMenu = ''
            }
            if (col.marks && col.marks.length === 0) {
              col.marks = null
            }
            return true
          })
        }
@@ -504,25 +508,14 @@
      } else if (item.type === 'form') {
        item.subcards = item.subcards.map(group => {
          group.subButton.uuid = group.uuid
          group.subButton.$menuId = group.uuid
          group.subButton.$MenuID = Tab.$MenuID
          group.subButton.OpenType = 'formSubmit'
          group.subButton.execError = 'never'
          group.subButton.logLabel = item.$menuname + '-' + group.subButton.label
          group.subButton.$tabId = Tab.uuid
          if (!group.subButton.Ot) {
            group.subButton.Ot = item.wrap.datatype === 'static' ? 'notRequired' : 'requiredSgl'
          }
          group.subButton.syncComponentId = group.subButton.syncComponent ? (group.subButton.syncComponent.pop() || '') : ''
          if (group.subButton.syncComponentId && group.subButton.syncComponentId === item.setting.supModule) {
            group.subButton.syncComponentId = ''
            if (group.subButton.execSuccess === 'grid') {
              group.subButton.execSuccess = 'mainline'
            }
          }
          group.subButton = this.resetButton(item, group.subButton, Tab)
          group.fields = group.fields.map(cell => {
            // 数据源sql语句,预处理,权限黑名单字段设置为隐藏表单
@@ -628,6 +621,30 @@
      }
    }
    if (cell.verify && cell.verify.invalid === 'true') {
      if (item.wrap && item.wrap.datatype === 'static') {
        cell.verify.invalid = 'false'
      } else if (item.setting && item.setting.maxScript && item.setting.maxScript >= 300) {
        cell.verify.invalid = 'false'
      } else if (cell.sqlType === 'insert') {
        cell.verify.invalid = 'false'
      } else if (cell.Ot === 'notRequired') {
        cell.verify.invalid = 'false'
      } else if (cell.intertype !== 'system' && cell.procMode !== 'system') {
        cell.verify.invalid = 'false'
      }
    }
    if (cell.verify && cell.verify.preHandle === 'true') {
      try {
        // eslint-disable-next-line
        let func = new Function('btn', 'systemType', cell.verify.pre_func)
        func(cell, window.GLOB.systemType)
      } catch (e) {
        console.warn(e)
      }
    }
    if (cell.syncComponentId) {
      if (cell.syncComponentId === item.setting.supModule) {
        cell.syncComponentId = ''
@@ -662,6 +679,10 @@
    if (cell.style.display === 'inline-block') {
      cell.style.verticalAlign = 'top'
    }
    if (cell.marks && cell.marks.length === 0) {
      cell.marks = null
    }
    if (['text', 'number', 'formula'].includes(cell.eleType)) {
@@ -712,12 +733,8 @@
      } else if (component.type === 'group') {
        component.components = this.formatSetting(component.components, params, regs, balMap)
        return component
      } else if (component.wrap && component.wrap.datatype === 'public') {
        component.setting.useMSearch = false
        component.setting.sync = 'false'
        return component
      } else if (component.wrap && component.wrap.datatype === 'static') {
      } else if (component.wrap && (component.wrap.datatype === 'static' || component.wrap.datatype === 'public')) {
        component.wrap.datatype = 'static'
        component.format = ''
        component.setting = component.setting || {}
        component.setting.useMSearch = false
@@ -730,6 +747,8 @@
      component.setting.arr_field = component.columns ? component.columns.map(col => col.field).join(',') : ''
      component.setting.useMSearch = component.setting.useMSearch === 'true'
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (component.setting.useMSearch) {
        if (!window.GLOB.SearchBox.has(component.$searchId)) {
          component.setting.useMSearch = false
@@ -738,9 +757,14 @@
        }
      }
      if (component.format === 'object') {
        component.setting.laypage = false
        component.setting.$top = true
      }
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.laypage = component.setting.laypage === 'true'
        component.setting.dataresource = ''
        return component
      }
@@ -761,7 +785,6 @@
      delete component.scripts
      component.setting.$name = component.$menuname || ''
      component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (!component.setting.execute) {
        component.setting.dataresource = ''
src/tabviews/subtable/index.jsx
@@ -238,6 +238,16 @@
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
          if (item.sqlType === 'insert') {
            item.verify.invalid = 'false'
          } else if (item.Ot === 'notRequired') {
            item.verify.invalid = 'false'
          } else if (item.intertype !== 'system' && item.procMode !== 'system') {
            item.verify.invalid = 'false'
          }
        }
        if (item.OpenType === 'funcbutton' && item.funcType === 'print' && item.verify) { // 打印机设置
          let _item = window.GLOB.UserCacheMap.get(Tab.uuid + item.uuid)
@@ -321,6 +331,8 @@
          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
        })
      } else {
        config.setting.dataresource = ''
      }
      if (config.setting.selected !== 'init' && config.setting.selected !== 'always') {
src/tabviews/subtabtable/index.jsx
@@ -210,6 +210,16 @@
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
          if (item.sqlType === 'insert') {
            item.verify.invalid = 'false'
          } else if (item.Ot === 'notRequired') {
            item.verify.invalid = 'false'
          } else if (item.intertype !== 'system' && item.procMode !== 'system') {
            item.verify.invalid = 'false'
          }
        }
        if (item.controlField) {
          if (/,/ig.test(item.controlVal)) {
            item.controlVals = item.controlVal.split(',')
@@ -278,6 +288,8 @@
          config.setting.dataresource = config.setting.dataresource.replace(cell.reg, cell.value)
          config.setting.customScript = config.setting.customScript.replace(cell.reg, cell.value)
        })
      } else {
        config.setting.dataresource = ''
      }
      if (config.setting.selected !== 'init' && config.setting.selected !== 'always') {
src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -199,9 +199,15 @@
      if (btn.syncComponentId === 'multiComponent') {
        btn.syncComponentIds.forEach((id, i) => {
          setTimeout(() => {
            MKEmitter.emit('reloadData', id)
            if (/\$focus/.test(id)) {
              MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
            } else {
              MKEmitter.emit('reloadData', id)
            }
          }, 20 * i)
        })
      } else if (/\$focus/.test(btn.syncComponentId)) {
        MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
      } else {
        MKEmitter.emit('reloadData', btn.syncComponentId)
      }
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -891,9 +891,15 @@
      if (btn.syncComponentId === 'multiComponent') {
        btn.syncComponentIds.forEach((id, i) => {
          setTimeout(() => {
            MKEmitter.emit('reloadData', id)
            if (/\$focus/.test(id)) {
              MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
            } else {
              MKEmitter.emit('reloadData', id)
            }
          }, 20 * i)
        })
      } else if (/\$focus/.test(btn.syncComponentId)) {
        MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
      } else {
        MKEmitter.emit('reloadData', btn.syncComponentId)
      }
src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -275,6 +275,7 @@
    return (
      <Button
        type={type}
        id={'button' + btn.uuid}
        title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
        style={btn.style || null}
        disabled={disabled}
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -47,6 +47,7 @@
  }
  moduleParams = null
  preCallback = null
  UNSAFE_componentWillMount () {
    const { btn, selectedData, BData, disabled } = this.props
@@ -180,33 +181,17 @@
  }
  actionSubmit = (res) => {
    const { btn, setting, BID } = this.props
    const { btn } = this.props
    const { selines } = this.state
    if (btn.uuid !== res.menuId) return
    let data = selines || []
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        duration: 3
      })
      return
    } else if (btn.Ot !== 'notRequired' && data.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择行!',
        duration: 5
      })
      return
    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        duration: 5
      })
    let valid = this.checkBtnData(data)
    if (!valid) {
      this.preCallback && this.preCallback()
      return
    }
@@ -214,122 +199,36 @@
    this.execSubmit(data, () => {}, res.form)
  }
  /**
   * @description 按钮状态改变
   */
  updateStatus = () => {
    this.setState({
      loading: false,
      visible: false,
      confirmLoading: false
    })
  }
  
  /**
   * @description 触发按钮操作
   */
  actionTrigger = (triggerId, record, type) => {
    const { BID, btn, selectedData, setting } = this.props
  actionTrigger = (triggerId, record, type, callback) => {
    const { btn, selectedData } = this.props
    const { loading, disabled } = this.state
    if (type === 'preButton') {
      if (btn.uuid !== triggerId) return
      this.preTrigger(callback)
      return
    } else {
      this.preCallback = null
    }
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        duration: 5
      })
      return
    } else if (type === 'linkbtn' && !btn.$toolbtn && !is(fromJS(selectedData || []), fromJS(record))) {
      return
    }
    if (type === 'linkbtn' && !btn.$toolbtn && !is(fromJS(selectedData || []), fromJS(record))) return
    if (btn.OpenType === 'form' && btn.formType === 'count_line') return
    this.setState({autoMatic: type === 'autoMatic'})
    let _this = this
    let data = record || selectedData || []
    if (btn.Ot !== 'notRequired' && data.length === 0) {
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        duration: 5
      })
      return
    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        duration: 5
      })
      return
    } else if (btn.intertype === 'system') {
      // 使用内部接口时,操作类型和数据源不可为空
      if (!btn.sql || !btn.sqlType) {
        notification.warning({
          top: 92,
          message: '按钮操作类型错误!',
          duration: 5
        })
        return
      } else if (data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return
      }
    } else if (btn.intertype === 'inner') {
      // 使用内部接口时,内部函数不可为空
      if (!btn.innerFunc) {
        notification.warning({
          top: 92,
          message: '按钮内部函数不可为空!',
          duration: 5
        })
        return
      }
    } else if (btn.intertype === 'custom' || btn.intertype === 'outer') {
      if (btn.callbackType === 'script' && (!btn.verify || !btn.verify.cbScripts || !btn.verify.cbScripts.filter(item => item.status !== 'false').length === 0)) {
        notification.warning({
          top: 92,
          message: '使用自定义脚本回调时,回调脚本不可为空!',
          duration: 5
        })
        return
      } else if (btn.procMode === 'system' && data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return
      } else if (btn.intertype === 'custom' && window.GLOB.systemType === 'production' && !btn.proInterface) {
        notification.warning({
          top: 92,
          message: '尚未设置正式系统接口地址!',
          duration: 5
        })
        return
      }
    } else if (!['inner', 'outer', 'system', 'custom'].includes(btn.intertype)) {
      if (btn.OpenType === 'form' && btn.formType === 'count_line') {
        return
      }
      // 接口类型错误
      notification.warning({
        top: 92,
        message: '按钮接口类型错误!',
        duration: 5
      })
      return
    }
    let valid = this.checkBtnData(data)
    if (!valid) return
    this.setState({
      selines: data
@@ -339,7 +238,6 @@
      this.setState({}, () => {
        MKEmitter.emit('mkFormSubmit', btn.uuid)
      })
      return
    } else if (btn.OpenType === 'prompt') {
      this.setState({loading: true})
      confirm({
@@ -410,10 +308,158 @@
      let _change = {
        prompt: '提示框',
        exec: '直接执行',
        pop: '弹窗(表单)'
        pop: '弹窗(表单)',
        formSubmit: '表单',
        form: '表单',
      }
      MKEmitter.emit('queryTrigger', {menuId: btn.uuid, name: _change[btn.OpenType]})
    }
  }
  preTrigger = (callback) => {
    const { btn, selectedData } = this.props
    const { loading, disabled } = this.state
    if (loading || disabled) {
      callback()
      return
    } else if (btn.OpenType === 'form') {
      callback()
      return
    }
    let _this = this
    let data = selectedData || []
    let valid = this.checkBtnData(data)
    if (!valid) {
      callback()
      return
    }
    this.preCallback = callback
    this.setState({
      selines: data
    })
    if (btn.OpenType === 'formSubmit') {
      this.setState({}, () => {
        MKEmitter.emit('mkFormSubmit', btn.uuid, callback)
      })
    } else if (btn.OpenType === 'prompt') {
      this.setState({loading: true})
      confirm({
        title: btn.tipTitle || '确定要执行吗?',
        onOk() {
          return new Promise(resolve => {
            _this.execSubmit(data, resolve)
          })
        },
        onCancel() {
          callback()
          _this.setState({loading: false})
        }
      })
    } else if (btn.OpenType === 'exec') {
      this.setState({loading: true})
      this.execSubmit(data, () => { this.setState({loading: false})})
    } else if (btn.OpenType === 'pop') {
      let modal = this.state.btnconfig
      if (!modal && btn.modal) {
        modal = this.handleModelConfig(btn.modal)
      }
      this.setState({
        loading: true,
        btnconfig: modal
      })
      if (modal) {
        if (modal.setting.display === 'prompt' || modal.setting.display === 'exec') {
          this.modelconfirm()
        } else {
          this.setState({
            visible: true
          })
        }
      }
    }
  }
  /**
   * @description 按钮状态改变
   */
  updateStatus = () => {
    this.setState({
      loading: false,
      visible: false,
      confirmLoading: false
    })
  }
  checkBtnData = (data) => {
    const { BID, btn, setting } = this.props
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        duration: 5
      })
      return false
    } else if (btn.Ot !== 'notRequired' && data.length === 0) {
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        duration: 5
      })
      return false
    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        duration: 5
      })
      return false
    } else if (btn.intertype === 'system') {
      if (data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return false
      }
    } else if (btn.intertype === 'custom' || btn.intertype === 'outer') {
      if (btn.callbackType === 'script' && (!btn.verify || !btn.verify.cbScripts || !btn.verify.cbScripts.filter(item => item.status !== 'false').length === 0)) {
        notification.warning({
          top: 92,
          message: '使用自定义脚本回调时,回调脚本不可为空!',
          duration: 5
        })
        return false
      } else if (btn.procMode === 'system' && data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return false
      } else if (btn.intertype === 'custom' && window.GLOB.systemType === 'production' && !btn.proInterface) {
        notification.warning({
          top: 92,
          message: '尚未设置正式系统接口地址!',
          duration: 5
        })
        return false
      }
    }
    return true
  }
  getSystemParam = (data, formdata, retmsg) => {
@@ -441,11 +487,11 @@
        param.ID = primaryId
        if (retmsg) {
          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
          const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, data[0], columns, retmsg, this.moduleParams) // 数据源
          param.LText = sql
          param.$callbacksql = callbacksql
        } else {
          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
          param.LText = getSysDefaultSql(btn, setting, '', param, data[0], columns, false, this.moduleParams) // 数据源
          if (btn.output) {
            param.key_back_type = 'Y'
          }
@@ -477,11 +523,11 @@
          param.ID = primaryId || Utils.getguid()
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, this.moduleParams) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, this.moduleParams) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -503,11 +549,11 @@
          param.ID = primaryId
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, retmsg, this.moduleParams) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            param.LText = getSysDefaultSql(btn, setting, formdata, param, data[0], columns, false, this.moduleParams) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -569,11 +615,11 @@
          param.ID = primaryId
          if (retmsg) {
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            const { sql, callbacksql } = getSysDefaultSql(btn, setting, '', param, cell, columns, retmsg, this.moduleParams) // 数据源
            param.LText = sql
            param.$callbacksql = callbacksql
          } else {
            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
            param.LText = getSysDefaultSql(btn, setting, '', param, cell, columns, false, this.moduleParams) // 数据源
            if (btn.output) {
              param.key_back_type = 'Y'
            }
@@ -609,11 +655,11 @@
            param.ID = Utils.getguid()
            if (retmsg) {
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, this.moduleParams) // 数据源
              param.LText = sql
              param.$callbacksql = callbacksql
            } else {
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, this.moduleParams) // 数据源
              if (btn.output) {
                param.key_back_type = 'Y'
              }
@@ -635,11 +681,11 @@
            param.ID = primaryId
            if (retmsg) {
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, this.moduleParams, Utils.getAllSearchOptions) // 数据源
              const { sql, callbacksql } = getSysDefaultSql(btn, setting, formdata, param, cell, columns, retmsg, this.moduleParams) // 数据源
              param.LText = sql
              param.$callbacksql = callbacksql
            } else {
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, this.moduleParams, Utils.getAllSearchOptions) // 数据源
              param.LText = getSysDefaultSql(btn, setting, formdata, param, cell, columns, false, this.moduleParams) // 数据源
              if (btn.output) {
                param.key_back_type = 'Y'
              }
@@ -971,21 +1017,92 @@
  /**
   * @description 按钮提交执行
   */
  execSubmit = (data, _resolve, formdata) => {
  execSubmit = (data, _resolve, formdata, force) => {
    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
    ) {
    if (btn.preButton && !force) {
      this.trigger(btn.preButton, data, _resolve, formdata, 0)
    } else if (btn.verify && btn.verify.invalid === 'true' && setting.dataresource) {
      MKEmitter.emit('queryModuleParam', btn.$menuId, (param) => {
        this.moduleParams = param
        let datasource = setting.dataresource
        let customScript = setting.customScript || ''
        let allSearch = Utils.getAllSearchOptions(param.search)
        let regoptions = allSearch.map(item => {
          return {
            reg: new RegExp('@' + item.key + '@', 'ig'),
            value: `'${item.value}'`
          }
        })
        regoptions.push({
          reg: new RegExp('@userName@', 'ig'),
          value: `'${sessionStorage.getItem('User_Name') || ''}'`
        }, {
          reg: new RegExp('@fullName@', 'ig'),
          value: `'${sessionStorage.getItem('Full_Name') || ''}'`
        }, {
          reg: new RegExp('@orderBy@', 'ig'),
          value: setting.order
        }, {
          reg: new RegExp('@pageSize@', 'ig'),
          value: 10
        }, {
          reg: new RegExp('@pageIndex@', 'ig'),
          value: 1
        })
        regoptions.forEach(item => {
          datasource = datasource.replace(item.reg, item.value)
          customScript = customScript.replace(item.reg, item.value)
        })
        this.moduleParams = {
          datasource,
          customScript
        }
        this.execRealSubmit(data, _resolve, formdata)
      })
    } else {
      this.execRealSubmit(data, _resolve, formdata)
    }
  }
  trigger = (btnId, data, resolve, formdata, times) => {
    if (times > 50) {
      notification.warning({
        top: 92,
        message: '前置按钮加载失败!',
        duration: 5
      })
      this.setState({loading: false})
      resolve()
      return
    }
    times++
    let node = document.getElementById('button' + btnId)
    if (node) {
      MKEmitter.emit('triggerBtnId', btnId, null, 'preButton', (res) => {
        if (!res) {
          this.setState({loading: false})
          resolve()
          return
        }
        if (res.status) {
          this.execSubmit(data, resolve, formdata, true)
        } else {
          this.execError(res)
        }
      })
    } else {
      setTimeout(() => {
        this.trigger(btnId, data, resolve, formdata, times)
      }, 100)
    }
  }
@@ -1986,30 +2103,76 @@
    delete result.message
    delete result.status
    result.func = btn.callbackFunc
    let ssoParam = null
    let sinParam = null
    let callParam = {...outParam, ...result}
    if (callParam.LTextOut) {
      callParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      callParam.secretkey = Utils.encrypt(callParam.LTextOut, callParam.timestamp)
      callParam.open_key = Utils.encryptOpenKey(callParam.secretkey, callParam.timestamp)
    }
    callParam.func = btn.callbackFunc
    callParam.userid = sessionStorage.getItem('LocalUserID') || ''
    callParam.LoginUID = sessionStorage.getItem('LocalLoginUID') || ''
    if (callParam.UpType === 'SSO' && window.GLOB.localSystemApi) {
    if (result.LTextOut) {
      callParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      callParam.secretkey = Utils.encrypt(callParam.LTextOut, callParam.timestamp)
      callParam.open_key = Utils.encryptOpenKey(callParam.secretkey, callParam.timestamp)
    } else {
      callParam = {...outParam}
      callParam.func = btn.callbackFunc
      callParam.MenuNO = 'sVersionDetail_LocalM'
      callParam.UpType = 'SSO'
      callParam.LTextOut = 'minke'
      callParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      callParam.secretkey = Utils.encrypt(callParam.LTextOut, callParam.timestamp)
      callParam.open_key = Utils.encryptOpenKey(callParam.secretkey, callParam.timestamp)
      callParam.userid = sessionStorage.getItem('LocalUserID') || ''
      callParam.LoginUID = sessionStorage.getItem('LocalLoginUID') || ''
      delete result.ErrCode
      delete result.ErrMesg
      sinParam = {...result}
      sinParam.func = 'sPC_TrdMenu_AddUpt_sso'
      if (window.GLOB.sysType === 'local') {
        if (!window.GLOB.systemType && window.GLOB.cloudServiceApi) {
          sinParam.rduri = window.GLOB.cloudServiceApi
        } else if (window.GLOB.localSystemApi) {
          sinParam.rduri = window.GLOB.localSystemApi
          sinParam.userid = sessionStorage.getItem('LocalUserID') || ''
          sinParam.LoginUID = sessionStorage.getItem('LocalLoginUID') || ''
        }
      }
    }
    if (result.UpType === 'SSO' && window.GLOB.localSystemApi) {
      ssoParam = fromJS(callParam).toJS()
      ssoParam.rduri = window.GLOB.localSystemApi
      delete ssoParam.UpType
    } else {
      delete callParam.UpType
    }
    if (ssoParam) {
    if (sinParam) {
      Api.genericInterface(sinParam).then(res => {
        if (!res.status) {
          this.execError(res)
          _resolve()
        } else {
          Api.genericInterface(callParam).then(re => {
            if (!re.status) {
              this.execError(re)
              _resolve()
            } else {
              if (params.length === 0) {
                this.execSuccess(res)
                _resolve()
              } else {
                this.outerLoopRequest(params, _resolve)
              }
            }
          })
        }
      })
    } else if (ssoParam) {
      Api.genericInterface(ssoParam).then(res => {
        if (!res.status) {
          this.execError(res)
@@ -2059,7 +2222,18 @@
    const { btn } = this.props
    const { autoMatic } = this.state
    if (autoMatic) {
    if (btn.resetForms) {
      MKEmitter.emit('resetForms', btn.uuid)
    }
    if (this.preCallback) {
      this.setState({
        loading: false,
        visible: false
      })
      this.preCallback(res)
      return
    } else if (autoMatic) {
      this.setState({
        loading: false,
        visible: false
@@ -2170,9 +2344,15 @@
      if (btn.syncComponentId === 'multiComponent') {
        btn.syncComponentIds.forEach((id, i) => {
          setTimeout(() => {
            MKEmitter.emit('reloadData', id)
            if (/\$focus/.test(id)) {
              MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
            } else {
              MKEmitter.emit('reloadData', id)
            }
          }, 20 * i)
        })
      } else if (/\$focus/.test(btn.syncComponentId)) {
        MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
      } else {
        MKEmitter.emit('reloadData', btn.syncComponentId)
      }
@@ -2222,7 +2402,7 @@
    const { btn } = this.props
    if (!btn.verify) return
    if (btn.verify.noteEnable !== 'true' && btn.verify.wxNote !== 'true' && btn.verify.printEnable !== 'true') return
    if (btn.verify.noteEnable !== 'true' && btn.verify.wxNote !== 'true' && btn.verify.printEnable !== 'true' && btn.verify.emailEnable !== 'true') return
    let id = ''
    if (btn.output) {
@@ -2237,6 +2417,9 @@
    if (btn.verify.noteEnable === 'true') {
      this.sendMessage(btn.verify, id)
    }
    if (btn.verify.emailEnable === 'true') {
      this.sendEmail(btn.verify, id)
    }
    if (btn.verify.wxNote === 'true') {
      if (btn.verify.wxTemplateId === 'mk_category_temp') {
@@ -2416,8 +2599,8 @@
  sendMessage = (verify, id) => {
    let param = {
      func: 's_get_sms_local',
      TypeCharOne: verify.noteTemp, // N不同内容,Y相同内容
      TypeCharTwo: verify.noteType, // N定时,Y实时
      TypeCharOne: verify.noteTemp || 'Y', // N不同内容,Y相同内容
      TypeCharTwo: verify.noteType || 'N', // N定时,Y实时
      upid: id
    }
@@ -2436,9 +2619,9 @@
      }
      let _param = {
        templatecode: verify.noteCode, // 模板编码
        TypeCharOne: verify.noteTemp,  // N不同内容,Y相同内容
        ID: verify.noteId || ''        // 模板Id,暂时未使用
        templatecode: verify.noteCode,        // 模板编码
        TypeCharOne: verify.noteTemp || 'Y',  // N不同内容,Y相同内容
        ID: verify.noteId || ''               // 模板Id,暂时未使用
      }
      _param.submitdate = res.submitdate
@@ -2446,17 +2629,17 @@
      let limit = 5 // 实时最大为5条,定时最大为100条
      let mobMap = new Map()
      if (verify.noteType === 'N') {
      if (verify.noteType === 'Y') {
        _param.func = 's_get_sms_sso_realtime'
      } else {
        _param.func = 's_get_sms_sso_timer'
        limit = 100
      } else if (verify.noteType === 'Y') {
        _param.func = 's_get_sms_sso_realtime'
      }
      let Ltext = []
      let error = false
      if (verify.noteTemp === 'Y') {
      if (verify.noteTemp !== 'N') {
        _param.p1 = res.p1 || ''
        _param.p2 = res.p2 || ''
        _param.p3 = res.p3 || ''
@@ -2465,25 +2648,156 @@
        let _p = _param.p1 + _param.p2 + _param.p3 + _param.p4 + _param.p5
        if (/\/|\.|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信|Q/.test(_p)) {
        if (/\/|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信/.test(_p)) {
          error = true
        }
      }
      res.send_data && res.send_data.forEach(item => {
        if (item.mob && !mobMap.has(item.mob) && Ltext.length < limit) {
          if (verify.noteTemp === 'Y') {
          if (verify.noteTemp !== 'N') {
            Ltext.push(`'${item.mob}'`)
          } else {
            let _p = `'${item.p1 || ''}','${item.p2 || ''}','${item.p3 || ''}','${item.p4 || ''}','${item.p5 || ''}','${item.mob}'`
            if (/\/|\.|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信|Q/.test(_p)) {
            if (/\/|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信/.test(_p)) {
              error = true
            }
            Ltext.push(_p)
          }
          mobMap.set(item.mob, true)
        }
      })
      if (error) {
        notification.warning({
          top: 92,
          message: '消息中含有非法字符',
          duration: 5
        })
        return
      }
      if (Ltext.length === 0) return
      Ltext = Ltext.join(';')
      _param.LText = window.btoa(window.encodeURIComponent(Ltext))
      _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp)
      _param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
      _param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
      _param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
      Api.genericInterface(_param).then(result => {
        if (!result.status) {
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
        }
      }, (error) => {
        if (error && error.ErrCode === 'LoginError') {
          let param = {
            func: 's_visitor_login',
            timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
            SessionUid: 'bh0bapabtd45epsgra79segbch6c1ibk',
            TypeCharOne: 'pc',
            appkey: '202004041613277377A6A2456D34A4948AE84'
          }
          param.LText = md5(window.btoa('bh0bapabtd45epsgra79segbch6c1ibk' + param.timestamp))
          param.secretkey = md5(param.LText + 'mingke' + param.timestamp)
          let params = {
            url: 'https://sso.mk9h.cn/webapi/dologon',
            method: 'post',
            data: JSON.stringify(param)
          }
          Api.directRequest(params)
          return
        }
      })
    })
  }
  sendEmail = (verify, id) => {
    let param = {
      func: 's_get_email_local',
      TypeCharOne: verify.emailTemp || 'Y', // N不同内容,Y相同内容
      TypeCharTwo: verify.emailType || 'N', // N定时,Y实时
      upid: id
    }
    param.LText = Utils.formatOptions(Utils.getuuid())
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      let _param = {
        msn_email_temp_no: verify.emailCode,   // 模板编码
        TypeCharOne: verify.emailTemp || 'Y',  // N不同内容,Y相同内容
        ID: verify.emailId || ''               // 模板Id,暂时未使用
      }
      _param.submitdate = res.submitdate
      let limit = 5 // 实时最大为5条,定时最大为100条
      let mobMap = new Map()
      if (verify.emailType === 'Y') {
        _param.func = 's_get_email_sso_realtime'
      } else {
        _param.func = 's_get_email_sso_timer'
        limit = 100
      }
      let Ltext = []
      let error = false
      if (verify.emailTemp !== 'N') {
        _param.p1 = res.p1 || ''
        _param.p2 = res.p2 || ''
        _param.p3 = res.p3 || ''
        _param.p4 = res.p4 || ''
        _param.p5 = res.p5 || ''
        let _p = _param.p1 + _param.p2 + _param.p3 + _param.p4 + _param.p5
        if (/\/|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信/.test(_p)) {
          error = true
        }
      }
      res.send_data && res.send_data.forEach(item => {
        if (item.email && !mobMap.has(item.email) && Ltext.length < limit) {
          if (verify.emailTemp !== 'N') {
            Ltext.push(`'${item.email}'`)
          } else {
            let _p = `'${item.p1 || ''}','${item.p2 || ''}','${item.p3 || ''}','${item.p4 || ''}','${item.p5 || ''}','${item.email}'`
            if (/\/|.*共.*产|.*习.*近|面试|邀请|下载|红包|招聘|好评|评价|政务通知|缴费|保险|股票|金融|房地产|教育|游戏|微信/.test(_p)) {
              error = true
            }
            Ltext.push(_p)
          }
          mobMap.set(item.email, true)
        }
      })
@@ -2554,7 +2868,14 @@
    const { btn } = this.props
    const { autoMatic } = this.state
    if (autoMatic) {
    if (this.preCallback) {
      this.setState({
        loading: false,
        visible: false
      })
      this.preCallback(res)
      return
    } else if (autoMatic) {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
@@ -2624,6 +2945,13 @@
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
    } else if (res.ErrCode === '-2') {
      this.setState({
        loadingNumber: '',
        loadingTotal: '',
        loading: false
      })
      return
    }
    this.errorContinue(sign)
@@ -2804,6 +3132,8 @@
      visible: false,
      confirmLoading: false
    })
    this.preCallback && this.preCallback()
  }
  modelconfirm = () => {
@@ -2945,6 +3275,7 @@
          })
        },
        onCancel() {
          _this.preCallback && _this.preCallback()
          _this.setState({ loading: false })
        }
      })
src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -215,9 +215,15 @@
      if (btn.syncComponentId === 'multiComponent') {
        btn.syncComponentIds.forEach((id, i) => {
          setTimeout(() => {
            MKEmitter.emit('reloadData', id)
            if (/\$focus/.test(id)) {
              MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
            } else {
              MKEmitter.emit('reloadData', id)
            }
          }, 20 * i)
        })
      } else if (/\$focus/.test(btn.syncComponentId)) {
        MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
      } else {
        MKEmitter.emit('reloadData', btn.syncComponentId)
      }
@@ -330,6 +336,7 @@
      <>
        <Button
          type={type}
          id={'button' + btn.uuid}
          title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
          loading={loading}
          disabled={disabled}
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -1968,6 +1968,8 @@
      return
    }
    if (res.ErrCode === '-2') return
    if (btnconfig && btnconfig.setting && btnconfig.setting.errFocus) {
      MKEmitter.emit('mkFC', 'focus', btnconfig.setting.errFocus)
    }
src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -217,6 +217,7 @@
    return (
      <Button
        type={type}
        id={'button' + btn.uuid}
        title={disabled ? (btn.reason || '') : (btn.show === 'icon' ? btn.label : '')}
        style={btn.style || null}
        disabled={disabled}
src/tabviews/zshare/fileupload/index.jsx
@@ -12,8 +12,9 @@
class FileUpload extends Component {
  static propTpyes = {
    config: PropTypes.object,  // 表单信息
    onChange: PropTypes.func,  // 表单变化
    data: PropTypes.any,
    config: PropTypes.object,
    onChange: PropTypes.func,
  }
  state = {
@@ -31,7 +32,7 @@
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    const { config, data } = this.props
    let filelist = []
    if (config.initval) {
@@ -56,6 +57,12 @@
          })
        } catch (e) {
          filelist = []
        }
        if (data && config.subFields && config.subFields.length === 1 && filelist.length === 1) {
          if (data[config.subFields[0].field]) {
            filelist[0].name = data[config.subFields[0].field]
          }
        }
      }
    }
@@ -270,7 +277,7 @@
      percent: 0
    })
    let file_name = file.name.replace(/\.{1}[^.]*$/ig, '')
    let file_name = file.name
    if (compress === 'true' || compress === 'base64') {
      let reader = new FileReader()
src/tabviews/zshare/fileupload/index.scss
@@ -34,6 +34,9 @@
      display: none;
    }
  }
  .ant-upload-list-item-card-actions {
    opacity: 1;
  }
}
.fileupload-form-container.limit-fileupload {
  > .ant-upload {
src/tabviews/zshare/mutilform/index.jsx
@@ -46,10 +46,12 @@
    ID: '',
    send_type: '',
    timestamp: '',
    n_id: ''
    n_id: '',
    focusId: ''
  }
  record = {}
  submitId = ''
  componentDidMount () {
    const { action, unload } = this.props
@@ -144,6 +146,17 @@
      item.fieldlength = item.fieldlength || 50
      let key = item.field.toLowerCase()
      // positecgroup 表单隐藏
      if (item.tooltip && /@[a-z0-9_]+@/.test(item.tooltip)) {
        let field = item.tooltip.replace(/@|\s/ig, '').toLowerCase()
        if (data[field] === 'N') {
          item.hidden = true
        }
        item.tooltip = ''
      }
      if (item.type === 'funcvar') {
        readin = false
@@ -268,7 +281,7 @@
      }
      if (item.type === 'number') {
        if (isNaN(item.initval)) {
        if (isNaN(item.initval) || item.initval === '') {
          item.initval = 0
        }
      } else if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect', 'cascader'].includes(item.type) && item.resourceType === '1') {
@@ -308,8 +321,8 @@
          validator: (rule, value, callback) => {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
            } else if (/--/.test(value)) {
              callback('不可使用 -- !')
            // } else if (/--/.test(value)) {
            //   callback('不可使用 -- !')
            } else {
              callback()
            }
@@ -423,8 +436,8 @@
          validator: (rule, value, callback) => {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
            } else if (/--/.test(value)) {
              callback('不可使用 -- !')
            // } else if (/--/.test(value)) {
            //   callback('不可使用 -- !')
            } else {
              callback()
            }
@@ -623,17 +636,19 @@
      }
      record[item.field] = item.initval
      item.orgval = item.initval
      if (linkFields[item.field]) {
        item.linkFields = linkFields[item.field]
      }
      
      if (item.enter === 'tab' || item.enter === 'sub') {
        if (fieldMap.has(item.tabField)) {
        item.tabUuid = ''
        if (item.tabField && fieldMap.has(item.tabField)) {
          item.tabUuid = fieldMap.get(item.tabField).uuid
        } else if (item.enter === 'tab') {
          item.enter = 'false'
        } else if (item.enter === 'sub') {
        } else if (item.enter === 'sub' && ['text', 'number'].includes(item.type)) {
          item.tabUuid = item.uuid
        }
      }
@@ -670,13 +685,16 @@
    this.record = record
    let ID = this.props.data ? this.props.data.$$uuid || '' : ''
    let focusItem = null
    this.setState({ formlist, ID }, () => {
    if (action.setting.focus && fieldMap.has(action.setting.focus)) {
      focusItem = fieldMap.get(action.setting.focus)
    }
    this.setState({ formlist, ID, focusId: focusItem ? focusItem.uuid : '' }, () => {
      if (unload) return
      
      if (action.setting && action.setting.focus && fieldMap.has(action.setting.focus)) {
        let focusItem = fieldMap.get(action.setting.focus)
      if (focusItem) {
        if (focusItem.type === 'text' || focusItem.type === 'number') {
          setTimeout(() => {
            MKEmitter.emit('mkFC', 'focus', focusItem.uuid)
@@ -702,6 +720,62 @@
        }
      }
    })
    if (action.subButton && action.subButton.resetForms) {
      MKEmitter.addListener('resetForms', this.resetForms)
    }
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('resetForms', this.resetForms)
  }
  resetForms = (id) => {
    const { action } = this.props
    const { focusId } = this.state
    if (id !== action.uuid) return
    let formlist = fromJS(this.state.formlist).toJS()
    let resetForms = action.subButton.resetForms || []
    formlist = formlist.map(item => {
      if (item.type !== 'text' && item.type !== 'number') return item
      if (resetForms.includes(item.field)) {
        item.initval = item.orgval
        this.record[item.field] = item.orgval
      }
      return item
    })
    let _list = fromJS(formlist).toJS().map(item => {
      if (item.type !== 'text' && item.type !== 'number') return item
      if (resetForms.includes(item.field) && !item.hidden) {
        item.hidden = true
      }
      return item
    })
    this.setState({
      formlist: _list
    }, () => {
      this.setState({
        formlist
      })
    })
    if (focusId || this.submitId) {
      setTimeout(() => {
        MKEmitter.emit('mkFC', 'focus', this.submitId || focusId)
      }, 50)
    }
  }
  getFormData = (deForms) => {
@@ -1181,7 +1255,7 @@
        } else if (item.type === 'fileupload') {
          className = item.readonly ? 'readonly' : ''
          className += item.fileType === 'picture-card' ? ' file-upload' : ''
          content = (<MKFileUpload config={item} onChange={(val, other = {}) => this.recordChange({[item.field]: val, ...other})} />)
          content = (<MKFileUpload config={item} data={this.record} onChange={(val, other = {}) => this.recordChange({[item.field]: val, ...other})} />)
        } else if (item.type === 'textarea') {
          content = (<MKTextArea config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})}/>)
        } else if (item.type === 'rate') {
@@ -1218,7 +1292,7 @@
    return fields
  }
  handleConfirm = () => {
  handleConfirm = (formId) => {
    const { formlist, send_type, timestamp, n_id } = this.state
    // 表单提交时检查输入值是否正确
@@ -1316,6 +1390,8 @@
          forms.push(_item)
        })
        this.submitId = formId || ''
        resolve(forms)
      })
    })
src/tabviews/zshare/mutilform/mkInput/index.jsx
@@ -123,7 +123,7 @@
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
    } else {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      this.props.onSubmit()
      this.props.onSubmit(config.tabUuid)
    }
  }
src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
@@ -40,7 +40,7 @@
    if (type === 'focus') {
      let node = document.getElementById(uuid)
      node.select()
      node && node.select()
    } else if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, true)
@@ -71,7 +71,7 @@
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
    } else {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      this.props.onSubmit()
      this.props.onSubmit(config.tabUuid)
    }
  }
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx
@@ -265,12 +265,13 @@
      if (config.enter === 'tab') {
        MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      } else if (config.enter === 'sub') {
        config.tabUuid && MKEmitter.emit('mkFC', 'focus', config.tabUuid)
        if (config.subFields) {
          setTimeout(() => {
            this.props.onSubmit()
            this.props.onSubmit(config.tabUuid)
          }, 1000)
        } else {
          this.props.onSubmit()
          this.props.onSubmit(config.tabUuid)
        }
      }
    })
src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -149,12 +149,13 @@
      if (config.enter === 'tab') {
        MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      } else if (config.enter === 'sub') {
        config.tabUuid && MKEmitter.emit('mkFC', 'focus', config.tabUuid)
        if (config.linkFields || config.subFields || config.controlFields) {
          setTimeout(() => {
            this.props.onSubmit()
            this.props.onSubmit(config.tabUuid)
          }, 1000)
        } else {
          this.props.onSubmit()
          this.props.onSubmit(config.tabUuid)
        }
      }
    })
src/tabviews/zshare/mutilform/mkVercode/index.jsx
@@ -55,8 +55,8 @@
    if (config.enter === 'tab') {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
    } else {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      this.props.onSubmit()
      config.tabUuid && MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      this.props.onSubmit(config.tabUuid)
    }
  }
src/tabviews/zshare/topSearch/index.jsx
@@ -426,6 +426,7 @@
  }
  resetSearch = (result) => {
    let trigger = false
    let _searchlist = fromJS(this.state.searchlist).toJS().map(item => {
      if (['select', 'link', 'multiselect', 'checkcard', 'radio'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
        let options = []
@@ -491,12 +492,23 @@
        item.options = item.oriOptions
      }
      if (item.$first && item.options.length > 0) {
        item.initval = item.options[0].Value
        trigger = true
      }
      return item
    })
    this.setState({
      searchlist: _searchlist
    })
    if (trigger) {
      setTimeout(() => {
        this.handleSubmit()
      }, 10)
    }
  }
  recordChange = (val, defer, item) => {
src/tabviews/zshare/topSearch/mkSelect/index.jsx
@@ -46,6 +46,12 @@
        config: fromJS(nextProps.config).toJS(),
        options: fromJS(nextProps.config.options).toJS()
      })
      if (config.$first && nextProps.config.initval) {
        this.setState({
          value: nextProps.config.initval
        })
      }
    }
  }
src/templates/comtableconfig/index.jsx
@@ -3,9 +3,8 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip, Col } from 'antd'
import { Button, Card, Collapse, notification, Spin, Tooltip, Col } from 'antd'
import { QuestionCircleOutlined, RedoOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -22,14 +21,13 @@
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
const Versions = asyncComponent(() => import('@/menu/versions'))
// const Versions = asyncComponent(() => import('@/menu/versions'))
const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent'))
// const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const UpdateTable = asyncComponent(() => import('./updatetable'))
const Unattended = asyncComponent(() => import('@/templates/zshare/unattended'))
const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
// const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -290,426 +288,428 @@
  /**
   * @description 三级菜单保存
   */
  submitConfig = () => {
    const { menu } = this.props
    const { delActions, openEdition } = this.state
  // submitConfig = () => {
  //   const { menu } = this.props
  //   const { delActions, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
  //   let _config = fromJS(this.state.config).toJS()
    // 基本信息验证
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      this.setState({activeKey: '0'})
      return
    }
  //   // 基本信息验证
  //   if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
  //     notification.warning({
  //       top: 92,
  //       message: '请完善菜单基本信息!',
  //       duration: 5
  //     })
  //     this.setState({activeKey: '0'})
  //     return
  //   }
    // 新建菜单,清除默认项
    if (_config.isAdd) {
      _config.search = _config.search.filter(item => !item.origin)
      _config.action = _config.action.filter(item => !item.origin)
      _config.columns = _config.columns.filter(item => !item.origin)
      _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
    }
  //   // 新建菜单,清除默认项
  //   if (_config.isAdd) {
  //     _config.search = _config.search.filter(item => !item.origin)
  //     _config.action = _config.action.filter(item => !item.origin)
  //     _config.columns = _config.columns.filter(item => !item.origin)
  //     _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
  //   }
    // 使用已有菜单时,默认添加关联标签id
    if (_config.type === 'user') {
      _config.action = _config.action.map(item => {
        if (item.OpenType === 'popview' && !item.linkTab) {
          item.linkTab = Utils.getuuid()
        }
        return item
      })
  //   // 使用已有菜单时,默认添加关联标签id
  //   if (_config.type === 'user') {
  //     _config.action = _config.action.map(item => {
  //       if (item.OpenType === 'popview' && !item.linkTab) {
  //         item.linkTab = Utils.getuuid()
  //       }
  //       return item
  //     })
  
      _config.tabgroups.forEach(group => {
        group.sublist = group.sublist.map(tab => {
          if (!tab.linkTab) {
            tab.linkTab = Utils.getuuid()
          }
          return tab
        })
      })
    }
  //     _config.tabgroups.forEach(group => {
  //       group.sublist = group.sublist.map(tab => {
  //         if (!tab.linkTab) {
  //           tab.linkTab = Utils.getuuid()
  //         }
  //         return tab
  //       })
  //     })
  //   }
    // 按钮不存在时,去掉绑定的双击按钮
    if (_config.setting.doubleClick && _config.action.findIndex((item) => item.uuid === _config.setting.doubleClick) === -1) {
      _config.setting.doubleClick = ''
    }
  //   // 按钮不存在时,去掉绑定的双击按钮
  //   if (_config.setting.doubleClick && _config.action.findIndex((item) => item.uuid === _config.setting.doubleClick) === -1) {
  //     _config.setting.doubleClick = ''
  //   }
    // 未设置数据源或标签不合法时,启用状态为false
    let vresult = this.verifyconfig(_config)
    if (vresult !== true) {
      _config.enabled = false
    }
  //   // 未设置数据源或标签不合法时,启用状态为false
  //   let vresult = this.verifyconfig(_config)
  //   if (vresult !== true) {
  //     _config.enabled = false
  //   }
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
  //   if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
  //     this.setState({
  //       menucloseloading: true
  //     })
  //   } else {
  //     this.setState({
  //       menuloading: true
  //     })
  //   }
    let _LongParam = ''
  //   let _LongParam = ''
    // 保存时删除配置类型,system 、user
    delete _config.type
    delete _config.isAdd
  //   // 保存时删除配置类型,system 、user
  //   delete _config.type
  //   delete _config.isAdd
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 5
      })
      this.setState({
        menucloseloading: false,
        menuloading: false
      })
      return
    }
  //   try {
  //     _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
  //   } catch (e) {
  //     notification.warning({
  //       top: 92,
  //       message: '编译错误',
  //       duration: 5
  //     })
  //     this.setState({
  //       menucloseloading: false,
  //       menuloading: false
  //     })
  //     return
  //   }
    let _sort = 0
    // let btntabs = []
  //   let _sort = 0
  //   // let btntabs = []
    let btnParam = {             // 添加菜单按钮
      func: 'sPC_Button_AddUpt',
      Type: 40,                  // 添加菜单下的按钮type为40,按钮下的按钮type为60
      ParentID: menu.MenuID,
      MenuNo: _config.MenuNo,
      Template: _config.Template || '',
      PageParam: '',
      LongParam: '',
      LText: []
    }
  //   let btnParam = {             // 添加菜单按钮
  //     func: 'sPC_Button_AddUpt',
  //     Type: 40,                  // 添加菜单下的按钮type为40,按钮下的按钮type为60
  //     ParentID: menu.MenuID,
  //     MenuNo: _config.MenuNo,
  //     Template: _config.Template || '',
  //     PageParam: '',
  //     LongParam: '',
  //     LText: []
  //   }
    _config.action.forEach(item => {
      if (item.hidden === 'true') return
      _sort++
      // if (item.OpenType === 'popview') {
      //   btntabs.push({
      //     uuid: item.uuid,
      //     linkTab: item.linkTab,
      //     label: item.label,
      //     sort: _sort
      //   })
      // }
  //   _config.action.forEach(item => {
  //     if (item.hidden === 'true') return
  //     _sort++
  //     // if (item.OpenType === 'popview') {
  //     //   btntabs.push({
  //     //     uuid: item.uuid,
  //     //     linkTab: item.linkTab,
  //     //     label: item.label,
  //     //     sort: _sort
  //     //   })
  //     // }
      
      btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
    })
  //     btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${_sort * 10}' as Sort`)
  //   })
    btnParam.LText = btnParam.LText.join(' union all ')
    btnParam.LText = Utils.formatOptions(btnParam.LText)
    btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
  //   btnParam.LText = btnParam.LText.join(' union all ')
  //   btnParam.LText = Utils.formatOptions(btnParam.LText)
  //   btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
    
    // let tabParam = { // 添加菜单tab页
    //   func: 'sPC_sMenusTab_AddUpt',
    //   MenuID: menu.MenuID
    // }
  //   // let tabParam = { // 添加菜单tab页
  //   //   func: 'sPC_sMenusTab_AddUpt',
  //   //   MenuID: menu.MenuID
  //   // }
    // let _LText = []
  //   // let _LText = []
    // btntabs.forEach(item => {
    //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
    // })
    // _config.tabgroups.forEach(group => {
    //   group.sublist.forEach(item => {
    //     _sort++
    //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
    //   })
    // })
  //   // btntabs.forEach(item => {
  //   //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
  //   // })
  //   // _config.tabgroups.forEach(group => {
  //   //   group.sublist.forEach(item => {
  //   //     _sort++
  //   //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
  //   //   })
  //   // })
    // _LText = _LText.join(' union all ')
  //   // _LText = _LText.join(' union all ')
    // 清空菜单下关联的标签
    // if (!_LText) {
    //   _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
    // }
  //   // 清空菜单下关联的标签
  //   // if (!_LText) {
  //   //   _LText = `select '${menu.MenuID}' as MenuID ,'' as Tabid,'' as TabName ,'0' as Sort`
  //   // }
    // tabParam.LText = Utils.formatOptions(_LText)
    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
  //   // tabParam.LText = Utils.formatOptions(_LText)
  //   // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
    let _vals = this.getFuncNames(_config)
  //   let _vals = this.getFuncNames(_config)
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
      FstID: _config.fstMenuId,
      SndID: _config.ParentId,
      ParentID: _config.ParentId,
      MenuID: menu.MenuID,
      MenuNo: _config.MenuNo,
      EasyCode: _config.easyCode || '',
      Template: _config.Template || '',
      MenuName: _config.MenuName,
      PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType, hidden: _config.hidden || 'false'}),
      LongParam: _LongParam,
      LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
      LTexttb: _vals.table.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
    }
  //   let param = {
  //     func: 'sPC_TrdMenu_AddUpt',
  //     FstID: _config.fstMenuId,
  //     SndID: _config.ParentId,
  //     ParentID: _config.ParentId,
  //     MenuID: menu.MenuID,
  //     MenuNo: _config.MenuNo,
  //     EasyCode: _config.easyCode || '',
  //     Template: _config.Template || '',
  //     MenuName: _config.MenuName,
  //     PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType, hidden: _config.hidden || 'false'}),
  //     LongParam: _LongParam,
  //     LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
  //     LTexttb: _vals.table.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
  //   }
    if (menu.menuSort) { // 菜单新建时设置排序
      param.Sort = menu.menuSort
    }
  //   if (menu.menuSort) { // 菜单新建时设置排序
  //     param.Sort = menu.menuSort
  //   }
    param.LText = param.LText.join(' union all ')
    param.LText = Utils.formatOptions(param.LText)
    param.LTexttb = param.LTexttb.join(' union all ')
    param.LTexttb = Utils.formatOptions(param.LTexttb)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
  //   param.LText = param.LText.join(' union all ')
  //   param.LText = Utils.formatOptions(param.LText)
  //   param.LTexttb = param.LTexttb.join(' union all ')
  //   param.LTexttb = Utils.formatOptions(param.LTexttb)
  //   param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    if (openEdition) { // 版本管理
      param.open_edition = openEdition
    }
  //   if (openEdition) { // 版本管理
  //     param.open_edition = openEdition
  //   }
    setTimeout(() => {
      // 有按钮或标签删除时,先进行删除操作
      // 删除成功后,保存页面配置
      new Promise(resolve => {
        if (delActions.length > 0) {
          let deffers = delActions.map(item => {
            let _param = {
              func: 'sPC_MainMenu_Del',
              MenuID: item.card ? item.card.uuid : item.uuid
            }
  //   setTimeout(() => {
  //     // 有按钮或标签删除时,先进行删除操作
  //     // 删除成功后,保存页面配置
  //     new Promise(resolve => {
  //       if (delActions.length > 0) {
  //         let deffers = delActions.map(item => {
  //           let _param = {
  //             func: 'sPC_MainMenu_Del',
  //             MenuID: item.card ? item.card.uuid : item.uuid
  //           }
            if (item.type === 'action') {
              let _ParentParam = null
  //           if (item.type === 'action') {
  //             let _ParentParam = null
              try {
                _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
              } catch (e) {
                console.warn('Stringify Failure')
                _ParentParam = null
              }
  //             try {
  //               _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
  //             } catch (e) {
  //               console.warn('Stringify Failure')
  //               _ParentParam = null
  //             }
              if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
                _param.ParentParam = _ParentParam
              }
            }
  //             if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
  //               _param.ParentParam = _ParentParam
  //             }
  //           }
            return new Promise(resolve => {
              Api.getCloudConfig(_param).then(response => {
                resolve(response)
              })
            })
          })
          Promise.all(deffers).then(result => {
            let error = null
            result.forEach(response => {
              if (!response.status) {
                error = response
              }
            })
  //           return new Promise(resolve => {
  //             Api.getCloudConfig(_param).then(response => {
  //               resolve(response)
  //             })
  //           })
  //         })
  //         Promise.all(deffers).then(result => {
  //           let error = null
  //           result.forEach(response => {
  //             if (!response.status) {
  //               error = response
  //             }
  //           })
            if (error) {
              this.setState({
                menuloading: false,
                menucloseloading: false
              })
              notification.warning({
                top: 92,
                message: error.message,
                duration: 5
              })
              resolve(false)
            } else {
              this.setState({
                delActions: []
              })
              resolve(true)
            }
          })
        } else if (delActions.length === 0) {
          resolve(true)
        }
      }).then(resp => {
        if (resp === false) return
  //           if (error) {
  //             this.setState({
  //               menuloading: false,
  //               menucloseloading: false
  //             })
  //             notification.warning({
  //               top: 92,
  //               message: error.message,
  //               duration: 5
  //             })
  //             resolve(false)
  //           } else {
  //             this.setState({
  //               delActions: []
  //             })
  //             resolve(true)
  //           }
  //         })
  //       } else if (delActions.length === 0) {
  //         resolve(true)
  //       }
  //     }).then(resp => {
  //       if (resp === false) return
        return true
      }).then(res => {
        if (res === true || res === false) return res
  //       return true
  //     }).then(res => {
  //       if (res === true || res === false) return res
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.warning({
            top: 92,
            message: msg,
            duration: 5
          })
          return false
        } else {
          return true
        }
      }).then(resp => {
        if (resp === false) return
        Api.getCloudConfig(param).then(response => {
          if (response.status) {
            this.setState({
              config: _config,
              openEdition: response.open_edition || '',
              originMenu: fromJS(_config).toJS()
            })
  //       let msg = res.filter(Boolean)[0]
  //       if (msg) {
  //         notification.warning({
  //           top: 92,
  //           message: msg,
  //           duration: 5
  //         })
  //         return false
  //       } else {
  //         return true
  //       }
  //     }).then(resp => {
  //       if (resp === false) return
  //       Api.getCloudConfig(param).then(response => {
  //         if (response.status) {
  //           this.setState({
  //             config: _config,
  //             openEdition: response.open_edition || '',
  //             originMenu: fromJS(_config).toJS()
  //           })
            this.submitAction(btnParam)
          } else {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      })
    }, +sessionStorage.getItem('mkDelay'))
  }
  //           this.submitAction(btnParam)
  //         } else {
  //           this.setState({
  //             menuloading: false,
  //             menucloseloading: false
  //           })
  //           notification.warning({
  //             top: 92,
  //             message: response.message,
  //             duration: 5
  //           })
  //         }
  //       })
  //     })
  //   }, +sessionStorage.getItem('mkDelay'))
  // }
  /**
   * @description 保存或修改菜单按钮集
   */
  submitAction = (btnParam) => {
    const { config } = this.state
  // submitAction = (btnParam) => {
  //   const { config } = this.state
    new Promise(resolve => {
      if (btnParam.LText) {
        Api.getCloudConfig(btnParam).then(result => {
          if (result.status) {
            this.setState({ // 保存成功后清空复制列表
              copyActions: []
            })
            resolve(result)
          } else {
            notification.warning({
              top: 92,
              message: result.message,
              duration: 5
            })
            resolve(false)
          }
        })
      } else {
        resolve(true)
      }
    }).then(response => {
      if (response === false) return response
  //   new Promise(resolve => {
  //     if (btnParam.LText) {
  //       Api.getCloudConfig(btnParam).then(result => {
  //         if (result.status) {
  //           this.setState({ // 保存成功后清空复制列表
  //             copyActions: []
  //           })
  //           resolve(result)
  //         } else {
  //           notification.warning({
  //             top: 92,
  //             message: result.message,
  //             duration: 5
  //           })
  //           resolve(false)
  //         }
  //       })
  //     } else {
  //       resolve(true)
  //     }
  //   }).then(response => {
  //     if (response === false) return response
      if (!this.state.originActions || this.state.originActions.length === 0) return 'true'
  //     if (!this.state.originActions || this.state.originActions.length === 0) return 'true'
      let oriActions = []
      this.state.originActions.forEach(item => {
        let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 查看初始化按钮是否存在
        if (!curBtn) return
        if (curBtn.OpenType !== item.prebtn.OpenType) return
        if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
  //     let oriActions = []
  //     this.state.originActions.forEach(item => {
  //       let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 查看初始化按钮是否存在
  //       if (!curBtn) return
  //       if (curBtn.OpenType !== item.prebtn.OpenType) return
  //       if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
        oriActions.push({
          prebtn: item.prebtn,
          curBtn: curBtn
        })
      })
  //       oriActions.push({
  //         prebtn: item.prebtn,
  //         curBtn: curBtn
  //       })
  //     })
      if (oriActions.length === 0) return 'true'
  //     if (oriActions.length === 0) return 'true'
      oriActions.forEach(action => {
        if (!action.prebtn || !action.prebtn.uuid) return
  //     oriActions.forEach(action => {
  //       if (!action.prebtn || !action.prebtn.uuid) return
        Api.getCloudConfig({
          func: 'sPC_Get_LongParam',
          MenuID: action.prebtn.uuid
        }).then(result => {
          if (result.status && result.LongParam) {
            let _temp = ''
  //       Api.getCloudConfig({
  //         func: 'sPC_Get_LongParam',
  //         MenuID: action.prebtn.uuid
  //       }).then(result => {
  //         if (result.status && result.LongParam) {
  //           let _temp = ''
            let _subconfig = ''
            try {
              _subconfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
              _temp = _subconfig.type
            } catch (e) {
              console.warn('Parse Failure')
              _subconfig = ''
            }
  //           let _subconfig = ''
  //           try {
  //             _subconfig = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
  //             _temp = _subconfig.type
  //           } catch (e) {
  //             console.warn('Parse Failure')
  //             _subconfig = ''
  //           }
            if (!_subconfig) return
  //           if (!_subconfig) return
            let param = {
              func: 'sPC_ButtonParam_AddUpt',
              ParentID: this.props.menu.MenuID,
              MenuID: action.curBtn.uuid,
              MenuNo: config.MenuNo,
              Template: _temp,
              MenuName: action.curBtn.label,
              PageParam: JSON.stringify({Template: _temp}),
              LongParam: result.LongParam
            }
            Api.getCloudConfig(param).then(() => {})
          }
        })
      })
      return 'true'
    }).then(response => {
      if (response === 'true') {
        notification.success({
          top: 92,
          message: '保存成功',
          duration: 2
        })
        if (this.state.closeVisible) {
          this.props.handleView()
        } else {
          this.setState({
            originActions: [],
            menuloading: false,
            menucloseloading: false
          })
        }
        this.props.reloadmenu()
      } else {
        this.setState({
          menuloading: false,
          menucloseloading: false
        })
      }
    })
  }
  //           let param = {
  //             func: 'sPC_ButtonParam_AddUpt',
  //             ParentID: this.props.menu.MenuID,
  //             MenuID: action.curBtn.uuid,
  //             MenuNo: config.MenuNo,
  //             Template: _temp,
  //             MenuName: action.curBtn.label,
  //             PageParam: JSON.stringify({Template: _temp}),
  //             LongParam: result.LongParam
  //           }
  //           Api.getCloudConfig(param).then(() => {})
  //         }
  //       })
  //     })
  //     return 'true'
  //   }).then(response => {
  //     if (response === 'true') {
  //       notification.success({
  //         top: 92,
  //         message: '保存成功',
  //         duration: 2
  //       })
  //       if (this.state.closeVisible) {
  //         this.props.handleView()
  //       } else {
  //         this.setState({
  //           originActions: [],
  //           menuloading: false,
  //           menucloseloading: false
  //         })
  //       }
  //       this.props.reloadmenu()
  //     } else {
  //       this.setState({
  //         menuloading: false,
  //         menucloseloading: false
  //       })
  //     }
  //   })
  // }
  /**
   * @description 点击返回时,判断配置保存状态
   */
  cancelConfig = () => {
    const { config, originMenu } = this.state
    // const { config, originMenu } = this.state
    let _this = this
    // let _this = this
    if (config.isAdd) {
      confirm({
        content: '菜单尚未提交,确定放弃保存吗?',
        onOk() {
          _this.props.handleView()
        },
        onCancel() {}
      })
    } else {
      if (!is(fromJS(originMenu), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      } else {
        this.props.handleView()
      }
    }
    // if (config.isAdd) {
    //   confirm({
    //     content: '菜单尚未提交,确定放弃保存吗?',
    //     onOk() {
    //       _this.props.handleView()
    //     },
    //     onCancel() {}
    //   })
    // } else {
    //   if (!is(fromJS(originMenu), fromJS(config))) {
    //     this.setState({
    //       closeVisible: true
    //     })
    //   } else {
    //     this.props.handleView()
    //   }
    // }
    this.props.handleView()
  }
  /**
@@ -1072,7 +1072,7 @@
  render () {
    const { menu } = this.props
    const { activeKey, config, chartview, openEdition } = this.state
    const { activeKey, config, chartview } = this.state
    if (!config) return null
@@ -1187,12 +1187,12 @@
            } bordered={false} extra={
              <div>
                <Unattended config={config} updateConfig={this.updateconfig}/>
                <Versions MenuId={menu.MenuID} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                {/* <Versions MenuId={menu.MenuID} open_edition={openEdition} updateConfig={this.refreshConfig}/> */}
                {/* <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/> */}
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} refresh={this.editConfig}/>
                {/* <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} refresh={this.editConfig}/> */}
                <UpdateTable config={config}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                {/* <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} /> */}
                {/* <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button> */}
                <Button onClick={this.cancelConfig}>关闭</Button>
              </div>
            } style={{ width: '100%' }}>
@@ -1281,7 +1281,7 @@
          </div>
        </DndProvider>
        {/* 返回时未保存提示 */}
        <Modal
        {/* <Modal
          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
          closable={false}
          maskClosable={false}
@@ -1295,7 +1295,7 @@
          destroyOnClose
        >
          配置已修改,是否保存配置信息?
        </Modal>
        </Modal> */}
        {this.state.loading && <Spin size="large" />}
      </div>
    )
src/templates/modalconfig/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Switch } from 'antd'
@@ -20,11 +20,11 @@
const { Panel } = Collapse
const { confirm } = Modal
const Versions = asyncComponent(() => import('@/menu/versions'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
// const Versions = asyncComponent(() => import('@/menu/versions'))
// const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const StyleController = asyncComponent(() => import('@/menu/stylecontroller'))
const ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
// const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
const DragElement = asyncComponent(() => import('./dragelement'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -407,110 +407,110 @@
    })
  }
  submitConfig = () => {
    const { editAction } = this.props
    const { config, menu, openEdition } = this.state
  // submitConfig = () => {
  //   const { editAction } = this.props
  //   const { config, menu, openEdition } = this.state
    if (config.fields[0] && config.fields[0].origin) {
      notification.warning({
        top: 92,
        message: '请添加表单',
        duration: 10
      })
      return
    }
  //   if (config.fields[0] && config.fields[0].origin) {
  //     notification.warning({
  //       top: 92,
  //       message: '请添加表单',
  //       duration: 10
  //     })
  //     return
  //   }
    let _LongParam = ''
    let _config = fromJS(config).toJS()
  //   let _LongParam = ''
  //   let _config = fromJS(config).toJS()
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 10
      })
      return
    }
  //   try {
  //     _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
  //   } catch (e) {
  //     notification.warning({
  //       top: 92,
  //       message: '编译错误',
  //       duration: 10
  //     })
  //     return
  //   }
    let param = {
      func: 'sPC_ButtonParam_AddUpt',
      ParentID: menu.MenuID,
      MenuID: editAction.uuid,
      MenuNo: menu.MenuNo,
      Template: 'Modal',
      MenuName: editAction.label,
      PageParam: JSON.stringify({Template: 'Modal'}),
      LongParam: _LongParam
    }
  //   let param = {
  //     func: 'sPC_ButtonParam_AddUpt',
  //     ParentID: menu.MenuID,
  //     MenuID: editAction.uuid,
  //     MenuNo: menu.MenuNo,
  //     Template: 'Modal',
  //     MenuName: editAction.label,
  //     PageParam: JSON.stringify({Template: 'Modal'}),
  //     LongParam: _LongParam
  //   }
    if (openEdition) {
      param.open_edition = openEdition
    }
  //   if (openEdition) {
  //     param.open_edition = openEdition
  //   }
    if (this.state.closeVisible) {
      this.setState({
        closeloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
  //   if (this.state.closeVisible) {
  //     this.setState({
  //       closeloading: true
  //     })
  //   } else {
  //     this.setState({
  //       menuloading: true
  //     })
  //   }
    Api.getCloudConfig(param).then(response => {
      if (response.status) {
        this.setState({
          openEdition: response.open_edition || '',
          menuloading: false,
          closeloading: false,
          closeVisible: false,
          originConfig: _config,
          config: _config
        })
        notification.success({
          top: 92,
          message: '保存成功',
          duration: 2
        })
      } else {
        this.setState({
          closeloading: false,
          menuloading: false
        })
        notification.warning({
          top: 92,
          message: response.message,
          duration: 10
        })
      }
    })
  }
  //   Api.getCloudConfig(param).then(response => {
  //     if (response.status) {
  //       this.setState({
  //         openEdition: response.open_edition || '',
  //         menuloading: false,
  //         closeloading: false,
  //         closeVisible: false,
  //         originConfig: _config,
  //         config: _config
  //       })
  //       notification.success({
  //         top: 92,
  //         message: '保存成功',
  //         duration: 2
  //       })
  //     } else {
  //       this.setState({
  //         closeloading: false,
  //         menuloading: false
  //       })
  //       notification.warning({
  //         top: 92,
  //         message: response.message,
  //         duration: 10
  //       })
  //     }
  //   })
  // }
  cancelConfig = () => {
    const { config, originConfig } = this.state
    let _this = this
    // const { config, originConfig } = this.state
    // let _this = this
    let isOrigin = config.fields.filter(item => item.origin).length > 0
    if (isOrigin) {
      confirm({
        content: '尚未提交,确定放弃保存吗?',
        onOk() {
          _this.handleViewBack()
        },
        onCancel() {}
      })
    } else {
      if (!is(fromJS(config), fromJS(originConfig))) {
        this.setState({
          closeVisible: true
        })
      } else {
        this.handleViewBack()
      }
    }
    // let isOrigin = config.fields.filter(item => item.origin).length > 0
    // if (isOrigin) {
    //   confirm({
    //     content: '尚未提交,确定放弃保存吗?',
    //     onOk() {
    //       _this.handleViewBack()
    //     },
    //     onCancel() {}
    //   })
    // } else {
    //   if (!is(fromJS(config), fromJS(originConfig))) {
    //     this.setState({
    //       closeVisible: true
    //     })
    //   } else {
    //     this.handleViewBack()
    //   }
    // }
    this.handleViewBack()
  }
  /**
@@ -681,8 +681,8 @@
  }
  render () {
    const { editAction } = this.props
    const { config, openEdition } = this.state
    // const { editAction } = this.props
    const { config } = this.state
    if (!config) return null
    
@@ -713,11 +713,11 @@
          <div className="setting">
            <Card title="表单配置" bordered={false} extra={
              <div>
                <Button type="danger" onClick={this.clearConfig}>清空</Button>
                <Versions MenuId={editAction.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                <ReplaceField type="form" config={config} updateConfig={this.updateconfig}/>
                <EditComponent options={['form']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                {/* <Button type="danger" onClick={this.clearConfig}>清空</Button> */}
                {/* <Versions MenuId={editAction.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/> */}
                {/* <ReplaceField type="form" config={config} updateConfig={this.updateconfig}/> */}
                {/* <EditComponent options={['form']} type="formboard" config={this.state.config} plusFields={this.plusFields}/> */}
                {/* <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button> */}
                <Button onClick={this.cancelConfig}>返回</Button>
              </div>
            } style={{ width: '100%' }}>
@@ -792,7 +792,7 @@
            wrappedComponentRef={(inst) => this.settingRef = inst}
          />
        </Modal>
        <Modal
        {/* <Modal
          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
          closable={false}
          maskClosable={false}
@@ -806,7 +806,7 @@
          destroyOnClose
        >
          配置已修改,是否保存配置信息?
        </Modal>
        </Modal> */}
        <StyleController />
      </div>
    )
src/templates/sharecomponent/actioncomponent/verifyexcelin/columnform/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Select, Button, Input, InputNumber, Radio } from 'antd'
import './index.scss'
// import './index.scss'
class ExcelInColumn extends Component {
  static propTpyes = {
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -7,7 +7,7 @@
import Api from '@/api'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
// import './index.scss'
class CustomForm extends Component {
  static propTpyes = {
@@ -341,7 +341,7 @@
              取消
            </Button>
          </Col>
          <Col span={3} style={{paddingTop: '15px', fontSize: '12px', whiteSpace: 'nowrap'}}>
          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
            强制保存:
            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
          </Col>
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -17,6 +17,7 @@
const { TabPane } = Tabs
const { confirm } = Modal
const { Search } = Input
const { Paragraph } = Typography
const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
const FullScripts = asyncComponent(() => import('@/templates/zshare/verifycard/fullScripts'))
@@ -31,6 +32,7 @@
    verify: {},
    systemScripts: [],
    activeKey: 'basemsg',
    searchKey: '',
    excelColumns: [
      {
        title: '字段',
@@ -39,6 +41,8 @@
        inputType: 'input',
        unique: true,
        strict: true,
        searchable: true,
        copy: true,
        editable: true
      },
      {
@@ -46,6 +50,7 @@
        dataIndex: 'Text',
        width: '14%',
        inputType: 'input',
        searchable: true,
        editable: true
      },
      {
@@ -297,6 +302,7 @@
    }
    this.setState({
      searchKey: '',
      verify: {
        ..._verify,
        default: _verify.default || 'true',
@@ -833,7 +839,7 @@
  render() {
    const { card } = this.props
    const { getFieldDecorator } = this.props.form
    const { verify, excelColumns, scriptsColumns, uniqueColumns, activeKey } = this.state
    const { verify, excelColumns, scriptsColumns, uniqueColumns, activeKey, searchKey } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -901,13 +907,13 @@
          } key="excelcolumn">
            <ColumnForm columnChange={this.columnChange}/>
            <Button className="excel-col-add mk-green" title="添加显示列字段" onClick={this.columnFieldInput}>
              同步显示列
              同步字段集
            </Button>
            <Button className="excel-col-add mk-red" title="清空Excel列" onClick={this.clearField}>
              清空Excel列
            </Button>
            <Col style={{fontSize: '12px', color: '#757575', paddingLeft: '10px'}} span={24}>注:数值类型(int 或 decimal),内容为必填;最大值和最小值在类型为数值时有效。导入-初始化:用于excel中不存在,导入时需要初始化的字段</Col>
            <EditTable actions={['edit', 'move', 'copy', 'del', 'extra:required:是否必填']} type="excelcolumn" data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
            <EditTable actions={['edit', 'move', 'copy', 'del', 'extra:required:是否必填']} searchKey={searchKey} type="excelcolumn" data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
          </TabPane>
          {card.intertype === 'system' ? <TabPane tab={
            <span>
@@ -925,7 +931,7 @@
            </span>
          } key="scripts" id="mk-exin-script">
            <FullScripts
              verify={verify}
              scripts={verify.scripts}
              getScriptsFullForm={() => this.scriptsFullForm}
              getScriptsForm={() => this.scriptsForm}
              handleStatus={this.handleStatus}
@@ -951,7 +957,12 @@
            />
            <EditTable actions={['move']} data={verify.scripts} columns={scriptsColumns} onChange={(scripts) => {this.setState({verify: {...verify, scripts}})}}/>
          </TabPane> : null}
          <TabPane tab="信息提示" key="tip">
          <TabPane tab={
            <span>
              信息提示
              {activeKey === 'excelcolumn' ? <span onClick={(e) => {e.stopPropagation()}}><Search className="mk-search-fields" defaultValue={searchKey} allowClear onSearch={(val, e) => {e.stopPropagation();this.setState({searchKey: val})}} /></span> : null}
            </span>
          } key="tip">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col offset={6} span={6}>
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.scss
@@ -15,6 +15,34 @@
    color: #1890ff;
    font-size: 12px;
  }
  .mk-search-fields {
    position: absolute;
    cursor: pointer;
    width: 150px;
    z-index: 1;
    top: 10px;
    right: -170px;
    display: inline-block;
    .ant-input {
      border-radius: 40px;
      height: 30px;
      transition: opacity 0.2s;
    }
    .ant-input:not(:hover):not(:active):not(:focus) {
      opacity: 0.6;
    }
    .ant-input:not(:hover):not(:active):not(:focus) + .ant-input-suffix {
      opacity: 0.6;
    }
  }
  .mk-search-fields:hover {
    .ant-input {
      opacity: 1;
    }
    .ant-input-suffix {
      opacity: 1;
    }
  }
  .verify-form {
    .sql {
      .ant-col-sm-8 {
src/templates/sharecomponent/actioncomponent/verifyexcelin/uniqueform/index.jsx
@@ -1,8 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Select, Button } from 'antd'
import './index.scss'
// import './index.scss'
class UniqueForm extends Component {
  static propTpyes = {
@@ -99,7 +98,7 @@
          <Col span={7}>
            <Form.Item label="验证类型">
              {getFieldDecorator('verifyType', {
                initialValue: 'physical',
                initialValue: 'logic',
                rules: [
                  {
                    required: true,
@@ -108,15 +107,15 @@
                ]
              })(
                <Select>
                  <Select.Option value="physical"> 物理验证(全量验证) </Select.Option>
                  <Select.Option value="logic"> 逻辑验证(全量验证) </Select.Option>
                  <Select.Option value="physical"> 物理验证(全量验证) </Select.Option>
                  <Select.Option value="physical_temp"> 物理验证(仅临时表) </Select.Option>
                  <Select.Option value="logic_temp"> 逻辑验证(仅临时表)  </Select.Option>
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={3} className="add">
          <Col span={3} className="add" style={{paddingTop: '4px'}}>
            <Button onClick={this.handleConfirm} className="mk-green">
              添加
            </Button>
src/templates/sharecomponent/actioncomponent/verifyexcelout/columnform/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Button, Input, InputNumber, Radio } from 'antd'
import './index.scss'
// import './index.scss'
class ExcelOutColumn extends Component {
  static propTpyes = {
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -9,7 +9,7 @@
import Utils from '@/utils/utils.js'
import { checkSQL } from '@/utils/utils-custom.js'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
// import './index.scss'
class CustomForm extends Component {
  static propTpyes = {
@@ -96,9 +96,16 @@
        _usefulFields.push(item.field)
        _usefulFields.push(item.datefield)
        _usefulFields.push(item.datefield + '1')
      } else if (['dateweek', 'datemonth'].includes(item.type)) {
      } else if (item.type === 'dateweek') {
        _usefulFields.push(item.field)
        _usefulFields.push(item.field + '1')
      } else if (item.type === 'datemonth') {
        if (item.match === '=') {
          _usefulFields.push(item.field)
        } else {
          _usefulFields.push(item.field)
          _usefulFields.push(item.field + '1')
        }
      } else if (item.type === 'daterange') {
        let _skey = item.field
        let _ekey = item.field + '1'
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Spin, Typography, Popconfirm } from 'antd'
import { Form, Tabs, Row, Col, Button, Input, notification, Modal, message, InputNumber, Spin, Typography, Popconfirm } from 'antd'
import { EditOutlined, StopOutlined, CheckCircleOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
import md5 from 'md5'
@@ -16,6 +16,7 @@
const { TabPane } = Tabs
const { confirm } = Modal
const { Search } = Input
const { Paragraph } = Typography
const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
@@ -29,6 +30,7 @@
    verify: {},
    debugId: '',
    activeKey: 'setting',
    searchKey: '',
    excelColumns: [
      {
        title: '字段',
@@ -36,6 +38,8 @@
        inputType: 'input',
        editable: true,
        unique: true,
        searchable: true,
        copy: true,
        width: '16%'
      },
      {
@@ -43,6 +47,7 @@
        dataIndex: 'Text',
        inputType: 'input',
        editable: true,
        searchable: true,
        unique: true,
        width: '16%'
      },
@@ -354,6 +359,7 @@
    }
    this.setState({
      searchKey: '',
      verify: _verify,
      searches: searches,
      activeKey: card.intertype === 'system' && _verify.dataType === 'custom' ? 'setting' : 'columns'
@@ -501,6 +507,7 @@
  }
  handleConfirm = () => {
    const { card, config } = this.props
    const { activeKey, verify } = this.state
    
    // 表单提交时检查输入值是否正确
@@ -516,6 +523,24 @@
        })
        
        return
      }
      if (card.intertype === 'system' && verify.dataType !== 'custom' && verify.columns.length > 0 && config.$c_ds && config.setting.interType === 'system' && config.columns && config.columns.length > 0) {
        let cols = []
        let columns = config.columns.map(c => c.field)
        verify.columns.forEach(col => {
          if (col.output === 'false' || col.Column === '$Index') return
          if (!columns.includes(col.Column)) {
            cols.push(col.Column)
          }
        })
        if (cols.length) {
          notification.warning({
            top: 92,
            message: `导出列(${cols.join('、')})在字段集中不存在!`,
            duration: 5
          })
        }
      }
      if (activeKey === 'setting') {
@@ -937,7 +962,7 @@
  render() {
    const { card } = this.props
    const { verify, excelColumns, scriptsColumns, activeKey, loading, searches } = this.state
    const { verify, excelColumns, scriptsColumns, activeKey, loading, searches, searchKey } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -965,13 +990,13 @@
          } key="columns">
            <ColumnForm columnChange={this.columnChange}/>
            <Button className="excel-col-add mk-green" title="添加显示列字段" onClick={this.columnFieldInput}>
              同步显示列
              同步字段集
            </Button>
            <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="excelcolumn" wrappedComponentRef={(inst) => this.columnRef = inst} data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
            <EditTable actions={['edit', 'move', 'copy', 'del']} type="excelcolumn" searchKey={searchKey} wrappedComponentRef={(inst) => this.columnRef = inst} data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
          </TabPane>
          {card.intertype === 'system' ? <TabPane tab={
            <span>
@@ -988,7 +1013,12 @@
            />
            <EditTable actions={['move']} data={verify.scripts} columns={scriptsColumns} onChange={(scripts) => {this.setState({verify: {...verify, scripts}})}}/>
          </TabPane> : null}
          <TabPane tab="信息提示" key="message">
          <TabPane tab={
            <span>
              信息提示
              {activeKey === 'columns' ? <span onClick={(e) => {e.stopPropagation()}}><Search className="mk-search-fields" defaultValue={searchKey} allowClear onSearch={(val, e) => {e.stopPropagation();this.setState({searchKey: val})}} /></span> : null}
            </span>
          } key="message">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col offset={6} span={6}>
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.scss
@@ -15,6 +15,34 @@
    color: #1890ff;
    font-size: 12px;
  }
  .mk-search-fields {
    position: absolute;
    cursor: pointer;
    width: 150px;
    z-index: 1;
    top: 10px;
    right: -170px;
    display: inline-block;
    .ant-input {
      border-radius: 40px;
      height: 30px;
      transition: opacity 0.2s;
    }
    .ant-input:not(:hover):not(:active):not(:focus) {
      opacity: 0.6;
    }
    .ant-input:not(:hover):not(:active):not(:focus) + .ant-input-suffix {
      opacity: 0.6;
    }
  }
  .mk-search-fields:hover {
    .ant-input {
      opacity: 1;
    }
    .ant-input-suffix {
      opacity: 1;
    }
  }
  .verify-form {
    .sql {
      .ant-col-sm-8 {
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -270,7 +270,7 @@
      dataType: _verify.dataType || 'line',
      linkType: _verify.linkType,
      printMode: _verify.printMode,
      printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-打印数据列表,form-表单信息(不存在时为{}),printer-打印设置,notification-信息提示控件,callback-释放按钮的回调'
      printFunc: _verify.printFunc || '// Function(data, form, printer, notification, Api, systemType, callback) data-打印数据列表,form-表单信息(不存在时为{}),printer-打印设置,notification-信息提示控件(移动端为Toast),Api-接口,systemType-系统类型(正式为 production,测试为空),callback-释放按钮的回调'
    })
  }
src/templates/sharecomponent/chartcomponent/chartcompile/formconfig.jsx
@@ -235,22 +235,6 @@
        text: '堆叠'
      }]
    }, {
      type: 'radio',
      key: 'repeat',
      label: '重复数据',
      initVal: card.repeat || 'unrepeat',
      required: false,
      options: [{
        value: 'unrepeat',
        text: '去重'
      }, {
        value: 'average',
        text: '平均'
      }, {
        value: 'cumsum',
        text: '累加'
      }]
    }, {
      type: 'number',
      key: 'InfoDefNumber',
      label: '展示数',
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -252,6 +252,7 @@
      reTypes.initval = 'text'
    }
    reTooltip.match = ''
    if (type === 'text') {
      reOptions.match = matchReg.class1
    } else if (type === 'multiselect') {
@@ -263,7 +264,8 @@
    } else if (type === 'date') {
      reOptions.match = matchReg.class4
    } else if (type === 'datemonth') {
      reOptions.match = matchReg.class5
      reTooltip.match = '匹配模式为 between 时,搜索条件为大于月初小于月末,匹配模式为 = 时,搜索条件为等于当前月(YYYY-MM)。'
      reOptions.match = matchReg.class6
    } else if (type === 'dateweek' || type === 'daterange' || type === 'range') {
      reOptions.match = matchReg.class5
    } else if (type === 'checkcard') {
@@ -284,6 +286,25 @@
    } else if (type === 'group') {
      reTooltip.field = '查询数据时(自定义脚本或统计数据源),类型字段将用作替换脚本中的 @字段@ ,类型字段对应值为:日 -> day;周 -> week;月 -> month;季 -> quarter;年 -> year;自定义 -> customized'
      reLabel.field = '类型字段'
    }
    reTooltip.initval = ''
    if (type === 'select') {
      if (this.record.resourceType === '0') {
        reTooltip.initval = '初始值应为数据的Value值,可使用@username@、@fullName@'
      } else if (this.record.resourceType === '1') {
        reTooltip.initval = '初始值应为《值·字段》的值,可使用@username@、@fullName@、$first。注:使用$first时,搜索条件应为必填。'
      }
    } else if (type === 'link') {
      if (this.record.resourceType === '0') {
        reTooltip.initval = '初始值应为数据的Value值。'
      } else if (this.record.resourceType === '1') {
        reTooltip.initval = '初始值应为《值·字段》的值,可使用$first。注:使用$first时,搜索条件应为必填。'
      }
    } else if (type === 'text') {
      reTooltip.initval = '可使用@username@、@fullName@。'
    } else if (type === 'range') {
      reTooltip.initval = '使用逗号拼接,例如 3,10'
    }
    return {
@@ -688,6 +709,23 @@
            values.field = values.field.join(',')
          }
          if (['select', 'link'].includes(values.type)) {
            if (values.resourceType === '1') {
              if (/\$first/.test(values.initval) && values.initval.replace(/\s/g, '') === '$first') {
                values.initval = '$first'
              }
              if (values.initval === '$first' && values.required !== 'true') {
                notification.warning({
                  top: 92,
                  message: '使用$first时,搜索条件应为必填!',
                  duration: 5
                })
                return
              }
            }
          }
          // 下拉菜单或联动菜单
          if (['multiselect', 'select', 'link', 'radio'].includes(values.type)) {
            if (values.resourceType === '0') {
src/templates/sharecomponent/settingcomponent/settingform/utils.jsx
@@ -118,13 +118,19 @@
      let arr = sql.match(/@[0-9a-zA-Z_]+@/ig)
      arr.forEach(item => {
        if (/@time_id@/ig.test(item)) return
        let reg = new RegExp(item, 'i')
        if (reg.test(_dataresource)) {
          errors.push(`数据源中存在未替换值${item}`)
        }
        scripts && scripts.forEach(script => {
          if (reg.test(script.sql)) {
            errors.push(`自定义脚本(${script.$index || ''})存在未替换值${item}`)
            if (script.$index) {
              errors.push(`自定义脚本(${script.$index})存在未替换值${item}`)
            } else {
              errors.push(`自定义脚本中存在未替换值${item}`)
            }
          }
        })
      })
src/templates/subtableconfig/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip, Col } from 'antd'
import { Button, Card, Collapse, notification, Spin, Tooltip, Col } from 'antd'
import { QuestionCircleOutlined, RedoOutlined } from '@ant-design/icons'
// import moment from 'moment'
@@ -22,11 +22,11 @@
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
// const { confirm } = Modal
const Versions = asyncComponent(() => import('@/menu/versions'))
// const Versions = asyncComponent(() => import('@/menu/versions'))
// const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
// const EditComponent = asyncComponent(() => import('@/templates/zshare/editcomponent'))
const SettingComponent = asyncComponent(() => import('@/templates/sharecomponent/settingcomponent'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
@@ -282,331 +282,332 @@
  /**
   * @description 标签页保存
   */
  submitConfig = () => {
    const { delActions, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
    let copyreg = /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/ig
  // submitConfig = () => {
  //   const { delActions, openEdition } = this.state
  //   let _config = fromJS(this.state.config).toJS()
  //   let copyreg = /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/ig
    // 基本信息验证
    if (!_config.tabName || !_config.tabNo) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      this.setState({activeKey: '0'})
      return
    }
  //   // 基本信息验证
  //   if (!_config.tabName || !_config.tabNo) {
  //     notification.warning({
  //       top: 92,
  //       message: '请完善菜单基本信息!',
  //       duration: 5
  //     })
  //     this.setState({activeKey: '0'})
  //     return
  //   }
    if (copyreg.test(_config.tabNo) || copyreg.test(_config.tabName)) {
      notification.warning({
        top: 92,
        message: '此标签为复制标签,请修改标签名称和标签参数,不可以时间格式 YYYY-MM-DD HH:mm:ss 结尾!',
        duration: 5
      })
      return
    }
  //   if (copyreg.test(_config.tabNo) || copyreg.test(_config.tabName)) {
  //     notification.warning({
  //       top: 92,
  //       message: '此标签为复制标签,请修改标签名称和标签参数,不可以时间格式 YYYY-MM-DD HH:mm:ss 结尾!',
  //       duration: 5
  //     })
  //     return
  //   }
    if (_config.isAdd) {
      if (_config.search[0] && _config.search[0].origin) {
        _config.search = _config.search.filter(item => !item.origin)
      }
      if (_config.action[0] && _config.action[0].origin) {
        _config.action = _config.action.filter(item => !item.origin)
      }
      if (_config.columns[0] && _config.columns[0].origin) {
        _config.columns = _config.columns.filter(item => !item.origin)
      }
    }
  //   if (_config.isAdd) {
  //     if (_config.search[0] && _config.search[0].origin) {
  //       _config.search = _config.search.filter(item => !item.origin)
  //     }
  //     if (_config.action[0] && _config.action[0].origin) {
  //       _config.action = _config.action.filter(item => !item.origin)
  //     }
  //     if (_config.columns[0] && _config.columns[0].origin) {
  //       _config.columns = _config.columns.filter(item => !item.origin)
  //     }
  //   }
    if (_config.setting.doubleClick && _config.action.findIndex((item) => item.uuid === _config.setting.doubleClick) === -1) {
      _config.setting.doubleClick = ''
    }
  //   if (_config.setting.doubleClick && _config.action.findIndex((item) => item.uuid === _config.setting.doubleClick) === -1) {
  //     _config.setting.doubleClick = ''
  //   }
    // 未设置数据源或主键时,启用状态为false
    let result = this.verifyconfig(_config)
  //   // 未设置数据源或主键时,启用状态为false
  //   let result = this.verifyconfig(_config)
  
    if (result !== true) {
      _config.enabled = false
    }
  //   if (result !== true) {
  //     _config.enabled = false
  //   }
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
  //   if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
  //     this.setState({
  //       menucloseloading: true
  //     })
  //   } else {
  //     this.setState({
  //       menuloading: true
  //     })
  //   }
    let _LongParam = ''
  //   let _LongParam = ''
    // 保存时删除配置类型,system 、user
    delete _config.type
    delete _config.isAdd
  //   // 保存时删除配置类型,system 、user
  //   delete _config.type
  //   delete _config.isAdd
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 5
      })
  //   try {
  //     _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
  //   } catch (e) {
  //     notification.warning({
  //       top: 92,
  //       message: '编译错误',
  //       duration: 5
  //     })
      this.setState({
        menucloseloading: false,
        menuloading: false
      })
      return
    }
  //     this.setState({
  //       menucloseloading: false,
  //       menuloading: false
  //     })
  //     return
  //   }
    // let btnParam = {
    //   func: 'sPC_Button_AddUpt',
    //   Type: 40,
    //   ParentID: _config.uuid,
    //   MenuNo: _config.tabNo,
    //   Template: 'SubTable',
    //   PageParam: '',
    //   LongParam: '',
    //   LText: []
    // }
  //   // let btnParam = {
  //   //   func: 'sPC_Button_AddUpt',
  //   //   Type: 40,
  //   //   ParentID: _config.uuid,
  //   //   MenuNo: _config.tabNo,
  //   //   Template: 'SubTable',
  //   //   PageParam: '',
  //   //   LongParam: '',
  //   //   LText: []
  //   // }
    // let btntabs = []
  //   // let btntabs = []
    // _config.action.forEach((item, index) => {
    //   if (item.hidden === 'true') return
    //   if (item.OpenType === 'popview') {
    //     btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
    //   }
    //   btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
    // })
  //   // _config.action.forEach((item, index) => {
  //   //   if (item.hidden === 'true') return
  //   //   if (item.OpenType === 'popview') {
  //   //     btntabs.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${(index + 1) * 10}' as Sort`)
  //   //   }
  //   //   btnParam.LText.push(`select '${item.uuid}' as menuid, '${item.label}' as menuname, '${(index + 1) * 10}' as Sort`)
  //   // })
    // btnParam.LText = btnParam.LText.join(' union all ')
    // btnParam.LText = Utils.formatOptions(btnParam.LText)
    // btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    // btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
  //   // btnParam.LText = btnParam.LText.join(' union all ')
  //   // btnParam.LText = Utils.formatOptions(btnParam.LText)
  //   // btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   // btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp)
    // let tabParam = { // 添加标签按钮tab页
    //   func: 'sPC_sMenusTab_AddUpt',
    //   MenuID: _config.uuid,
    //   LText: btntabs.join(' union all ')
    // }
  //   // let tabParam = { // 添加标签按钮tab页
  //   //   func: 'sPC_sMenusTab_AddUpt',
  //   //   MenuID: _config.uuid,
  //   //   LText: btntabs.join(' union all ')
  //   // }
    // tabParam.LText = Utils.formatOptions(tabParam.LText)
    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
  //   // tabParam.LText = Utils.formatOptions(tabParam.LText)
  //   // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
    let param = {
      func: 'sPC_Tab_AddUpt',
      MenuID: _config.uuid,
      MenuNo: _config.tabNo,
      Template: 'SubTable',
      MenuName: _config.tabName,
      Remark: _config.Remark,
      Sort: 0,
      PageParam: JSON.stringify({Template: 'SubTable'}),
      LongParam: _LongParam
    }
  //   let param = {
  //     func: 'sPC_Tab_AddUpt',
  //     MenuID: _config.uuid,
  //     MenuNo: _config.tabNo,
  //     Template: 'SubTable',
  //     MenuName: _config.tabName,
  //     Remark: _config.Remark,
  //     Sort: 0,
  //     PageParam: JSON.stringify({Template: 'SubTable'}),
  //     LongParam: _LongParam
  //   }
    if (openEdition) {
      param.open_edition = openEdition
    }
  //   if (openEdition) {
  //     param.open_edition = openEdition
  //   }
    // 有按钮或标签删除时,先进行删除操作
    // 删除成功后,保存页面配置
    new Promise(resolve => {
      if (delActions.length > 0) {
        let deffers = delActions.map(item => {
          let _param = {
            func: 'sPC_MainMenu_Del',
            MenuID: item.card.uuid
          }
  //   // 有按钮或标签删除时,先进行删除操作
  //   // 删除成功后,保存页面配置
  //   new Promise(resolve => {
  //     if (delActions.length > 0) {
  //       let deffers = delActions.map(item => {
  //         let _param = {
  //           func: 'sPC_MainMenu_Del',
  //           MenuID: item.card.uuid
  //         }
          let _ParentParam = null
  //         let _ParentParam = null
          try {
            _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
          } catch (e) {
            console.warn('Stringify Failure')
            _ParentParam = null
          }
  //         try {
  //           _ParentParam = window.btoa(window.encodeURIComponent(JSON.stringify(item.card)))
  //         } catch (e) {
  //           console.warn('Stringify Failure')
  //           _ParentParam = null
  //         }
          if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
            _param.ParentParam = _ParentParam
          }
  //         if (_ParentParam) { // 删除按钮时,保存按钮配置信息,用于恢复按钮
  //           _param.ParentParam = _ParentParam
  //         }
          return new Promise(resolve => {
            Api.getCloudConfig(_param).then(response => {
              resolve(response)
            })
          })
        })
        Promise.all(deffers).then(result => {
          let error = null
          result.forEach(response => {
            if (!response.status) {
              error = response
            }
          })
  //         return new Promise(resolve => {
  //           Api.getCloudConfig(_param).then(response => {
  //             resolve(response)
  //           })
  //         })
  //       })
  //       Promise.all(deffers).then(result => {
  //         let error = null
  //         result.forEach(response => {
  //           if (!response.status) {
  //             error = response
  //           }
  //         })
          if (error) {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: error.message,
              duration: 5
            })
            resolve(false)
          } else {
            this.setState({
              delActions: []
            })
            resolve(true)
          }
        })
      } else if (delActions.length === 0) {
        resolve(true)
      }
    }).then(resp => {
      if (resp === false) return
  //         if (error) {
  //           this.setState({
  //             menuloading: false,
  //             menucloseloading: false
  //           })
  //           notification.warning({
  //             top: 92,
  //             message: error.message,
  //             duration: 5
  //           })
  //           resolve(false)
  //         } else {
  //           this.setState({
  //             delActions: []
  //           })
  //           resolve(true)
  //         }
  //       })
  //     } else if (delActions.length === 0) {
  //       resolve(true)
  //     }
  //   }).then(resp => {
  //     if (resp === false) return
      return true
    }).then(res => {
      if (res === true || res === false) return res
  //     return true
  //   }).then(res => {
  //     if (res === true || res === false) return res
      let msg = res.filter(Boolean)[0]
      if (msg) {
        notification.warning({
          top: 92,
          message: msg,
          duration: 5
        })
        return false
      } else {
        return true
      }
    }).then(resp => {
      if (resp === false) return
  //     let msg = res.filter(Boolean)[0]
  //     if (msg) {
  //       notification.warning({
  //         top: 92,
  //         message: msg,
  //         duration: 5
  //       })
  //       return false
  //     } else {
  //       return true
  //     }
  //   }).then(resp => {
  //     if (resp === false) return
      Api.getCloudConfig(param).then(response => {
        if (response.status) {
          this.setState({
            openEdition: response.open_edition || '',
            config: _config,
            originConfig: fromJS(_config).toJS()
          }, () => {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.success({
              top: 92,
              message: '保存成功',
              duration: 2
            })
            if (this.state.closeVisible) {
              this.handleViewBack()
            }
          })
          this.submitAction()
        } else {
          this.setState({
            menuloading: false,
            menucloseloading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
  //     Api.getCloudConfig(param).then(response => {
  //       if (response.status) {
  //         this.setState({
  //           openEdition: response.open_edition || '',
  //           config: _config,
  //           originConfig: fromJS(_config).toJS()
  //         }, () => {
  //           this.setState({
  //             menuloading: false,
  //             menucloseloading: false
  //           })
  //           notification.success({
  //             top: 92,
  //             message: '保存成功',
  //             duration: 2
  //           })
  //           if (this.state.closeVisible) {
  //             this.handleViewBack()
  //           }
  //         })
  //         this.submitAction()
  //       } else {
  //         this.setState({
  //           menuloading: false,
  //           menucloseloading: false
  //         })
  //         notification.warning({
  //           top: 92,
  //           message: response.message,
  //           duration: 5
  //         })
  //       }
  //     })
  //   })
  // }
  /**
   * @description 保存或修改菜单按钮
   */
  submitAction = () => {
    const { config } = this.state
  // submitAction = () => {
  //   const { config } = this.state
    let oriActions = []
    this.state.originActions.forEach(item => {
      let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 查看初始化按钮是否存在
      if (!curBtn) return
      if (curBtn.OpenType !== item.prebtn.OpenType) return
      if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
  //   let oriActions = []
  //   this.state.originActions.forEach(item => {
  //     let curBtn = config.action.filter(cell => item.curuuid === cell.uuid)[0] // 查看初始化按钮是否存在
  //     if (!curBtn) return
  //     if (curBtn.OpenType !== item.prebtn.OpenType) return
  //     if (curBtn.OpenType === 'funcbutton' && curBtn.execMode !== 'pop') return
      oriActions.push({
        prebtn: item.prebtn,
        curBtn: curBtn
      })
    })
  //     oriActions.push({
  //       prebtn: item.prebtn,
  //       curBtn: curBtn
  //     })
  //   })
    if (oriActions.length === 0) return
  //   if (oriActions.length === 0) return
    oriActions.forEach(action => {
      Api.getCloudConfig({
        func: 'sPC_Get_LongParam',
        MenuID: action.prebtn ? action.prebtn.uuid : ''
      }).then(result => {
        if (result.status && result.LongParam) {
          let _LongParam = ''
  //   oriActions.forEach(action => {
  //     Api.getCloudConfig({
  //       func: 'sPC_Get_LongParam',
  //       MenuID: action.prebtn ? action.prebtn.uuid : ''
  //     }).then(result => {
  //       if (result.status && result.LongParam) {
  //         let _LongParam = ''
          if (result.LongParam) {
            try {
              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _LongParam = ''
            }
          }
  //         if (result.LongParam) {
  //           try {
  //             _LongParam = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
  //           } catch (e) {
  //             console.warn('Parse Failure')
  //             _LongParam = ''
  //           }
  //         }
          if (_LongParam) {
            let param = {
              func: 'sPC_ButtonParam_AddUpt',
              ParentID: config.uuid,
              MenuID: action.curBtn.uuid,
              MenuNo: config.tabNo,
              Template: _LongParam.type,
              MenuName: action.curBtn.label,
              PageParam: JSON.stringify({Template: _LongParam.type}),
              LongParam: result.LongParam
            }
            Api.getCloudConfig(param).then(() => {})
          }
        }
      })
    })
  }
  //         if (_LongParam) {
  //           let param = {
  //             func: 'sPC_ButtonParam_AddUpt',
  //             ParentID: config.uuid,
  //             MenuID: action.curBtn.uuid,
  //             MenuNo: config.tabNo,
  //             Template: _LongParam.type,
  //             MenuName: action.curBtn.label,
  //             PageParam: JSON.stringify({Template: _LongParam.type}),
  //             LongParam: result.LongParam
  //           }
  //           Api.getCloudConfig(param).then(() => {})
  //         }
  //       }
  //     })
  //   })
  // }
  cancelConfig = () => {
    const { config, originConfig } = this.state
    // const { config, originConfig } = this.state
    let _this = this
    // let _this = this
    if (originConfig.isAdd) {
      confirm({
        content: '菜单尚未提交,确定放弃保存吗?',
        onOk() {
          _this.handleViewBack()
        },
        onCancel() {}
      })
    } else {
      if (!is(fromJS(originConfig), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      } else {
        this.handleViewBack()
      }
    }
    // if (originConfig.isAdd) {
    //   confirm({
    //     content: '菜单尚未提交,确定放弃保存吗?',
    //     onOk() {
    //       _this.handleViewBack()
    //     },
    //     onCancel() {}
    //   })
    // } else {
    //   if (!is(fromJS(originConfig), fromJS(config))) {
    //     this.setState({
    //       closeVisible: true
    //     })
    //   } else {
    //     this.handleViewBack()
    //   }
    // }
    this.handleViewBack()
  }
  /**
@@ -910,7 +911,7 @@
  }
  render () {
    const { activeKey, config, chartview, openEdition } = this.state
    const { activeKey, config, chartview } = this.state
    if (!config) return null
@@ -994,11 +995,11 @@
              </div>
            } bordered={false} extra={
              <div>
                <Versions MenuId={config.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                {/* <Versions MenuId={config.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/> */}
                {/* <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/> */}
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} refresh={this.updateConfig}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                {/* <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} refresh={this.updateConfig}/> */}
                {/* <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} /> */}
                {/* <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button> */}
                <Button onClick={this.cancelConfig}>返回</Button>
              </div>
            } style={{ width: '100%' }}>
@@ -1080,7 +1081,7 @@
            </Card>
          </div>
        </DndProvider>
        <Modal
        {/* <Modal
          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
          closable={false}
          maskClosable={false}
@@ -1094,7 +1095,7 @@
          destroyOnClose
        >
          配置已修改,是否保存配置信息?
        </Modal>
        </Modal> */}
        {this.state.loading && <Spin size="large" />}
      </div>
    )
src/templates/treepageconfig/index.jsx
@@ -3,9 +3,8 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { Button, Card, Modal, Collapse, notification, Spin, Switch, Tooltip, Row, Col, Tree } from 'antd'
import { Button, Card, Collapse, notification, Spin, Tooltip, Row, Col, Tree } from 'antd'
import { QuestionCircleOutlined, RedoOutlined, SearchOutlined, FileOutlined, FolderOpenOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -17,7 +16,7 @@
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
// const { confirm } = Modal
const { TreeNode } = Tree
const UpdateTable = asyncComponent(() => import('./updatetable'))
@@ -215,255 +214,256 @@
  /**
   * @description 三级菜单保存
   */
  submitConfig = () => {
    const { menu } = this.props
    const { delTabs, openEdition } = this.state
  // submitConfig = () => {
  //   const { menu } = this.props
  //   const { delTabs, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
  //   let _config = fromJS(this.state.config).toJS()
    // 基本信息验证
    if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      this.setState({activeKey: '0'})
      return
    }
  //   // 基本信息验证
  //   if (!_config.fstMenuId || !_config.ParentId || !_config.MenuName || !_config.MenuNo) {
  //     notification.warning({
  //       top: 92,
  //       message: '请完善菜单基本信息!',
  //       duration: 5
  //     })
  //     this.setState({activeKey: '0'})
  //     return
  //   }
    // 新建验证
    if (_config.isAdd) {
      _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
    }
  //   // 新建验证
  //   if (_config.isAdd) {
  //     _config.tabgroups[0].sublist = _config.tabgroups[0].sublist.filter(item => !item.origin)
  //   }
    // 使用已有菜单时,默认添加关联标签id
    if (_config.type === 'user') {
      _config.tabgroups.forEach(group => {
        group.sublist = group.sublist.map(tab => {
          if (!tab.linkTab) {
            tab.linkTab = Utils.getuuid()
          }
          return tab
        })
      })
    }
  //   // 使用已有菜单时,默认添加关联标签id
  //   if (_config.type === 'user') {
  //     _config.tabgroups.forEach(group => {
  //       group.sublist = group.sublist.map(tab => {
  //         if (!tab.linkTab) {
  //           tab.linkTab = Utils.getuuid()
  //         }
  //         return tab
  //       })
  //     })
  //   }
    // 未设置数据源或标签不合法时,启用状态为false
    let vresult = this.verifyconfig(_config)
    if (vresult !== true) {
      _config.enabled = false
    }
  //   // 未设置数据源或标签不合法时,启用状态为false
  //   let vresult = this.verifyconfig(_config)
  //   if (vresult !== true) {
  //     _config.enabled = false
  //   }
    if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
      this.setState({
        menucloseloading: true
      })
    } else {
      this.setState({
        menuloading: true
      })
    }
  //   if (this.state.closeVisible) { // 显示关闭对话框时,模态框中保存按钮,显示保存中状态
  //     this.setState({
  //       menucloseloading: true
  //     })
  //   } else {
  //     this.setState({
  //       menuloading: true
  //     })
  //   }
    // 保存时删除配置类型,system 、user
    delete _config.type
    delete _config.isAdd
  //   // 保存时删除配置类型,system 、user
  //   delete _config.type
  //   delete _config.isAdd
    let _LongParam = ''
  //   let _LongParam = ''
    try {
      _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
    } catch (e) {
      notification.warning({
        top: 92,
        message: '编译错误',
        duration: 5
      })
      this.setState({
        menucloseloading: false,
        menuloading: false
      })
      return
    }
  //   try {
  //     _LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
  //   } catch (e) {
  //     notification.warning({
  //       top: 92,
  //       message: '编译错误',
  //       duration: 5
  //     })
  //     this.setState({
  //       menucloseloading: false,
  //       menuloading: false
  //     })
  //     return
  //   }
    // let _sort = 0
    // let btntabs = []
  //   // let _sort = 0
  //   // let btntabs = []
    
    // let tabParam = { // 添加菜单tab页
    //   func: 'sPC_sMenusTab_AddUpt',
    //   MenuID: menu.MenuID
    // }
  //   // let tabParam = { // 添加菜单tab页
  //   //   func: 'sPC_sMenusTab_AddUpt',
  //   //   MenuID: menu.MenuID
  //   // }
    // let _LText = []
  //   // let _LText = []
    // btntabs.forEach(item => {
    //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
    // })
    // _config.tabgroups.forEach(group => {
    //   group.sublist.forEach(item => {
    //     _sort++
    //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
    //   })
    // })
  //   // btntabs.forEach(item => {
  //   //   _LText.push(`select '${item.uuid}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${item.sort * 10}' as Sort`)
  //   // })
  //   // _config.tabgroups.forEach(group => {
  //   //   group.sublist.forEach(item => {
  //   //     _sort++
  //   //     _LText.push(`select '${menu.MenuID}' as MenuID ,'${item.linkTab}' as Tabid,'${item.label}' as TabName ,'${_sort * 10}' as Sort`)
  //   //   })
  //   // })
    // _LText = _LText.join(' union all ')
  //   // _LText = _LText.join(' union all ')
    // tabParam.LText = Utils.formatOptions(_LText)
    // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
  //   // tabParam.LText = Utils.formatOptions(_LText)
  //   // tabParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   // tabParam.secretkey = Utils.encrypt(tabParam.LText, tabParam.timestamp)
    let _funcs = []
    let _tables = []
  //   let _funcs = []
  //   let _tables = []
    if (_config.setting.tableName) {
      _tables.push(_config.setting.tableName)
    }
    if (_config.setting.innerFunc) {
      _funcs.push({func: _config.setting.innerFunc, label: _config.MenuName || ''})
    }
    if (_config.setting.outerFunc) {
      _funcs.push({func: _config.setting.outerFunc, label: _config.MenuName || ''})
    }
  //   if (_config.setting.tableName) {
  //     _tables.push(_config.setting.tableName)
  //   }
  //   if (_config.setting.innerFunc) {
  //     _funcs.push({func: _config.setting.innerFunc, label: _config.MenuName || ''})
  //   }
  //   if (_config.setting.outerFunc) {
  //     _funcs.push({func: _config.setting.outerFunc, label: _config.MenuName || ''})
  //   }
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
      FstID: _config.fstMenuId,
      SndID: _config.ParentId,
      ParentID: _config.ParentId,
      MenuID: menu.MenuID,
      MenuNo: _config.MenuNo,
      EasyCode: _config.easyCode,
      Template: _config.Template,
      MenuName: _config.MenuName,
      PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType}),
      LongParam: _LongParam,
      LText: _funcs.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
      LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
    }
  //   let param = {
  //     func: 'sPC_TrdMenu_AddUpt',
  //     FstID: _config.fstMenuId,
  //     SndID: _config.ParentId,
  //     ParentID: _config.ParentId,
  //     MenuID: menu.MenuID,
  //     MenuNo: _config.MenuNo,
  //     EasyCode: _config.easyCode,
  //     Template: _config.Template,
  //     MenuName: _config.MenuName,
  //     PageParam: JSON.stringify({...menu.PageParam, Template: _config.Template, OpenType: _config.OpenType}),
  //     LongParam: _LongParam,
  //     LText: _funcs.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
  //     LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`)
  //   }
    if (menu.menuSort) { // 菜单新建时设置排序
      param.Sort = menu.menuSort
    }
  //   if (menu.menuSort) { // 菜单新建时设置排序
  //     param.Sort = menu.menuSort
  //   }
    param.LText = param.LText.join(' union all ')
    param.LText = Utils.formatOptions(param.LText)
    param.LTexttb = param.LTexttb.join(' union all ')
    param.LTexttb = Utils.formatOptions(param.LTexttb)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
  //   param.LText = param.LText.join(' union all ')
  //   param.LText = Utils.formatOptions(param.LText)
  //   param.LTexttb = param.LTexttb.join(' union all ')
  //   param.LTexttb = Utils.formatOptions(param.LTexttb)
  //   param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
  //   param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    if (openEdition) { // 版本管理
      param.open_edition = openEdition
    }
  //   if (openEdition) { // 版本管理
  //     param.open_edition = openEdition
  //   }
    // 有按钮或标签删除时,先进行删除操作
    // 删除成功后,保存页面配置
    new Promise(resolve => {
      if (delTabs.length > 0) {
        let deffers = delTabs.map(item => {
          let _param = {
            func: 'sPC_MainMenu_Del',
            MenuID: item.uuid
          }
  //   // 有按钮或标签删除时,先进行删除操作
  //   // 删除成功后,保存页面配置
  //   new Promise(resolve => {
  //     if (delTabs.length > 0) {
  //       let deffers = delTabs.map(item => {
  //         let _param = {
  //           func: 'sPC_MainMenu_Del',
  //           MenuID: item.uuid
  //         }
          return new Promise(resolve => {
            Api.getCloudConfig(_param).then(response => {
              resolve(response)
            })
          })
        })
        Promise.all(deffers).then(result => {
          let error = null
          result.forEach(response => {
            if (!response.status) {
              error = response
            }
          })
  //         return new Promise(resolve => {
  //           Api.getCloudConfig(_param).then(response => {
  //             resolve(response)
  //           })
  //         })
  //       })
  //       Promise.all(deffers).then(result => {
  //         let error = null
  //         result.forEach(response => {
  //           if (!response.status) {
  //             error = response
  //           }
  //         })
          if (error) {
            this.setState({
              menuloading: false,
              menucloseloading: false
            })
            notification.warning({
              top: 92,
              message: error.message,
              duration: 5
            })
            resolve(false)
          } else {
            this.setState({
              delTabs: []
            })
            resolve(true)
          }
        })
      } else if (delTabs.length === 0) {
        resolve(true)
      }
    }).then(resp => {
      if (resp === false) return
  //         if (error) {
  //           this.setState({
  //             menuloading: false,
  //             menucloseloading: false
  //           })
  //           notification.warning({
  //             top: 92,
  //             message: error.message,
  //             duration: 5
  //           })
  //           resolve(false)
  //         } else {
  //           this.setState({
  //             delTabs: []
  //           })
  //           resolve(true)
  //         }
  //       })
  //     } else if (delTabs.length === 0) {
  //       resolve(true)
  //     }
  //   }).then(resp => {
  //     if (resp === false) return
      Api.getCloudConfig(param).then(response => {
        if (response.status) {
          this.setState({
            config: _config,
            openEdition: response.open_edition || '',
            originMenu: fromJS(_config).toJS(),
            menuloading: false,
            menucloseloading: false
          })
  //     Api.getCloudConfig(param).then(response => {
  //       if (response.status) {
  //         this.setState({
  //           config: _config,
  //           openEdition: response.open_edition || '',
  //           originMenu: fromJS(_config).toJS(),
  //           menuloading: false,
  //           menucloseloading: false
  //         })
          notification.success({
            top: 92,
            message: '保存成功',
            duration: 2
          })
  //         notification.success({
  //           top: 92,
  //           message: '保存成功',
  //           duration: 2
  //         })
          this.props.reloadmenu()
  //         this.props.reloadmenu()
          if (this.state.closeVisible) {
            this.props.handleView()
          }
        } else {
          this.setState({
            menuloading: false,
            menucloseloading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
  //         if (this.state.closeVisible) {
  //           this.props.handleView()
  //         }
  //       } else {
  //         this.setState({
  //           menuloading: false,
  //           menucloseloading: false
  //         })
  //         notification.warning({
  //           top: 92,
  //           message: response.message,
  //           duration: 5
  //         })
  //       }
  //     })
  //   })
  // }
  /**
   * @description 点击返回时,判断配置保存状态
   */
  cancelConfig = () => {
    const { config, originMenu } = this.state
    let _this = this
    // const { config, originMenu } = this.state
    // let _this = this
    if (config.isAdd) {
      confirm({
        content: '菜单尚未提交,确定放弃保存吗?',
        onOk() {
          _this.props.handleView()
        },
        onCancel() {}
      })
    } else {
      if (!is(fromJS(originMenu), fromJS(config))) {
        this.setState({
          closeVisible: true
        })
      } else {
        this.props.handleView()
      }
    }
    // if (config.isAdd) {
    //   confirm({
    //     content: '菜单尚未提交,确定放弃保存吗?',
    //     onOk() {
    //       _this.props.handleView()
    //     },
    //     onCancel() {}
    //   })
    // } else {
    //   if (!is(fromJS(originMenu), fromJS(config))) {
    //     this.setState({
    //       closeVisible: true
    //     })
    //   } else {
    //     this.props.handleView()
    //   }
    // }
    this.props.handleView()
  }
  /**
@@ -710,8 +710,8 @@
            } bordered={false} extra={
              <div>
                <UpdateTable config={config}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                {/* <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} /> */}
                {/* <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button> */}
                <Button onClick={this.cancelConfig}>关闭</Button>
              </div>
            } style={{ width: '100%' }}>
@@ -765,7 +765,7 @@
          </div>
        </DndProvider>
        {/* 返回时未保存提示 */}
        <Modal
        {/* <Modal
          bodyStyle={{textAlign: 'center', color: '#000000', fontSize: '16px'}}
          closable={false}
          maskClosable={false}
@@ -779,7 +779,7 @@
          destroyOnClose
        >
          配置已修改,是否保存配置信息?
        </Modal>
        </Modal> */}
        {this.state.loading && <Spin size="large" />}
      </div>
    )
src/templates/zshare/codemirror/index.jsx
@@ -240,7 +240,7 @@
          {fullScreen || func ? <Dropdown overlayClassName="mk-mirror-font" overlay={menu} placement="bottomRight">
            <FontSizeOutlined />
          </Dropdown> : null}
          <SwapOutlined title="字符替换" onClick={() => this.setState({visible: true})}/>
          {!mode ? <SwapOutlined title="字符替换" onClick={() => this.setState({visible: true})}/> : null}
          {display ? <CodeMirror
            className="code-mirror-area"
            value={defaultVal}
src/templates/zshare/editTable/index.jsx
@@ -826,7 +826,17 @@
      return item
    })
    let reg = searchKey ? new RegExp(searchKey, 'i') : null
    let reg = null
    let regs = []
    if (searchKey) {
      reg = new RegExp(searchKey, 'i')
      this.state.columns.forEach(col => {
        if (col.searchable) {
          regs.push(col.dataIndex)
        }
      })
    }
    return (
      <EditableContext.Provider value={this.props.form}>
@@ -845,7 +855,7 @@
                  className += ' active'
                }
                if (searchKey) {
                  if (!reg.test(record.field) && !reg.test(record.label)) {
                  if (regs.findIndex(f => reg.test(record[f])) === -1) {
                    className += ' hidden'
                  }
                }
src/templates/zshare/formconfig.jsx
@@ -166,7 +166,6 @@
      type: 'text',
      key: 'initval',
      label: '初始值',
      tooltip: '类型为下拉菜单时,初始值应为数据的Value值(使用数据源时,应为《值·字段》的值);类型为数值(区间)时,初始值使用逗号拼接,例如 3,10;文本与下拉菜单中可使用@username@、@fullName@',
      initVal: card.initval,
      required: false
    },
src/templates/zshare/modalform/index.jsx
@@ -289,6 +289,10 @@
      if (this.record.interception === 'func') {
        shows.push('func')
      }
    } else if (type === 'popSelect') {
      if (this.record.enter === 'tab' || this.record.enter === 'sub') {
        shows.push('tabField')
      }
    }
    if (['multiselect', 'select', 'link', 'radio', 'checkbox', 'checkcard', 'cascader'].includes(type)) {
@@ -383,7 +387,7 @@
      if (value === 'text' || value === 'number') {
        this.record.enter = 'sub'
        _fieldval.enter = 'sub'
      } else if (value === 'select' || value === 'link') {
      } else if (['select', 'link', 'popSelect', 'vercode'].includes(value)) {
        _fieldval.enter = 'false'
      }
src/templates/zshare/verifycard/baseform/index.jsx
@@ -1,11 +1,12 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Select, Radio, Tooltip, Input, notification } from 'antd'
import { Form, Row, Col, Select, Radio, Tooltip, Input } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
import MkPrintTemps from '@/menu/components/share/actioncomponent/actionform/mkPrintTemps'
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
const sysTempsIds = ['8IFltwzyKcu15iA8fqSyb6m-pMa88a3ZTu0No3vDHgo', 'LOB-bbt9jVncGh7IOAUdESh1Sgzcbt62UwOqSqcK9ok']
@@ -16,6 +17,7 @@
    verify: PropTypes.object,
    unionFields: PropTypes.array,
    notes: PropTypes.array,
    emailCodes: PropTypes.array,
    appType: PropTypes.any,
    onChange: PropTypes.func
  }
@@ -128,10 +130,14 @@
    let error = ''
    if (verify.noteEnable === 'true' && !verify.noteCode) { // 开启短信时,需要模板编码
      error = '开启短信时,需要选择短信模板!'
    } else if (verify.emailEnable === 'true' && !verify.emailCode) {
      error = '开启邮件发送时,需要选择邮件模板!'
    } else if (verify.printEnable === 'true' && !verify.printTempId) {
      error = '使用单据打印时,需要选择打印模板!'
    } else if (verify.accountdate === 'true' && !verify.accountfield) {
      error = '开启账期时,需要选择验证公司!'
    } else if (verify.preHandle === 'true' && !verify.pre_func) {
      error = '开启按钮预处理时,需要填写处理函数!'
    } else if (verify.wxNote === 'true') {
      if (!verify.wxTemplateId) {
        error = '开启公众号消息推送时,需要选择消息模板!'
@@ -146,12 +152,17 @@
  }
  onOptionChange = (value, key) => {
    const { verify, setting } = this.props
    const { verify } = this.props
    let _verify = {...verify, [key]: value}
    if (_verify.noteEnable !== 'true') {
      _verify.noteCode = ''
      _verify.noteId = ''
    }
    if (_verify.emailEnable !== 'true') {
      _verify.emailCode = ''
      _verify.emailId = ''
    }
    if (_verify.printEnable !== 'true') {
      _verify.printTempId = ''
@@ -159,6 +170,9 @@
    if (_verify.accountdate !== 'true') {
      _verify.accountfield = ''
      _verify.voucherdate = ''
    }
    if (_verify.preHandle !== 'true') {
      _verify.pre_func = ''
    }
    if (_verify.wxNote !== 'true') {
      _verify.wxTemplateId = ''
@@ -175,15 +189,6 @@
      }
    }
    if (verify.invalid !== 'true' && _verify.invalid === 'true' && setting.maxScript && setting.maxScript >= 300) {
      notification.warning({
        top: 92,
        message: '数据源中自定义脚本过于复杂,不能使用失效验证!',
        duration: 5
      })
      return
    }
    this.props.onChange(_verify)
  }
@@ -191,6 +196,14 @@
    const { verify } = this.props
    let _verify = {...verify, noteCode: val, noteId: option.props.id}
    this.props.onChange(_verify)
  }
  onEmailCodeChange = (val, option) => {
    const { verify } = this.props
    let _verify = {...verify, emailCode: val, emailId: option.props.id}
    this.props.onChange(_verify)
  }
@@ -279,7 +292,7 @@
  }
  render() {
    const { unionFields, verify, notes, card, appType, columns } = this.props
    const { unionFields, verify, notes, emailCodes, card, appType, columns } = this.props
    const { wxTemps, selectTemp } = this.state
    const formItemLayout = {
      labelCol: {
@@ -320,8 +333,13 @@
            </Form.Item>
          </Col> : null}
          {card.intertype !== 'inner' ? <Col span={8}>
            <Form.Item label={'失效验证'}>
              <Radio.Group value={verify.invalid} onChange={(e) => {this.onOptionChange(e.target.value, 'invalid')}}>
            <Form.Item label={
              verify.limitText ? <Tooltip placement="bottomLeft" title={verify.limitText}>
                <QuestionCircleOutlined className="mk-form-tip" />
                失效验证
              </Tooltip> : '失效验证'
            }>
              <Radio.Group value={verify.invalid} disabled={verify.limitInvalid} onChange={(e) => {this.onOptionChange(e.target.value, 'invalid')}}>
                <Radio value="true">开启</Radio>
                <Radio value="false">不开启</Radio>
              </Radio.Group>
@@ -383,7 +401,7 @@
                短信模板
              </Tooltip>
            } required>
              <Select value={verify.noteCode} onSelect={this.onNoteCodeChange}>
              <Select value={verify.noteCode || ''} onSelect={this.onNoteCodeChange}>
                {notes.map(option =>
                  <Select.Option key={option.value} id={option.id} value={option.value}>
                    {option.name}
@@ -399,7 +417,7 @@
                发送方式
              </Tooltip>
            }>
              <Radio.Group value={verify.noteType} onChange={(e) => {this.onOptionChange(e.target.value, 'noteType')}}>
              <Radio.Group value={verify.noteType || 'N'} onChange={(e) => {this.onOptionChange(e.target.value, 'noteType')}}>
                <Radio value="Y">实时</Radio>
                <Radio value="N">定时</Radio>
              </Radio.Group>
@@ -412,7 +430,63 @@
                短信内容
              </Tooltip>
            }>
              <Radio.Group value={verify.noteTemp} onChange={(e) => {this.onOptionChange(e.target.value, 'noteTemp')}}>
              <Radio.Group value={verify.noteTemp || 'Y'} onChange={(e) => {this.onOptionChange(e.target.value, 'noteTemp')}}>
                <Radio value="Y">相同</Radio>
                <Radio value="N">不同</Radio>
              </Radio.Group>
            </Form.Item>
          </Col> : null}
          <Col span={24}></Col>
          <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title={'选择发送邮件时,需完善邮件设置。'}>
                <QuestionCircleOutlined className="mk-form-tip" />
                发送邮件
              </Tooltip>
            }>
              <Radio.Group value={verify.emailEnable} onChange={(e) => {this.onOptionChange(e.target.value, 'emailEnable')}}>
                <Radio value="true">开启</Radio>
                <Radio value="false">不开启</Radio>
              </Radio.Group>
            </Form.Item>
          </Col>
          {verify.emailEnable === 'true' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title={<span>邮件模板添加地址:<a target="_blank" rel="noopener noreferrer" href="https://cloud.mk9h.cn/admin/index.html">云中心</a>-&gt;应用服务-&gt;开发者中心-&gt;邮件模板。</span>}>
                <QuestionCircleOutlined className="mk-form-tip" />
                邮件模板
              </Tooltip>
            } required>
              <Select value={verify.emailCode || ''} onSelect={this.onEmailCodeChange}>
                {emailCodes.map(option =>
                  <Select.Option key={option.value} id={option.id} value={option.value}>
                    {option.name}
                  </Select.Option>
                )}
              </Select>
            </Form.Item>
          </Col> : null}
          {verify.emailEnable === 'true' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title={'实时发送最多同时发送5个用户,定时发送最多同时发送100个用户。'}>
                <QuestionCircleOutlined className="mk-form-tip" />
                发送方式
              </Tooltip>
            }>
              <Radio.Group value={verify.emailType || 'N'} onChange={(e) => {this.onOptionChange(e.target.value, 'emailType')}}>
                <Radio value="Y">实时</Radio>
                <Radio value="N">定时</Radio>
              </Radio.Group>
            </Form.Item>
          </Col> : null}
          {verify.emailEnable === 'true' ? <Col span={8}>
            <Form.Item label={
              <Tooltip placement="bottomLeft" title={'当向多个用户发送短信时,短信内容是否相同。'}>
                <QuestionCircleOutlined className="mk-form-tip" />
                邮件内容
              </Tooltip>
            }>
              <Radio.Group value={verify.emailTemp || 'Y'} onChange={(e) => {this.onOptionChange(e.target.value, 'emailTemp')}}>
                <Radio value="Y">相同</Radio>
                <Radio value="N">不同</Radio>
              </Radio.Group>
@@ -620,6 +694,23 @@
              </div>
            </div>
          </Col> : null}
          <Col span={24}></Col>
          <Col span={8}>
            <Form.Item label={
              <Tooltip placement="topRight" title="运行时修改按钮参数,入参为(btn, systemType)。注:systemType为系统类型,正式系统为production">
                <QuestionCircleOutlined className="mk-form-tip" />
                按钮预处理
              </Tooltip>
            }>
              <Radio.Group value={verify.preHandle || 'false'} onChange={(e) => {this.onOptionChange(e.target.value, 'preHandle')}}>
                <Radio value="true">开启</Radio>
                <Radio value="false">不开启</Radio>
              </Radio.Group>
            </Form.Item>
          </Col>
          {verify.preHandle === 'true' ? <Col span={24} style={{paddingLeft: '50px'}}>
            <CodeMirror mode="text/javascript" theme="cobalt" value={verify.pre_func || ''} onChange={(val) => {this.onOptionChange(val, 'pre_func')}} />
          </Col> : null}
        </Row>
      </Form>
    )
src/templates/zshare/verifycard/billcodeform/index.jsx
@@ -311,7 +311,7 @@
            </Button>
          </Col>
          {type === '1' ? <Col span={7}>
            <Form.Item label={'位数'}>
            <Form.Item label="位数">
              {getFieldDecorator('Type', {
                initialValue: 4,
                rules: [
@@ -320,11 +320,11 @@
                    message: '请输入位数!'
                  }
                ]
              })(<InputNumber min={1} max={10} precision={0} />)}
              })(<InputNumber min={1} max={10} precision={0} onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col> : null}
          {type === '2' ? <Col span={7}>
            <Form.Item label={'凭证标识'}>
            <Form.Item label="凭证标识">
              {getFieldDecorator('ModularDetailCode', {
                initialValue: this.state.modularDetail[0] ? this.state.modularDetail[0].ModularDetailCode : '',
                rules: [
@@ -366,7 +366,7 @@
                    message: '请输入数字、字母以及_'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col> : null}
        </Row>
src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -1,6 +1,6 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Button, Modal, Tooltip, Radio, Select, Switch } from 'antd'
import { Form, Row, Col, Button, Modal, Tooltip, Radio, Select, Switch, notification } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
@@ -29,18 +29,39 @@
      editItem: record
    })
    this.props.form.setFieldsValue({
      sql: record.sql,
      position: record.position || 'back'
    })
    if (this.props.type) {
      this.props.form.setFieldsValue({
        sql: record.sql
      })
    } else {
      this.props.form.setFieldsValue({
        sql: record.sql,
        position: record.position || 'back'
      })
    }
  }
  handleConfirm = () => {
    const { type } = this.props
    const { editItem, skip } = this.state
    // 表单提交时检查输入值是否正确
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (type === 'fullscreen' && err) {
        notification.warning({
          top: 92,
          message: '请输入sql!',
          duration: 5
        })
        return
      }
      if (!err) {
        values.uuid = editItem ? editItem.uuid : ''
        values.position = values.position || (editItem ? editItem.position : 'front')
        if (type === 'fullscreen' && editItem) {
          values.status = editItem.status || 'true'
        }
        let pass = checkSQL(values.sql, 'customscript')
@@ -166,9 +187,9 @@
  }
  render() {
    const { usefulfields, systemScripts, btn } = this.props
    const { usefulfields, systemScripts, btn, type } = this.props
    const { getFieldDecorator } = this.props.form
    const { skip } = this.state
    const { editItem, skip } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -185,25 +206,25 @@
    return (
      <Form {...formItemLayout} className="verify-form verify-custom-callback-scripts" id="verify-custom-callback-scripts">
        <Row gutter={24}>
          <Col span={8}>
          {!type ? <Col span={8}>
            <Form.Item label={'表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
              {btn.cbTable}
            </Form.Item>
          </Col>
          <Col span={10}>
          </Col> : null}
          {!type ? <Col span={10}>
            <Form.Item label={'报错字段'} style={{margin: 0, whiteSpace: 'nowrap'}}>
              ErrorCode(增加后缀NT表示数据不回滚,如ENT、NNT、FNT、NMNT、CNT、-2NT), retmsg
            </Form.Item>
          </Col>
          <Col span={24} className="sqlfield">
          </Col> : null}
          {!type ? <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {usefulfields ? <span>, {usefulfields}</span> : ''}
            </Form.Item>
          </Col>
          <Col span={8} style={{whiteSpace: 'nowrap'}}>
          </Col> : null}
          {!type ? <Col span={8} style={{whiteSpace: 'nowrap'}}>
            <Form.Item style={{marginBottom: 0}} label={
              <Tooltip placement="bottomLeft" title={'自定义脚本与默认sql位置关系。'}>
                <QuestionCircleOutlined className="mk-form-tip" />
@@ -219,8 +240,8 @@
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={8}>
          </Col> : null}
          {!type ? <Col span={8}>
            <Form.Item label={'快捷添加'} style={{marginBottom: 0}}>
              <Select
                allowClear
@@ -235,16 +256,16 @@
                )}
              </Select>
            </Form.Item>
          </Col>
          </Col> : null}
          <Col span={5} className="add" style={{whiteSpace: 'nowrap'}}>
            <Button onClick={this.handleConfirm} loading={this.state.loading} className="mk-green" style={{marginBottom: 15, marginLeft: 40}}>
              保存
              {type === 'fullscreen' && !editItem ? '添加' : '保存'}
            </Button>
            <Button onClick={this.handleCancel} style={{marginBottom: 15, marginLeft: 10}}>
              取消
            </Button>
          </Col>
          <Col span={3} style={{paddingTop: '15px', fontSize: '12px', whiteSpace: 'nowrap'}}>
          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
            强制保存:
            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
          </Col>
src/templates/zshare/verifycard/contrastform/index.jsx
@@ -48,7 +48,7 @@
                    message: '请输入内容1!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col>
          <Col span={7}>
@@ -85,7 +85,7 @@
                    message: '请输入内容2!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col>
          <Col span={3} className="add">
@@ -107,11 +107,11 @@
                    message: '提示信息不允许包含\''
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col>
          <Col span={7}>
            <Form.Item label={'报错编码'}>
            <Form.Item label="报错编码">
              {getFieldDecorator('errorCode', {
                initialValue: 'E',
                rules: [
src/templates/zshare/verifycard/customform/index.jsx
@@ -195,7 +195,7 @@
                    message: '提示信息不允许包含\''
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleConfirm}/>)}
            </Form.Item>
          </Col>
          <Col span={7}>
src/templates/zshare/verifycard/customscript/index.jsx
@@ -351,10 +351,10 @@
              取消
            </Button>
          </Col>
          {!_type ? <Col span={3} style={{paddingTop: '15px', fontSize: '12px', whiteSpace: 'nowrap'}}>
          <Col span={3} className="forced" style={{paddingTop: '12px', fontSize: '12px', whiteSpace: 'nowrap'}}>
            强制保存:
            <Switch checked={skip} size="small" onChange={() => this.setState({skip: !skip})}/>
          </Col> : null}
          </Col>
          <Col span={24} className="sql">
            <Form.Item label={
              <Tooltip placement="topLeft" overlayStyle={{width: '320px', maxWidth: '320px'}} title={<><div>{'调试替换符 /*$breakpoint_begin_xxxx@ 、@breakpoint_end_xxxx$*/,在控制台中输入 window.debug = \'xxxx\' 会启用对应的调试语句,快捷键 ctrl+c 或在控制台中输入 window.debug = false 关闭调试。注:调试时字符 $breakpoint_proc@ 将被替换。'}</div><div style={{height: '5px'}}></div><div>{'数据检查替换符 $check@ -> \'\'、 @check$ -> \'\',ErrorCode等于C时会询问是否继续执行,确定时 $check@ -> /*、 @check$ -> */。注:1、需使用系统接口 2、行设置为“选择多行”时无效。'}</div></>}>
src/templates/zshare/verifycard/fullScripts/index.jsx
@@ -10,7 +10,7 @@
class fullScripts extends Component {
  static propTpyes = {
    verify: PropTypes.object,
    scripts: PropTypes.array,
    getScriptsForm: PropTypes.func
  }
@@ -41,9 +41,11 @@
  }
  render() {
    const { verify, children } = this.props
    const { scripts, children } = this.props
    const { visible, scriptId } = this.state
    if (scripts.length === 0) return null
    return (
      <>
        <BorderOutlined className="full-scripts" onClick={this.trigger}/>
@@ -57,7 +59,7 @@
        >
          <img className="unfull-scripts" src={MinView} onClick={() => this.setState({visible: false, scriptId: ''})} alt=""/>
          <div className="script-table-wrap">
            {verify.scripts.map(item => {
            {scripts.map(item => {
              let title = item.sql.match(/^\s*\/\*.+\*\//)
              title = title && title[0] ? title[0] : ''
              let _text = title ? item.sql.replace(title, '') : item.sql
src/templates/zshare/verifycard/fullScripts/index.scss
@@ -112,10 +112,11 @@
            width: 89.5%;
          }
        }
        .add {
        .add {
          position: absolute;
          top: 10px;
          z-index: 1;
          padding-top: 0px!important;
          .ant-btn {
            height: 28px;
          }
@@ -124,6 +125,13 @@
            margin-right: 10px;
          }
        }
        .forced {
          position: absolute;
          top: 10px;
          z-index: 1;
          text-align: right;
          right: 80px;
        }
      }
    }
  }
src/templates/zshare/verifycard/index.jsx
@@ -42,7 +42,7 @@
    activeKey: 'base',
    appType: sessionStorage.getItem('appType'),
    notes: [],              // 短信模板
    setting: null,
    emailCodes: [],         // 邮箱模板
    verify: {},
    fields: [],
    usefulfields: '',
@@ -540,15 +540,31 @@
    const { appType } = this.state
    let _verify = fromJS(card.verify || {}).toJS()
    let _invalid = _verify.invalid
    let _invalid = _verify.invalid || 'true'
    if (!_invalid) { // 选择行时,失效验证默认开启
      if (config.setting && config.setting.maxScript && config.setting.maxScript >= 300) {
        _invalid = 'false'
      } else {
        _invalid = card.Ot !== 'notRequired' ? 'true' : 'false'
      }
    _verify.limitInvalid = false
    if (config.wrap && config.wrap.datatype === 'public') {
      _verify.limitInvalid = true
      _verify.limitText = '公共数据源,不可使用失效验证'
      _invalid = 'false'
    } else if (config.wrap && config.wrap.datatype === 'static') {
      _verify.limitInvalid = true
      _verify.limitText = '静态数据源,不可使用失效验证'
      _invalid = 'false'
    } else if (config.setting && config.setting.maxScript && config.setting.maxScript >= 300) {
      _verify.limitInvalid = true
      _verify.limitText = '数据源中自定义脚本过于复杂,不能使用失效验证!'
      _invalid = 'false'
    } else if (card.sqlType === 'insert') {
      _verify.limitInvalid = true
      _verify.limitText = '按钮操作类型为《添加》时,不能使用失效验证!'
      _invalid = 'false'
    } else if (card.Ot === 'notRequired') {
      _verify.limitInvalid = true
      _verify.limitText = '按钮《不选择行》时,不能使用失效验证!'
      _invalid = 'false'
    }
    if (card.sqlType === 'custom') { // 自定义验证时,不使用默认sql
      _verify.default = 'false'
    }
@@ -556,9 +572,9 @@
    _verify.default = _verify.default || 'true'
    _verify.wxNote = _verify.wxNote || 'false'           // 公众号消息推送是否开启
    _verify.noteEnable = _verify.noteEnable || 'false'   // 短信发送是否开启
    _verify.emailEnable = _verify.emailEnable || 'false' // 邮件发送是否开启
    _verify.printEnable = _verify.printEnable || 'false' // 单据打印是否开启
    _verify.noteType = _verify.noteType || 'N'           // 短信发送模式:Y(实时)、N(定时)
    _verify.noteTemp = _verify.noteTemp || 'Y'           // 短信发送模板:Y(相同)、N(不同)
    _verify.preHandle = _verify.preHandle || 'false'     // 按钮预处理是否开启
    _verify.invalid = _invalid
    _verify.uniques = _verify.uniques || []
    _verify.contrasts = _verify.contrasts || []
@@ -621,7 +637,6 @@
    this.setState({
      activeKey: activeKey,
      verifyInter: verifyInter,
      setting: config.setting || {},
      verify: _verify,
      oriVerify: fromJS(_verify).toJS()
    })
@@ -1046,7 +1061,12 @@
      {
        obj_name: 'noteCodes',
        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`))
        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 =u.openid`))
      },
      {
        obj_name: 'emailCodes',
        arr_field: 'msn_email_temp_no,remark,id',
        LText: window.btoa(window.encodeURIComponent(`select t.id,t.msn_email_temp_no,t.remark from (select * from bd_msn_email_temp where deleted=0) t inner join (select openid from susers where uid=@userid@) u on t.openid=u.openid`))
      },
      {
        obj_name: 'scripts',
@@ -1087,6 +1107,13 @@
            return {
              name: item.describe,
              value: item.templatecode,
              id: item.id
            }
          }),
          emailCodes: res.emailCodes.map(item => {
            return {
              name: item.remark,
              value: item.msn_email_temp_no,
              id: item.id
            }
          }),
@@ -1424,7 +1451,7 @@
  handleConfirm = () => {
    const { card } = this.props
    const { setting, activeKey } = this.state
    const { activeKey } = this.state
    let verify = fromJS(this.state.verify).toJS()
    if (activeKey === 'base') {
@@ -1446,13 +1473,6 @@
        notification.warning({
          top: 92,
          message: '不执行默认sql时,必须设置自定义脚本!',
          duration: 5
        })
        return
      } else if (verify.invalid === 'true' && setting.maxScript && setting.maxScript >= 300) {
        notification.warning({
          top: 92,
          message: '数据源中自定义脚本过于复杂,不能使用失效验证!',
          duration: 5
        })
        return
@@ -1485,6 +1505,9 @@
          })
        })
      }
      delete verify.limitInvalid
      delete verify.limitText
      if (msg) {
        confirm({
@@ -1549,7 +1572,7 @@
  render() {
    const { card, columns } = this.props
    const { activeKey, verifyInter, setting, verify, fields, uniqueFields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, cbScriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes, appType } = this.state
    const { activeKey, verifyInter, verify, fields, uniqueFields, uniqueColumns, unionFields, onceUniqueColumns, columnsFields, contrastColumns, customColumns, orderColumns, scriptsColumns, cbScriptsColumns, orderModular, orderModularDetail, voucher, voucherDetail, notes, emailCodes, appType } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -1571,7 +1594,7 @@
              {verify.default === 'false' ? <span className="count-tip"><ExclamationOutlined style={{color: 'orange'}}/></span> : null}
            </span>
          } key="base">
            <BaseForm card={card} appType={appType} columns={columns} unionFields={unionFields} setting={setting} verify={verify} notes={notes} onChange={(verify) => this.setState({verify})} wrappedComponentRef={(inst) => this.baseForm = inst}/>
            <BaseForm card={card} appType={appType} columns={columns} unionFields={unionFields} verify={verify} notes={notes} emailCodes={emailCodes} onChange={(verify) => this.setState({verify})} wrappedComponentRef={(inst) => this.baseForm = inst}/>
          </TabPane> : null}
          {verifyInter === 'system' ? <TabPane tab={
            <span>
@@ -1650,7 +1673,7 @@
            </span>
          } key="scripts" id="mk-normal-script">
            <FullScripts
              verify={verify}
              scripts={verify.scripts}
              getScriptsFullForm={() => this.scriptsFullForm}
              getScriptsForm={() => this.scriptsForm}
              handleStatus={this.handleStatus}
@@ -1688,6 +1711,24 @@
              {verify.cbScripts.length ? <span className="count-tip">{verify.cbScripts.length}</span> : null}
            </span>
          } key="cbScripts" id="mk-callback-script">
            <FullScripts
              scripts={verify.cbScripts}
              getScriptsFullForm={() => this.cbscriptsFullForm}
              getScriptsForm={() => this.cbscriptsForm}
              handleStatus={(item) => this.handleStatus(item, 'cbscripts')}
              handleDelete={(item) => this.handleDelete(item, 'cbscripts')}
            >
              <CallBackCustomScript
                type="fullscreen"
                btn={this.props.card}
                initsql={this.state.initsql}
                customScripts={verify.cbScripts}
                usefulfields={this.state.usefulfields}
                systemScripts={this.state.systemScripts}
                scriptsChange={this.cbScriptsChange}
                wrappedComponentRef={(inst) => this.cbscriptsFullForm = inst}
              />
            </FullScripts>
            <CallBackCustomScript
              btn={this.props.card}
              initsql={this.state.initsql}
src/templates/zshare/verifycard/uniqueform/index.jsx
@@ -106,8 +106,8 @@
                ]
              })(
                <Select>
                  <Select.Option value="physical"> 物理验证 </Select.Option>
                  <Select.Option value="logic"> 逻辑验证 </Select.Option>
                  <Select.Option value="physical"> 物理验证 </Select.Option>
                </Select>
              )}
            </Form.Item>
src/utils/option.js
@@ -242,6 +242,13 @@
  class5: [{
    value: 'between',
    text: 'between'
  }],
  class6: [{
    value: 'between',
    text: 'between'
  }, {
    value: '=',
    text: '='
  }]
}
src/utils/utils-custom.js
@@ -6,7 +6,7 @@
   * @description 获取下级模块
   * @return {String}  selfId  当前组件id
   */
  static getSubModules (components, selfId, supId) {
  static getSubModules (components, selfId, supId, has) {
    let modules = []
    components.forEach(item => {
      if (item.uuid === selfId || item.type === 'navbar') {
@@ -17,6 +17,17 @@
          label: item.name,
          disabled: supId === item.uuid
        })
        if (item.type === 'form' && item.subtype === 'simpleform' && item.wrap.refocus && supId !== item.uuid) {
          modules.push({
            value: item.uuid + '$focus-refresh',
            label: item.name + '(刷新-聚焦)',
          })
          modules.push({
            value: item.uuid + '$focus-nofresh',
            label: item.name + '(不刷新-聚焦)',
          })
        }
      } else if (item.type === 'tabs') {
        if (item.subtype === 'tabletabs') {
          item.subtabs.forEach(tab => {
@@ -38,7 +49,7 @@
                type: 'tab',
                value: f_tab.uuid,
                label: f_tab.label,
                children: this.getSubModules(f_tab.components, selfId, supId)
                children: this.getSubModules(f_tab.components, selfId, supId, has)
              }
  
              if (subItem.children.length === 0) {
@@ -672,11 +683,23 @@
    }
    if (btn.syncComponent && btn.syncComponent[0] === 'multiComponent' && btn.syncComponents) {
      btn.syncComponents = btn.syncComponents.map(m => {
        m.syncComId = m.syncComId.map(n => md5(commonId + n))
        m.syncComId = m.syncComId.map(n => {
          if (/\$focus/.test(n)) {
            return md5(commonId + n.split('$')[0]) + '$' + n.split('$')[1]
          }
          return md5(commonId + n)
        })
        return m
      })
    } else if (btn.syncComponent && btn.syncComponent.length > 0) {
      btn.syncComponent = btn.syncComponent.map(m => md5(commonId + m))
      btn.syncComponent = btn.syncComponent.map(m => {
        if (/\$focus/.test(m)) {
          return md5(commonId + m.split('$')[0]) + '$' + m.split('$')[1]
        }
        return md5(commonId + m)
      })
    }
  }
@@ -984,7 +1007,11 @@
      if (item.type === 'date') {
        value = '1949-10-01 00:00:00.000'
      } else if (item.type === 'datemonth') {
        value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
        if (item.match === '=') {
          value = '1949-10'
        } else {
          value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
        }
      } else if (item.type === 'dateweek') {
        value = '1949-10-01 00:00:00.000,1949-10-02 00:00:00.000'
      } else if (item.type === 'daterange') {
@@ -1036,9 +1063,16 @@
      searchText.push(`('${item.value}' ${item.match} '%'+${item.key}+'%')`)
    } else if (item.type === 'date') {
      searchText.push('(' + item.key + ' ' + item.match + ' \'' + item.value + '\')')
    } else if (item.type === 'datemonth' || item.type === 'dateweek' || item.type === 'range') {
    } else if (item.type === 'dateweek' || item.type === 'range') {
      let val = item.value.split(',')
      searchText.push('(' + item.key + ' >= \'' + val[0] + '\' AND ' + item.key + ' < \'' + val[1] + '\')')
    } else if (item.type === 'datemonth') {
      if (item.match === '=') {
        searchText.push('(' + item.key + ' = \'' + item.value + '\')')
      } else {
        let val = item.value.split(',')
        searchText.push('(' + item.key + ' >= \'' + val[0] + '\' AND ' + item.key + ' < \'' + val[1] + '\')')
      }
    } else if (item.type === 'daterange') {
      let val = item.value.split(',')
@@ -1081,7 +1115,8 @@
          value: `'${item.value}'`
        })
      }
    } else if (['dateweek', 'datemonth', 'range'].includes(item.type)) {
    } else if (['dateweek', 'range'].includes(item.type)) {
      let val = item.value.split(',')
      options.push({
        reg: new RegExp('@' + item.key + '@', 'ig'),
@@ -1090,6 +1125,22 @@
        reg: new RegExp('@' + item.key + '1@', 'ig'),
        value: `'${val[1]}'`
      })
    } else if (item.type === 'datemonth') {
      if (item.match === '=') {
        options.push({
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${item.value}'`
        })
      } else {
        let val = item.value.split(',')
        options.push({
          reg: new RegExp('@' + item.key + '@', 'ig'),
          value: `'${val[0]}'`
        }, {
          reg: new RegExp('@' + item.key + '1@', 'ig'),
          value: `'${val[1]}'`
        })
      }
    } else if (item.type === 'daterange') {
      let val = item.value.split(',')
      let _skey = item.key
src/utils/utils-datamanage.js
@@ -204,8 +204,14 @@
        } else {
          DateCount = `/*system_query*/select count(1) as total from ${_dataresource} ${_search}`
        }
      } else if (setting.$top) {
        if (orderBy) {
          LText = `/*system_query*/select top 1 ${arr_field} from ${_dataresource} ${_search} order by ${orderBy} `
        } else {
          LText = `/*system_query*/select top 1 ${arr_field} from ${_dataresource} ${_search}  `
        }
      } else if (orderBy) {
        LText = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${orderBy}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
        LText = `/*system_query*/select ${arr_field} from ${_dataresource} ${_search} order by ${orderBy} `
      } else {
        LText = `/*system_query*/select ${arr_field} from ${_dataresource} ${_search}  `
      }
@@ -458,8 +464,14 @@
    _search = _search ? 'where ' + _search : ''
  }
  if (setting.order && _dataresource) {
    _dataresource = `select top 1000 ${setting.arr_field} from (select ${setting.arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows `
  if (setting.$top) {
    if (setting.order && _dataresource) {
      _dataresource = `select top 1 ${setting.arr_field} from ${_dataresource} ${_search} order by ${setting.order} `
    } else if (_dataresource) {
      _dataresource = `select top 1 ${setting.arr_field} from ${_dataresource} ${_search} `
    }
  } else if (setting.order && _dataresource) {
    _dataresource = `select top 1000 ${setting.arr_field} from ${_dataresource} ${_search} order by ${setting.order} `
  } else if (_dataresource) {
    _dataresource = `select top 1000 ${setting.arr_field} from ${_dataresource} ${_search} `
  }
src/utils/utils.js
@@ -348,6 +348,9 @@
          item.initval = ''
          item.initType = ''
        }
      } else if ((item.type === 'select' || item.type === 'link') && item.initval === '$first' && item.resourceType === '1') {
        item.initval = ''
        item.$first = true
      }
      
      item.oriInitval = item.initval
@@ -469,17 +472,21 @@
          newsearches[item.key] = _val
        }
      } else if (item.type === 'datemonth') {
        // 月-过滤条件,从月开始至结束
        let _startval = ''
        let _endval = ''
        if (item.value) {
          _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
          _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
        if (item.match === '=') {
          newsearches[item.key] = item.value
        } else {
          // 月-过滤条件,从月开始至结束
          let _startval = ''
          let _endval = ''
          if (item.value) {
            _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
            _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
          }
          newsearches[item.key] = _startval
          newsearches[item.key + '1'] = _endval
        }
        newsearches[item.key] = _startval
        newsearches[item.key + '1'] = _endval
      } else if (item.type === 'dateweek') {
        let _startval = ''
        let _endval = ''
@@ -583,10 +590,14 @@
        searchText.push('(' + item.key + ' ' + _match + ' \'' + _val + timetail + '\')')
      } else if (item.type === 'datemonth') { // 月-过滤条件,从月开始至结束,结束时间为月末加一天的0点,方式为<
        let _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
        let _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
        searchText.push('(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')')
        if (item.match === '=') {
          searchText.push('(' + item.key + ' = \'' + item.value + '\')')
        } else {
          let _startval = moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000'
          let _endval = moment(item.value, 'YYYY-MM').endOf('month').add(1, 'days').format('YYYY-MM-DD') + ' 00:00:00.000'
          searchText.push('(' + item.key + ' >= \'' + _startval + '\' AND ' + item.key + ' < \'' + _endval + '\')')
        }
      } else if (item.type === 'dateweek') { // 周-过滤条件
        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'
@@ -679,17 +690,21 @@
        options.push(item)
      } else if (item.type === 'datemonth') {
        let _startval = item.value ? moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000' : '1970-01-01 00:00:00.000'
        let _endval = item.value ? moment(item.value, 'YYYY-MM').endOf('month').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'
        copy.value = _endval
        item.value = _startval
        options.push(item)
        options.push(copy)
        if (item.match === '=') {
          options.push(item)
        } else {
          let _startval = item.value ? moment(item.value, 'YYYY-MM').startOf('month').format('YYYY-MM-DD') + ' 00:00:00.000' : '1970-01-01 00:00:00.000'
          let _endval = item.value ? moment(item.value, 'YYYY-MM').endOf('month').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'
          copy.value = _endval
          item.value = _startval
          options.push(item)
          options.push(copy)
        }
      } else if (item.type === 'dateweek') {
        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'
@@ -1103,10 +1118,19 @@
    let _insert = ''
    if (btn.default !== 'false') {
      let _fields = []
      btn.columns.forEach(col => {
        if (col.import === 'false' || col.import === 'init') return
        _fields.push(col.Column)
      })
      _fields = _fields.join(',')
      _insert = `
      /* 默认sql */
      Insert into ${database}${sheet} (${fields},createuserid,createuser,createstaff,bid)
      Select ${fields},'${sessionStorage.getItem('UserID') || ''}',@username,@fullname,'${BID}' From #${sheet}
      Insert into ${database}${sheet} (${_fields},createuserid,createuser,createstaff,bid)
      Select ${_fields},'${sessionStorage.getItem('UserID') || ''}',@username,@fullname,'${BID}' From #${sheet}
      `
    }
@@ -1372,7 +1396,7 @@
 * @return {Array}   columns   显示列
 * @return {Boolean} retmsg    是否需要数据返回
 */
export function getSysDefaultSql (btn, setting, formdata, param, data, columns, retmsg = false, moduleParams, getOptions) {
export function getSysDefaultSql (btn, setting, formdata, param, data, columns, retmsg = false, moduleParams) {
  let primaryId = param.ID
  let BID = param.BID || ''
  let verify = btn.verify || {}
@@ -1622,47 +1646,9 @@
  }
  // 失效验证,添加数据时不用
  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 (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('@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 (verify.invalid === 'true' && moduleParams && moduleParams.dataresource) {
    let datasource = moduleParams.dataresource
    let customScript = moduleParams.customScript || ''
    if (customScript) {
      _sql += `
@@ -1872,7 +1858,7 @@
  let hasvoucher = false
  // 凭证-显示列中选取,必须选行
  if (verify.voucher && verify.voucher.enabled && data) {
  if (verify.voucher && verify.voucher.enabled) {
    let _voucher = verify.voucher
    hasvoucher = true
@@ -1880,7 +1866,7 @@
    _sql += `
      /* 创建凭证 */
      exec s_BVoucher_Create
        @Bill ='${_data[_voucher.linkField.toLowerCase()]}',
        @Bill ='${_data[_voucher.linkField.toLowerCase()] || ''}',
        @BVoucherType ='${_voucher.BVoucherType}',
        @VoucherTypeOne ='${_voucher.VoucherTypeOne}',
        @VoucherTypeTwo ='${_voucher.VoucherTypeTwo}',
src/views/billprint/index.jsx
@@ -395,6 +395,10 @@
                } else {
                  item.IsSort = 'false'
                }
                if (item.marks && item.marks.length === 0) {
                  item.marks = null
                }
          
                return true
              })
@@ -461,6 +465,11 @@
          if (!component.format) return component  // 没有动态数据  数据格式 array 或 object
          component.setting.arr_field = component.columns ? component.columns.map(col => col.field).join(',') : ''
          component.setting.laypage = false   // 是否分页,转为boolean 统一格式
          if (component.format === 'object') {
            component.setting.$top = true
          }
          if (component.setting.interType !== 'system') { // 不使用系统函数时
            component.setting.sync = 'false'
@@ -484,7 +493,6 @@
          delete component.scripts
    
          component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
          component.setting.laypage = false   // 是否分页,转为boolean 统一格式
          component.setting.onload = 'true'   // 默认加载
    
          if (!component.setting.execute) {
@@ -610,6 +618,10 @@
    if (cell.style.display === 'inline-block') {
      cell.style.verticalAlign = 'top'
    }
    if (cell.marks && cell.marks.length === 0) {
      cell.marks = null
    }
    
    if (['text', 'number', 'formula'].includes(cell.eleType)) {
      cell.innerHeight = cell.innerHeight || 'auto'
@@ -673,7 +685,8 @@
      inter.setting.$name = '公共数据源-' + inter.setting.name
      inter.setting.execute = inter.setting.execute !== 'false'
      inter.setting.laypage = true
      inter.setting.laypage = false
      inter.setting.$top = true
      if (!inter.setting.execute) {
        inter.setting.dataresource = ''
src/views/design/header/index.jsx
@@ -141,6 +141,7 @@
                EasyCode: trd.EasyCode,
                type: 'CommonTable',            // 默认值为常用表
                OpenType: 'newtab',             // 打开方式
                up_action: window.GLOB.upStatus && trd.up_action === 'Y',
                level: 'third'
              }
  
src/views/design/sidemenu/index.jsx
@@ -326,7 +326,7 @@
                {item.children.map(cell => {
                  return (
                    <Menu.Item key={cell.MenuID}>
                      <span className="editable-menu-item" onDoubleClick={() => this.editmenu(cell)}>{cell.PageParam && cell.PageParam.interfaces === 'true' ? <ApiOutlined title="菜单中使用了外部接口" /> : null}{cell.MenuName}</span>
                      <span className={'editable-menu-item ' + (cell.up_action ? 'unupdate' : '')} onDoubleClick={() => this.editmenu(cell)}>{cell.PageParam && cell.PageParam.interfaces === 'true' ? <ApiOutlined title="菜单中使用了外部接口" /> : null}{cell.MenuName}</span>
                    </Menu.Item>
                  )
                })}
src/views/design/sidemenu/index.scss
@@ -24,6 +24,10 @@
        color: orange;
      }
    }
    .editable-menu-item.unupdate {
      color: orange;
    }
  }
  .ant-menu-sub.ant-menu-inline {
    position: relative;
src/views/interface/history/index.jsx
@@ -260,18 +260,18 @@
          ))}
          <div className="list-line" key="example">
            <div className="line-title">示例</div>
              <div className="line-item" key="dologon">
              <div className="line-item" style={{cursor: 'pointer'}} key="dologon" onClick={this.uselogon}>
                <div className="method">POST</div>
                <div className="inter" style={{lineHeight: '40px'}}>dologon</div>
                <div className="action" style={{paddingLeft: '40px'}}>
                  <RightOutlined onClick={this.uselogon} />
                  <RightOutlined/>
                </div>
              </div>
              <div className="line-item" key="dostars">
              <div className="line-item" style={{cursor: 'pointer'}} key="dostars" onClick={this.usedostars}>
                <div className="method">POST</div>
                <div className="inter" style={{lineHeight: '40px'}}>dostars</div>
                <div className="action" style={{paddingLeft: '40px'}}>
                  <RightOutlined onClick={this.usedostars} />
                  <RightOutlined/>
                </div>
              </div>
          </div>
src/views/login/index.jsx
@@ -1009,7 +1009,7 @@
              <a target="_blank" rel="noopener noreferrer" href={webSite} dangerouslySetInnerHTML={{ __html: copyRight.replace(/\s/ig, '&nbsp;') }}></a> :
              <p dangerouslySetInnerHTML={{ __html: copyRight ? copyRight.replace(/\s/ig, '&nbsp;') : '' }}></p>
            }
            {ICP ? <p dangerouslySetInnerHTML={{ __html: ICP.replace(/\s/ig, '&nbsp;') }}></p> : null}
            {ICP ? <a target="_blank" rel="noopener noreferrer" href="https://beian.miit.gov.cn/#/Integrated/index" dangerouslySetInnerHTML={{ __html: ICP.replace(/\s/ig, '&nbsp;') }}></a> : null}
          </div>
        </div>
        {/* 编辑状态登录 */}
src/views/login/index.scss
@@ -255,7 +255,7 @@
      margin-right: 15px;
    }
    a {
      display: inline-block;
      display: block;
      margin-bottom: 5px;
      color: var(--mk-sys-font-color);
    }
src/views/menudesign/index.jsx
@@ -749,6 +749,10 @@
        config.components = this.resetSyncQuery(config.components)
      }
      if (config.MenuID === 'home_page_id') {
        config.permission = 'false'
      }
      let tbs = []
      let btns = this.getMenuMessage(config, tbs)
      let arr = []
@@ -908,10 +912,10 @@
            duration: 2
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          Modal.warning({
            width: 400,
            title: res.message,
            okText: '知道了'
          })
        }
        MKEmitter.emit('completeSave')
@@ -1104,6 +1108,27 @@
    }, 400)
  }
  checklog = () => {
    const { oriConfig, config } = this.state
    return is(fromJS(oriConfig), fromJS(config))
  }
  updateLogConfig = (config) => {
    config.fstMenuId = this.state.config.fstMenuId || config.fstMenuId || ''
    config.parentId = this.state.config.parentId || config.parentId || ''
    this.setState({
      config: null
    }, () => {
      this.setState({
        config: config
      })
    })
    window.GLOB.customMenu = config
  }
  render () {
    const { view, comloading, MenuType, MenuId, config, settingshow, ParentId, menuloading, eyeopen, needUpdate } = this.state
@@ -1164,7 +1189,7 @@
                  <div className="mk-opeartion-list">
                    {config ? <Debug config={config}/> : null}
                    <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                    <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                    {config ? <Versions MenuId={MenuId} Template="CustomPage" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
                    <TableNodes config={config} />
                    <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                    <SysInterface config={config} updateConfig={this.updateConfig}/>
src/views/menudesign/menuform/index.jsx
@@ -50,6 +50,7 @@
    thdMenuList = JSON.parse(thdMenuList)
    let thdMenu = null
    let firstId = ''
    thdMenuList.forEach(trd => {
      if (MenuId === trd.MenuID) {
@@ -65,17 +66,21 @@
          smenulist = item.children
        }
      })
      firstId = thdMenu.FstId || ''
    }
    this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
    if (firstId !== config.fstMenuId) {
      this.props.updateConfig({...config, fstMenuId: firstId})
    }
    this.setState({
      fstMenuId: thdMenu ? thdMenu.FstId : '',
      fstMenuId: firstId,
      menulist,
      smenulist
    }, () => {
      this.props.form.setFieldsValue({
        fstMenuId: thdMenu ? thdMenu.FstId : '',
        fstMenuId: firstId,
        parentId: thdMenu ? thdMenu.ParentId : ''
      })
    })
@@ -149,24 +154,29 @@
        })
        let smenulist = []
        let firstId = ''
        if (thdMenu) {
          menulist.forEach(item => {
            if (item.MenuID === thdMenu.FstId) {
              smenulist = item.children
            }
          })
          firstId = thdMenu.FstId || ''
        }
        sessionStorage.setItem('fstMenuList', JSON.stringify(menulist))
        sessionStorage.setItem('thdMenuList', JSON.stringify(thdMenuList))
        this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
        if (firstId !== config.fstMenuId) {
          this.props.updateConfig({...config, fstMenuId: firstId})
        }
        this.setState({
          fstMenuId: thdMenu ? thdMenu.FstId : '',
          fstMenuId: firstId,
          menulist,
          smenulist
        }, () => {
          this.props.form.setFieldsValue({
            fstMenuId: thdMenu ? thdMenu.FstId : '',
            fstMenuId: firstId,
            parentId: thdMenu ? thdMenu.ParentId : ''
          })
        })
src/views/mobdesign/index.jsx
@@ -568,6 +568,7 @@
        
        config.uuid = MenuId
        config.MenuID = MenuId
        config.Template = 'webPage'
        config.open_edition = result.open_edition || ''
        config.direction = config.direction || sessionStorage.getItem('direction') || 'vertical'
        window.GLOB.urlFields = config.urlFields || []
@@ -686,6 +687,7 @@
    
    config.uuid = MenuId
    config.MenuID = MenuId
    config.Template = 'webPage'
    config.open_edition = result.open_edition || ''
    this.setState({
@@ -825,6 +827,7 @@
      config.uuid = MenuId
      config.MenuID = MenuId
      config.open_edition = ''
      config.Template = 'webPage'
      config.MenuName = urlParam.MenuName || ''
      // config.MenuNo = urlParam.MenuNo || ''
      config.MenuNo = ''
@@ -1688,10 +1691,10 @@
            duration: 2
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          Modal.warning({
            width: 400,
            title: res.message,
            okText: '知道了'
          })
        }
        MKEmitter.emit('completeSave')
@@ -2055,6 +2058,24 @@
    window.GLOB.customMenu = config
  }
  checklog = () => {
    const { oriConfig, config } = this.state
    return is(fromJS(oriConfig), fromJS(config))
  }
  updateLogConfig = (config) => {
    this.setState({
      config: null
    }, () => {
      this.setState({
        config: config
      })
    })
    window.GLOB.customMenu = config
  }
  render () {
    const { view, viewType, comloading, loading, settingshow, controlshow, activeKey, MenuId, config, menuloading, adapters, eyeopen, needUpdate } = this.state
@@ -2130,7 +2151,7 @@
                <Button className="mk-border-purple set-login" onClick={this.setLoginView}><LoginOutlined /> 设为登录页</Button>
                <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                <Transfer MenuID={MenuId} />
                <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                {config ? <Versions MenuId={MenuId} Template="webPage" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
                <Button type="default" onClick={this.closeView}>关闭</Button>
              </div>
            </div>
src/views/pcdesign/index.jsx
@@ -531,6 +531,7 @@
        config.uuid = MenuId
        config.MenuID = MenuId
        config.Template = 'webPage'
        config.open_edition = result.open_edition || ''
        window.GLOB.urlFields = config.urlFields || []
@@ -737,6 +738,7 @@
      
      config.uuid = MenuId
      config.MenuID = MenuId
      config.Template = 'webPage'
      config.open_edition = ''
      config.MenuName = urlParam.MenuName || ''
      config.MenuNo = ''
@@ -1405,10 +1407,10 @@
            duration: 2
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          Modal.warning({
            width: 400,
            title: res.message,
            okText: '知道了'
          })
        }
        MKEmitter.emit('completeSave')
@@ -1676,6 +1678,24 @@
    })
  }
  checklog = () => {
    const { oriConfig, config } = this.state
    return is(fromJS(oriConfig), fromJS(config))
  }
  updateLogConfig = (config) => {
    this.setState({
      config: null
    }, () => {
      this.setState({
        config: config
      })
    })
    window.GLOB.customMenu = config
  }
  render () {
    const { view, loading, comloading, activeKey, settingshow, controlshow, MenuId, config, menuloading, eyeopen, needUpdate } = this.state
@@ -1742,7 +1762,7 @@
                <Button className="mk-border-purple" onClick={this.setLoginView}><LoginOutlined/> 设为登录页</Button>
                <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                <Transfer MenuID={MenuId} />
                <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                {config ? <Versions MenuId={MenuId} Template="webPage" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
                <Button type="default" onClick={this.closeView}>关闭</Button>
              </div>
            </div>
src/views/rolemanage/index.jsx
@@ -23,6 +23,7 @@
    app: null,
    loading: false,
    menulist: [],
    sortType: '',
    columns: [
      {
        title: '菜单名称', dataIndex: 'MenuName', key: 'MenuName', align: 'center', render: (text, record) => {
@@ -38,11 +39,19 @@
        title: '菜单参数', dataIndex: 'MenuNo', key: 'MenuNo', align: 'center'
      },
      {
        title: '修改时间', dataIndex: 'modifydate', key: 'modifydate', align: 'center', sorter: true, render: (text, record) => {
          if (window.GLOB.upStatus && record.up_action === 'Y') {
            return <span style={{color: 'orange'}}>{text}</span>
          }
          return text
        }
      },
      {
        title: '操作',
        key: 'action',
        align: 'center',
        render: (text, record) => (
          <div>
          <div style={{minWidth: '125px'}}>
            {record.type !== 'none' ?
              <Button type="link" onClick={() => this.deleteMenu(record)} style={{color: '#ff4d4f'}}>删除</Button> :
              <Button type="link" onClick={() => {
@@ -878,12 +887,30 @@
    window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify({...app, MenuID: item.MenuID, type: 'app'})))}`))
  }
  changeTable = (pagination, filters, sorter) => {
    this.setState({sortType: sorter.order || ''})
  }
  render () {
    const { app, loading, columns, menulist, trees, searchkey } = this.state
    let _menulist = menulist
    const { app, loading, columns, menulist, trees, searchkey, sortType } = this.state
    let _menulist = fromJS(menulist).toJS()
    if (searchkey) {
      _menulist = _menulist.filter(item => item.MenuName.toLowerCase().indexOf(searchkey.toLowerCase()) > -1)
    }
    if (sortType === 'ascend') {
      _menulist.sort((a, b) => {
        if (a.modifydate > b.modifydate) return 1
        if (a.modifydate < b.modifydate) return -1
        return 0
      })
    } else if (sortType === 'descend') {
      _menulist.sort((a, b) => {
        if (a.modifydate < b.modifydate) return 1
        if (a.modifydate > b.modifydate) return -1
        return 0
      })
    }
    return (
@@ -907,6 +934,7 @@
                  columns={columns}
                  dataSource={_menulist}
                  pagination={false}
                  onChange={this.changeTable}
                />
              </div>
            </div>
src/views/rolemanage/index.scss
@@ -68,8 +68,8 @@
      border-radius: 4px;
    }
    .ant-table-tbody {
      > tr.ant-table-row-selected td {
        background: #bae7ff;
      td:nth-child(1), td:nth-child(2) {
        word-break: break-all;
      }
    }
  }
src/views/tabledesign/index.jsx
@@ -651,10 +651,10 @@
            duration: 2
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          Modal.warning({
            width: 400,
            title: res.message,
            okText: '知道了'
          })
        }
        MKEmitter.emit('completeSave')
@@ -818,6 +818,27 @@
    sessionStorage.setItem('settingshow', '' + !this.state.settingshow)
  }
  checklog = () => {
    const { oriConfig, config } = this.state
    return is(fromJS(oriConfig), fromJS(config))
  }
  updateLogConfig = (config) => {
    config.fstMenuId = this.state.config.fstMenuId || config.fstMenuId || ''
    config.parentId = this.state.config.parentId || config.parentId || ''
    this.setState({
      config: null
    }, () => {
      this.setState({
        config: config
      })
    })
    window.GLOB.customMenu = config
  }
  render () {
    const { view, activeKey, comloading, MenuId, config, settingshow, ParentId, menuloading } = this.state
@@ -875,7 +896,7 @@
                    {config ? <Debug config={config}/> : null}
                    {config ? <Transfer config={config}/> : null}
                    {config ? <Unattended config={config} updateConfig={this.updateConfig}/> : null}
                    <Versions MenuId={MenuId} open_edition={config ? config.open_edition : ''}/>
                    {config ? <Versions MenuId={MenuId} Template="BaseTable" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
                    <TableNodes config={config} />
                    <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                    <PasteBaseTable type="page" insert={this.insert}/>