king
2023-01-17 d5ce81026882ada34e5d49411be7c90ee96cc102
2023-01-17
237个文件已修改
14个文件已添加
8653 ■■■■ 已修改文件
package-lock.json 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/cacheutils.js 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/viewstyle.scss 375 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/account.png 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/voucher.png 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.scss 53 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/resetpwd/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/keyInterface/index.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/keyInterface/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/mk-icon/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/styleInput/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/styleInput/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.scss 50 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/action.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/elementform/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/options.jsx 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardsimplecomponent/index.jsx 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardsimplecomponent/index.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/options.jsx 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/prop-card/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/table-card/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/carousel/data-card/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/carousel/data-card/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/carousel/prop-card/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-G6/chartcompile/formconfig.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-G6/index.jsx 105 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/code/sandbox/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.scss 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.scss 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.scss 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/group/normal-group/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/group/paste/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/iframe/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/iframe/options.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/account/index.jsx 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/account/index.scss 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/account/options.jsx 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/index.jsx 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/index.scss 97 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/options.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/voucherTable/index.jsx 361 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/voucher/voucherTable/index.scss 259 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/options.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 79 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/markcomponent/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/searchcomponent/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/index.jsx 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/options.jsx 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/options.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/options.jsx 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/paste/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/timeline/normal-timeline/index.scss 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/timeline/normal-timeline/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tree/antd-tree/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tree/antd-tree/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/card.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulecell/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulesource/option.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/pastecontroller/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/tablenodes/index.jsx 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/tablenodes/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/colorsketch/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/menubar/common-menubar/index.scss 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/menubar/normal-menubar/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/menubar/normal-menubar/options.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/index.scss 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/options.jsx 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/sharecode/options.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/tabs/antv-tabs/options.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/header/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modulesource/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/index.scss 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/loginform.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/options.jsx 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/login/normal-login/signform.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/index.scss 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/options.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/balcony/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardItem/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.scss 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/prop-card/index.jsx 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/prop-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/carousel/data-card/index.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/carousel/prop-card/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/carousel/prop-card/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-G6/index.jsx 224 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-dashboard/index.jsx 150 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-pie/index.jsx 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-scatter/index.jsx 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/custom-chart/index.jsx 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/code/sand-box/index.jsx 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/group/normal-group/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/iframe/index.jsx 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/iframe/index.scss 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/account/index.jsx 148 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/account/index.scss 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/assistTable/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/index.jsx 127 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/index.scss 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/voucherTable/index.jsx 149 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/voucher/voucherTable/index.scss 119 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.scss 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/tabtransfer/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.jsx 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/base-table/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.jsx 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/normal-table/index.scss 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/timeline/normal-timeline/index.jsx 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/timeline/normal-timeline/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/tree/antd-tree/index.jsx 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 38 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/changeuserbutton/index.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/excelInbutton/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/index.jsx 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/index.scss 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 620 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/cardcomponent/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkCheckCard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkColor/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/tablenodes/index.jsx 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/tablenodes/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/index.jsx 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/updatetable/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/checkCard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/actionform/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx 190 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx 558 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/index.scss 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx 77 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/settingform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/createinterface/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editcomponent/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/datatable/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-datamanage.js 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appcheck/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/submutilform/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.scss 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/homeform/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/menuform/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/popview/menuform/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 182 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/menuform/index.jsx 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/index.jsx 306 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/menuform/index.jsx 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/menuform/index.jsx 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sso/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/index.scss 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/sidemenu/config.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/proc/index.jsx 363 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/proc/index.scss 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -19343,6 +19343,52 @@
      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
    },
    "sheetjs-style": {
      "version": "0.15.8",
      "resolved": "https://registry.npmjs.org/sheetjs-style/-/sheetjs-style-0.15.8.tgz",
      "integrity": "sha512-/wRiwnq5ck7aO+zLBs+u5JqQK4agUTIGCS0nxgaMjFl6XdlVaaB/RNJcP6S6Efj3+RYbSZuAoyqmSnbzxfT7Kg==",
      "requires": {
        "adler-32": "~1.2.0",
        "cfb": "^1.1.4",
        "codepage": "~1.14.0",
        "commander": "~2.17.1",
        "crc-32": "~1.2.0",
        "exit-on-epipe": "~1.0.1",
        "ssf": "~0.10.3",
        "wmf": "~1.0.1"
      },
      "dependencies": {
        "cfb": {
          "version": "1.2.2",
          "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
          "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
          "requires": {
            "adler-32": "~1.3.0",
            "crc-32": "~1.2.0"
          },
          "dependencies": {
            "adler-32": {
              "version": "1.3.1",
              "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
              "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A=="
            }
          }
        },
        "commander": {
          "version": "2.17.1",
          "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
          "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
        },
        "ssf": {
          "version": "0.10.3",
          "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.10.3.tgz",
          "integrity": "sha512-pRuUdW0WwyB2doSqqjWyzwCD6PkfxpHAHdZp39K3dp/Hq7f+xfMwNAWIi16DyrRg4gg9c/RvLYkJTSawTPTm1w==",
          "requires": {
            "frac": "~1.1.2"
          }
        }
      }
    },
    "shell-quote": {
      "version": "1.6.1",
      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
@@ -21720,6 +21766,11 @@
        "string-width": "^1.0.2 || 2 || 3 || 4"
      }
    },
    "wmf": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz",
      "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw=="
    },
    "wolfy87-eventemitter": {
      "version": "5.2.9",
      "resolved": "https://registry.npmjs.org/wolfy87-eventemitter/-/wolfy87-eventemitter-5.2.9.tgz",
package.json
@@ -95,6 +95,7 @@
    "resolve-url-loader": "3.1.0",
    "sass-loader": "7.2.0",
    "semver": "6.3.0",
    "sheetjs-style": "^0.15.8",
    "spark-md5": "^3.0.1",
    "sql-formatter": "^11.0.2",
    "style-loader": "1.0.0",
src/api/cacheutils.js
@@ -22,6 +22,13 @@
          throw 'CREATE TABLE ERROR'
        })
        tx.executeSql('CREATE TABLE IF NOT EXISTS CACHES (menuid varchar(50), CreateDate varchar(50), LongParam text, CDefine1 varchar(50), CDefine2 varchar(50))', [], () => {
        }, () => {
          // eslint-disable-next-line
          throw 'CREATE TABLE ERROR'
        })
        if (window.GLOB.systemType === '') {
          tx.executeSql('CREATE TABLE IF NOT EXISTS FUNCS (func_code varchar(50), key_sql text, CDefine1 varchar(50), CDefine2 varchar(50), CDefine3 varchar(50))', [], () => {
@@ -217,11 +224,55 @@
  }
  /**
   * @description 将缓存数据写入websql
   */
  static writeCacheInWebSql (data) {
    if (!window.GLOB.WebSql) return
    window.GLOB.WebSql.transaction(tx => {
      tx.executeSql(`DELETE FROM CACHES where menuid='${data[0]}'`)
      if (data[2]) {
        tx.executeSql('INSERT INTO CACHES (menuid, CreateDate, LongParam) VALUES (?, ?, ?)', data)
      }
    })
  }
  /**
   * @description 获取websql中的配置信息
   */
  static getWebSqlCacheConfig (MenuID) {
    if (!window.GLOB.WebSql) return Promise.resolve()
    return new Promise((resolve, reject) => {
      window.GLOB.WebSql.transaction(tx => {
        tx.executeSql(`SELECT * FROM CACHES WHERE menuid='${MenuID}'`, [], (tx, results) => {
          resolve(results.rows[0])
        }, (tx, results) => {
          console.warn(results)
          resolve()
        })
      })
    })
  }
  /**
   * @description 删除websql中超过7天的缓存信息
   */
  static delWebSqlCacheConfig (date, type) {
    if (!window.GLOB.WebSql) return
    window.GLOB.WebSql.transaction(tx => {
      if (type === 'all') {
        tx.executeSql('DELETE FROM CACHES')
      } else {
        tx.executeSql(`DELETE FROM CACHES where CreateDate<'${date}'`)
      }
    })
  }
  /**
   * @description 打开IndexedDB
   */
  static openIndexDB (db) {
    try {
      let request = window.indexedDB.open(db, 1)
      let request = window.indexedDB.open(db, 2)
      request.onerror = () => {
        console.warn('IndexedDB 初始化失败!')
      }
@@ -237,6 +288,9 @@
          let objectStore = window.GLOB.IndexDB.createObjectStore('configs', { keyPath: 'id' })
          objectStore.createIndex('menuid', 'menuid', { unique: false })
          objectStore.createIndex('userid', 'userid', { unique: false })
        }
        if (!window.GLOB.IndexDB.objectStoreNames.contains('caches')) {
          window.GLOB.IndexDB.createObjectStore('caches', { keyPath: 'menuid' })
        }
        if (window.GLOB.systemType === '' && !window.GLOB.IndexDB.objectStoreNames.contains('funcs')) {
          window.GLOB.IndexDB.createObjectStore('funcs', { keyPath: 'id' })
@@ -440,12 +494,62 @@
  static writeInIndexDB (data) {
    if (!window.GLOB.IndexDB || !data) return
    let request = window.GLOB.IndexDB.transaction(['configs'], 'readwrite')
      .objectStore('configs')
      .add(data)
    window.GLOB.IndexDB.transaction(['configs'], 'readwrite').objectStore('configs').add(data)
  }
    request.onerror = () => {
      window.GLOB.IndexDB = null
  /**
   * @description 将数据写入IndexedDB
   */
  static writeCacheInIndexDB (data) {
    if (!window.GLOB.IndexDB) return
    let objectStore = window.GLOB.IndexDB.transaction(['caches'], 'readwrite').objectStore('caches')
    objectStore.delete(data.menuid)
    if (data.LongParam) {
      objectStore.add(data)
    }
  }
  /**
   * @description 获取IndexedDB中的配置信息
   */
  static getIndexDBCacheConfig (MenuID) {
    if (!window.GLOB.IndexDB) return Promise.resolve()
    return new Promise((resolve, reject) => {
      let request = window.GLOB.IndexDB.transaction(['caches']).objectStore('caches').get(MenuID)
      request.onerror = () => {
        resolve()
      }
      request.onsuccess = () => {
        resolve(request.result)
      }
    })
  }
  /**
   * @description 删除IndexedDB中超过7天的缓存信息
   */
  static delIndexDBCacheConfig (date, type) {
    if (!window.GLOB.IndexDB) return
    if (type === 'all') {
      window.GLOB.IndexDB.transaction(['caches'], 'readwrite').objectStore('caches').clear()
    } else {
      let request = window.GLOB.IndexDB.transaction(['caches'], 'readwrite').objectStore('caches').openCursor()
      request.onsuccess = (e) => {
        let cursor = e.target.result
        if (cursor) {
          if (cursor.value.CreateDate < date) {
            cursor.delete()
          }
          cursor.continue()
        }
      }
    }
  }
}
src/api/index.js
@@ -12,7 +12,7 @@
window.GLOB.WebSql = null
window.GLOB.IndexDB = null
window.GLOB.OuterToken = {}
const systemMenuKeys = `1581067625930haged11ieaivpavv77k,1581734956310scks442ul2d955g9tu5,1583991994144ndddg0bhh0is6shi0v1,1583979633842550imkchl4qt4qppsiv,1578900109100np8aqd0a77q3na46oas,
const systemMenuKeys = `1581067625930haged11ieaivpavv77k,1581734956310scks442ul2d955g9tu5,1583991994144ndddg0bhh0is6shi0v1,1583979633842550imkchl4qt4qppsiv,
  1585192949946f3et2ts8tn82krmumdf,15855615451212m12ip23vpcm79kloro,1587005717541lov40vg61q7l1rbveon,1590458676585agbbr63t6ihighg2i1g,1602315375262ikd33ii0nii34pt861o,1582771068837vsv54a089lgp45migbg,
  1582777675954ifu05upurs465omoth7,158294809668898cklbv6c5bou8e1fpu,1584676379094iktph45fb8imhg96bql,1584695125339vo5g7iqgfn01qmrd6s2,1584699661372vhmpp9dn9foo0eob722,15848421131551gg04ie8sitsd3f7467,
  1589782279158ngr675kk3oksin35sul,1589788042787ffdt9hle4s45k9r1nvs,1594095599055qicg2eb642v5qglhnuo,1577972969199lei1g0qkvlh4tkc908m,16044812935562g807p3p12huk8kokmb,
@@ -298,7 +298,7 @@
  /**
   * @description 手机号验证码登录
   */
  getphoneusermsg (phoneNo, checkcode, isCloud = false, ipAddress, city) {
  getphoneusermsg (phoneNo, checkcode, isCloud = false) {
    let param = {
      // func: 'webapi_login',
      mob: phoneNo,
@@ -307,8 +307,8 @@
      check_code: checkcode,
      way_no: 'sms_vcode',
      systemType: options.sysType,
      login_city: city,
      login_id_address: ipAddress,
      login_city: sessionStorage.getItem('city') || '',
      login_id_address: sessionStorage.getItem('ipAddress') || '',
      kei_id: window.btoa(window.encodeURIComponent(window.GLOB.host)),
      device_id: localStorage.getItem('SessionUid'),
      appkey: window.GLOB.appkey || ''
@@ -337,14 +337,14 @@
  /**
   * @description 登录系统, 获取用户信息
   */
  getusermsg (username, password, isCloud = false, ipAddress, city) {
  getusermsg (username, password, isCloud = false) {
    let param = {
      // func: 'webapi_login',
      UserName: username,
      systemType: options.sysType,
      Type: 'S',
      login_city: city,
      login_id_address: ipAddress,
      login_city: sessionStorage.getItem('city') || '',
      login_id_address: sessionStorage.getItem('ipAddress') || '',
      kei_id: window.btoa(window.encodeURIComponent(window.GLOB.host)),
      device_id: localStorage.getItem('SessionUid'),
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
@@ -400,6 +400,55 @@
    })
  }
  delCacheConfig (type = '') {
    let date = moment().subtract(7, 'days').format('YYYY-MM-DD')
    CacheUtils.delWebSqlCacheConfig(date, type)
    CacheUtils.delIndexDBCacheConfig(date, type)
  }
  writeCacheConfig (menuid, data) {
    if (!menuid) return
    let date = moment().format('YYYY-MM-DD')
    let _data = data ? JSON.stringify(data) : ''
    CacheUtils.writeCacheInWebSql([menuid, date, _data])
    CacheUtils.writeCacheInIndexDB({menuid, CreateDate: date, LongParam: _data})
  }
  getLCacheConfig (menuid) {
    return new Promise((resolve, reject) => {
      if (window.GLOB.WebSql) {
        CacheUtils.getWebSqlCacheConfig(menuid).then(res => {
          if (res && res.LongParam) {
            let _data = JSON.parse(res.LongParam)
            if (_data.length === 0) {
              resolve()
            } else {
              resolve(_data)
            }
          } else {
            resolve()
          }
        })
      } else if (window.GLOB.IndexDB) {
        CacheUtils.getIndexDBCacheConfig(menuid).then(res => {
          if (res && res.LongParam) {
            let _data = JSON.parse(res.LongParam)
            if (_data.length === 0) {
              resolve()
            } else {
              resolve(_data)
            }
          } else {
            resolve()
          }
        })
      } else {
        resolve()
      }
    })
  }
  /**
   * @description 登录二次验证 // positecgroup
   */
src/assets/css/main.scss
@@ -36,11 +36,9 @@
/*背景色*/
html, body {
  --mk-sys-color: #1890ff;
  width: 100%;
  font-size: 14px;
  // .ant-table, .ant-dropdown {
  //   color: rgba(0, 0, 0, 0.85);
  // }
}
#root {
  height: 100%;
@@ -180,9 +178,9 @@
  z-index: 1090!important;
}
.ant-dropdown {
  z-index: 1090!important;
}
// .ant-dropdown {
//   z-index: 1090!important;
// }
.mk-normal-dropdown {
  .ant-dropdown-menu {
@@ -472,4 +470,22 @@
  .video-react .video-react-poster {
    background-size: cover;
  }
}
.table-vertical-top {
  table td {
    vertical-align: top;
  }
}
.table-vertical-bottom {
  table td {
    vertical-align: bottom;
  }
}
// 系统色设置
.mk-main-view {
  display: flex;
  flex: auto;
  min-height: 100%;
}
src/assets/css/viewstyle.scss
@@ -1,6 +1,3 @@
// bg1     主背景色
// bg2     次背景色
// font1   主字体颜色
// color1  1阶色 - 底色
// color2  2阶色
// color3  3阶色
@@ -11,152 +8,8 @@
// color8  8阶色
// color9  9阶色
// color10 10阶色
@mixin viewstyle($bg1, $bg2, $font1, $font2, $color1, $color2, $color3, $color4, $color5, $color6, $color7, $color8, $color9, $color10) {
  .login-container {
    background-color: $bg1;
    .logo {
      border-color: $color6;
      .plat-name {
        color: $font1;
      }
    }
    .login-middle {
      border-color: $color6;
      .login-form-button {
        background-color: $color6;
        border-color: $color6;
      }
      .login-form-button[disabled] {
        background-color: $color5;
        border-color: $color5;
      }
      button.vercode {
        color: $color6;
      }
      .login-way-wrap {
        .login-way.active, .login-way:hover {
          color: $color6;
        }
      }
      .anticon-eye {
        color: $color6;
      }
      .ant-input:hover {
        border-color: $color6!important;
      }
      .ant-input:focus, .ant-input:active {
        border-color: $color4;
        box-shadow: 0 0 0 2px $color2;
      }
      .ant-input-affix-wrapper:hover .ant-input:not(.ant-input-disabled) {
        border-color: $color4;
      }
    }
    .login-bottom {
      color: $font1;
      a {
        color: $font1;
      }
    }
  }
  .menu-board {
    .menu-wrap {
      .title {
        color: $color6;
      }
      .menu-detail {
        div:hover {
          color: $color5;
        }
      }
    }
  }
@mixin viewstyle($color1, $color2, $color3, $color4, $color5, $color6, $color7) {
  #root > .mk-main-view {
    > .header-container {
      background: $bg1;
      color: $font1;
      box-shadow: 0 1px 1px #d9d9d9;
      .header-setting span {
        color: $font1;
      }
      > .header-collapse .anticon {
        color: $font1;
      }
      > .header-menu {
        li {
          span {
            color: $font1;
          }
          &:hover {
            span {
              color: $color6;
              border-bottom: 4px solid $color6;
            }
          }
          &.active {
            span {
              color: $color6;
              border-bottom: 4px solid $color6;
            }
          }
        }
      }
    }
    > .mk-side-menu {
      border-right: 1px solid #d9d9d9;
      background: $bg1;
      > .ant-menu {
        background: $bg1;
        > .ant-menu-submenu {
          color: $font1;
          background: transparent;
          > .ant-menu-submenu-title {
            &:hover {
              color: $font1;
            }
            > .ant-menu-submenu-arrow:before {
              background: $font1;
            }
            > .ant-menu-submenu-arrow:after {
              background: $font1;
            }
          }
          > .ant-menu-sub {
            background: transparent;
            box-shadow: none;
            .ant-menu-item {
              a {
                color: $font2;
              }
            }
          }
        }
        > .ant-menu-submenu.ant-menu-submenu-open {
          > .ant-menu-submenu-title {
            background: $bg2;
          }
        }
      }
    }
    > .mk-side-menu:not(.edit) {
      > .ant-menu {
        > .ant-menu-submenu {
          > .ant-menu-sub {
            .ant-menu-item.ant-menu-item-active, .ant-menu-item.ant-menu-item-selected {
              background: $color5;
              color: #ffffff;
              a {
                color: #ffffff;
              }
            }
          }
        }
      }
    }
    >.mk-tabview-wrap {
      >.content-header {
        >.ant-tabs {
@@ -221,7 +74,7 @@
        > .card-item-box {
          border-color: $color6!important;
          background-color: $color1!important;
          .ant-mk-text, .ant-mk-date {
          .ant-mk-text:not(.sign-font) {
            color: $color6;
          }
        }
@@ -231,7 +84,7 @@
      .mk-card:hover, .mk-card.active, .mk-card.selected {
        > .card-item-box {
          border-color: $color6!important;
          .ant-mk-text, .ant-mk-date {
          .ant-mk-text:not(.sign-font) {
            color: $color6;
          }
        }
@@ -251,7 +104,7 @@
      }
      .mk-card:hover {
        > .card-item-box {
          .ant-mk-text, .ant-mk-date {
          .ant-mk-text:not(.sign-font) {
            color: $color6;
          }
        }
@@ -259,7 +112,7 @@
      .mk-card.active, .mk-card.selected {
        > .card-item-box {
          border-bottom-color: $color6!important;
          .ant-mk-text, .ant-mk-date {
          .ant-mk-text:not(.sign-font) {
            color: $color6;
          }
        }
@@ -441,11 +294,7 @@
  .system-color {
    color: $color6;
  }
  .system-background {
    background: $color6;
    border-color: $color6;
    color: #ffffff;
  }
  .ant-timeline.system {
    .ant-timeline-item-tail {
      border-color: $color2;
@@ -494,6 +343,11 @@
      }
    }
  }
  .ant-spin {
    .ant-spin-dot-item {
      background-color: $color6;
    }
  }
}
body.hidden-split-line #root { // 去除登录页分割线
@@ -507,152 +361,121 @@
  }
}
@mixin bgblack() {
  #root > .mk-main-view {
    > .header-container {
      box-shadow: none;
      > .header-menu {
        li {
          &:hover, &.active {
            span {
              color: #ffffff;
            }
          }
        }
      }
      .header-menu::-webkit-scrollbar-track {
        box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.05);
        border: 1px solid rgba(255, 255, 255, 0.07);
        background: rgba(255, 255, 255, 255);
        border-radius: 3px;
      }
    }
  }
// 皮肤背景与字体颜色
body[class*='-black'] {
  --mk-sys-background: #000000;
  --mk-sys-light-background: #434343;
  --mk-sys-font-color: rgba(255, 255, 255, 0.85);
  --mk-sys-light-font-color: rgba(255, 255, 255, 0.65);
}
body[class*='-white'] {
  --mk-sys-background: #ffffff;
  --mk-sys-light-background: #ffffff;
  --mk-sys-font-color: rgba(0, 0, 0, 0.85);
  --mk-sys-light-font-color: rgba(0, 0, 0, 0.65);
}
body.mk-blue-black {
body[class*='mk-blue-'] {
  --mk-sys-color: #1890ff;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65), #e6f7ff, #bae7ff, #91d5ff, #69c0ff, #40a9ff, #1890ff, #096dd9, #0050b3, #003a8c, #002766);
  @include bgblack();
  --mk-sys-color1: #e6f7ff;
  --mk-sys-color5: #40a9ff;
  @include viewstyle(#e6f7ff, #bae7ff, #91d5ff, #69c0ff, #40a9ff, #1890ff, #096dd9);
}
body.mk-blue-white {
  --mk-sys-color: #1890ff;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #e6f7ff, #bae7ff, #91d5ff, #69c0ff, #40a9ff, #1890ff, #096dd9, #0050b3, #003a8c, #002766);
}
body.mk-red-black {
body[class*='mk-red-'] {
  --mk-sys-color: #f5222d;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65), #fff1f0, #ffccc7, #ffa39e, #ff7875, #ff4d4f, #f5222d, #cf1322, #a8071a, #820014, #5c0011);
  @include bgblack();
  --mk-sys-color1: #fff1f0;
  --mk-sys-color5: #ff4d4f;
  @include viewstyle(#fff1f0, #ffccc7, #ffa39e, #ff7875, #ff4d4f, #f5222d, #cf1322);
}
body.mk-red-white {
  --mk-sys-color: #f5222d;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fff1f0, #ffccc7, #ffa39e, #ff7875, #ff4d4f, #f5222d, #cf1322, #a8071a, #820014, #5c0011);
}
body.mk-orange-red-black {
body[class*='mk-orange-red-'] {
  --mk-sys-color: #fa541c;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65), #fff2e8, #ffd8bf, #ffbb96, #ff9c6e, #ff7a45, #fa541c, #d4380d, #ad2102, #871400, #610b00);
  @include bgblack();
  --mk-sys-color1: #fff2e8;
  --mk-sys-color5: #ff7a45;
  @include viewstyle(#fff2e8, #ffd8bf, #ffbb96, #ff9c6e, #ff7a45, #fa541c, #d4380d);
}
body.mk-orange-red-white {
  --mk-sys-color: #fa541c;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fff2e8, #ffd8bf, #ffbb96, #ff9c6e, #ff7a45, #fa541c, #d4380d, #ad2102, #871400, #610b00);
}
body.mk-orange-black {
body[class*='mk-orange-'] {
  --mk-sys-color: #fa8c16;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65), #fff7e6, #ffe7ba, #ffd591, #ffc069, #ffa940, #fa8c16, #d46b08, #ad4e00, #873800, #612500);
  @include bgblack();
  --mk-sys-color1: #fff7e6;
  --mk-sys-color5: #ffa940;
  @include viewstyle(#fff7e6, #ffe7ba, #ffd591, #ffc069, #ffa940, #fa8c16, #d46b08);
}
body.mk-orange-white {
  --mk-sys-color: #fa8c16;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fff7e6, #ffe7ba, #ffd591, #ffc069, #ffa940, #fa8c16, #d46b08, #ad4e00, #873800, #612500);
}
body.mk-orange-yellow-black {
body[class*='mk-orange-yellow-'] {
  --mk-sys-color: #faad14;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#fffbe6, #fff1b8, #ffe58f, #ffd666, #ffc53d, #faad14, #d48806, #ad6800, #874d00, #613400);
  @include bgblack();
  --mk-sys-color1: #fffbe6;
  --mk-sys-color5: #ffc53d;
  @include viewstyle(#fffbe6, #fff1b8, #ffe58f, #ffd666, #ffc53d, #faad14, #d48806);
}
body.mk-orange-yellow-white {
  --mk-sys-color: #faad14;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fffbe6, #fff1b8, #ffe58f, #ffd666, #ffc53d, #faad14, #d48806, #ad6800, #874d00, #613400);
}
body.mk-yellow-black {
body[class*='mk-yellow-'] {
  --mk-sys-color: #fadb14;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#feffe6, #ffffb8, #fffb8f, #fff566, #ffec3d, #fadb14, #d4b106, #ad8b00, #876800, #614700);
  @include bgblack();
  --mk-sys-color1: #feffe6;
  --mk-sys-color5: #ffec3d;
  @include viewstyle(#feffe6, #ffffb8, #fffb8f, #fff566, #ffec3d, #fadb14, #d4b106);
}
body.mk-yellow-white {
  --mk-sys-color: #fadb14;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #feffe6, #ffffb8, #fffb8f, #fff566, #ffec3d, #fadb14, #d4b106, #ad8b00, #876800, #614700);
}
body.mk-yellow-green-black {
body[class*='mk-yellow-green-'] {
  --mk-sys-color: #a0d911;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#fcffe6, #f4ffb8, #eaff8f, #d3f261, #bae637, #a0d911, #7cb305, #5b8c00, #3f6600, #254000);
  @include bgblack();
  --mk-sys-color1: #fcffe6;
  --mk-sys-color5: #bae637;
  @include viewstyle(#fcffe6, #f4ffb8, #eaff8f, #d3f261, #bae637, #a0d911, #7cb305);
}
body.mk-yellow-green-white {
  --mk-sys-color: #a0d911;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fcffe6, #f4ffb8, #eaff8f, #d3f261, #bae637, #a0d911, #7cb305, #5b8c00, #3f6600, #254000);
}
body.mk-green-black {
body[class*='mk-green-'] {
  --mk-sys-color: #52c41a;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#f6ffed, #d9f7be, #b7eb8f, #95de64, #73d13d, #52c41a, #389e0d, #237804, #135200, #092b00);
  @include bgblack();
  --mk-sys-color1: #f6ffed;
  --mk-sys-color5: #73d13d;
  @include viewstyle(#f6ffed, #d9f7be, #b7eb8f, #95de64, #73d13d, #52c41a, #389e0d);
}
body.mk-green-white {
  --mk-sys-color: #52c41a;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #f6ffed, #d9f7be, #b7eb8f, #95de64, #73d13d, #52c41a, #389e0d, #237804, #135200, #092b00);
}
body.mk-cyan-black {
body[class*='mk-cyan-'] {
  --mk-sys-color: #13c2c2;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#e6fffb, #b5f5ec, #87e8de, #5cdbd3, #36cfc9, #13c2c2, #08979c, #006d75, #00474f, #002329);
  @include bgblack();
  --mk-sys-color1: #e6fffb;
  --mk-sys-color5: #36cfc9;
  @include viewstyle(#e6fffb, #b5f5ec, #87e8de, #5cdbd3, #36cfc9, #13c2c2, #08979c);
}
body.mk-cyan-white {
  --mk-sys-color: #13c2c2;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #e6fffb, #b5f5ec, #87e8de, #5cdbd3, #36cfc9, #13c2c2, #08979c, #006d75, #00474f, #002329);
}
body.mk-blue-purple-black {
body[class*='mk-blue-purple-'] {
  --mk-sys-color: #2f54eb;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#f0f5ff, #d6e4ff, #adc6ff, #85a5ff, #597ef7, #2f54eb, #1d39c4, #10239e, #061178, #030852);
  @include bgblack();
  --mk-sys-color1: #f0f5ff;
  --mk-sys-color5: #597ef7;
  @include viewstyle(#f0f5ff, #d6e4ff, #adc6ff, #85a5ff, #597ef7, #2f54eb, #1d39c4);
}
body.mk-blue-purple-white {
  --mk-sys-color: #2f54eb;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #f0f5ff, #d6e4ff, #adc6ff, #85a5ff, #597ef7, #2f54eb, #1d39c4, #10239e, #061178, #030852);
}
body.mk-purple-black {
body[class*='mk-purple-'] {
  --mk-sys-color: #722ed1;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#f9f0ff, #efdbff, #d3adf7, #b37feb, #9254de, #722ed1, #531dab, #391085, #22075e, #120338);
  @include bgblack();
  --mk-sys-color1: #f9f0ff;
  --mk-sys-color5: #9254de;
  @include viewstyle(#f9f0ff, #efdbff, #d3adf7, #b37feb, #9254de, #722ed1, #531dab);
}
body.mk-purple-white {
  --mk-sys-color: #722ed1;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #f9f0ff, #efdbff, #d3adf7, #b37feb, #9254de, #722ed1, #531dab, #391085, #22075e, #120338);
}
body.mk-magenta-black {
body[class*='mk-magenta-'] {
  --mk-sys-color: #eb2f96;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#fff0f6, #ffd6e7, #ffadd2, #ff85c0, #f759ab, #eb2f96, #c41d7f, #9e1068, #780650, #520339);
  @include bgblack();
  --mk-sys-color1: #fff0f6;
  --mk-sys-color5: #f759ab;
  @include viewstyle(#fff0f6, #ffd6e7, #ffadd2, #ff85c0, #f759ab, #eb2f96, #c41d7f);
}
body.mk-magenta-white {
  --mk-sys-color: #eb2f96;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fff0f6, #ffd6e7, #ffadd2, #ff85c0, #f759ab, #eb2f96, #c41d7f, #9e1068, #780650, #520339);
}
body.mk-grass-green-black {
body[class*='mk-grass-green-'] {
  --mk-sys-color: #aeb303;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#f2efda, #e6de97, #d9d26c, #ccc845, #bfbf22, #aeb303, #838c00, #5c6600, #374000, #151a00);
  @include bgblack();
  --mk-sys-color1: #f2efda;
  --mk-sys-color5: #bfbf22;
  @include viewstyle(#f2efda, #e6de97, #d9d26c, #ccc845, #bfbf22, #aeb303, #838c00);
}
body.mk-grass-green-white {
  --mk-sys-color: #aeb303;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #f2efda, #e6de97, #d9d26c, #ccc845, #bfbf22, #aeb303, #838c00, #5c6600, #374000, #151a00);
}
body.mk-deep-red-black {
body[class*='mk-deep-red-'] {
  --mk-sys-color: #c32539;
  @include viewstyle(#000000, #434343,rgba(255, 255, 255, 0.85), rgba(255, 255, 255, 0.65),#fff0f0, #f5cbcb, #e89b9e, #db7077, #cf4856, #c32539, #9c162c, #750b20, #4f0315, #29010c);
  @include bgblack();
  --mk-sys-color1: #fff0f0;
  --mk-sys-color5: #cf4856;
  @include viewstyle(#fff0f0, #f5cbcb, #e89b9e, #db7077, #cf4856, #c32539, #9c162c);
}
body.mk-deep-red-white {
  --mk-sys-color: #c32539;
  @include viewstyle(#ffffff, #ffffff, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0.65), #fff0f0, #f5cbcb, #e89b9e, #db7077, #cf4856, #c32539, #9c162c, #750b20, #4f0315, #29010c);
}
body[class*='mk-deep-blue-'] {
  --mk-sys-color: #1d3661;
  --mk-sys-color1: #eff1f4;
  --mk-sys-color5: #394c6f;
  @include viewstyle(#eff1f4, #e0e3e9, #dbdfe6, #c6cede, #394c6f, #1d3661, #1d3661);
}
src/assets/mobimg/account.png
src/assets/mobimg/voucher.png
src/components/header/index.jsx
@@ -558,6 +558,7 @@
            resolve()
          } else {
            Api.updateAppVersion()
            Api.delCacheConfig('all')
            setTimeout(() => {
              notification.success({
                top: 92,
src/components/header/index.scss
@@ -7,6 +7,8 @@
  width: 100%;
  height: 48px;
  display: flex;
  background: var(--mk-sys-background);
  color: var(--mk-sys-font-color);
  .header-logo {
    width: 180px;
@@ -39,7 +41,7 @@
      position: relative;
      top: 3px;
      font-size: 20px;
      color: #ffffff;
      color: var(--mk-sys-font-color);
    }
  }
  .header-collapse.collapse {
@@ -62,18 +64,21 @@
        padding: 0 10px;
        height: 42px;
        display: inline-block;
        color: var(--mk-sys-font-color);
      }
      &:hover {
        color: #eeeeee;
        span {
          border-bottom: 4px solid #fafcfb;
          color: var(--mk-sys-color);
          border-bottom: 4px solid var(--mk-sys-color);
        }
      }
      &.active {
        color: #ffffff;
        span {
          border-bottom: 4px solid #1890ff;
          color: var(--mk-sys-color);
          border-bottom: 4px solid var(--mk-sys-color);
        }
      }
    }
@@ -95,9 +100,9 @@
    border-radius: 5px;
  }
  .header-menu::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(255, 255, 255, 0.05);
    border: 1px solid rgba(255, 255, 255, 0.07);
    background: rgba(255, 255, 255, 255);
    border-radius: 3px;
  }
@@ -111,7 +116,7 @@
      margin-right: 7px;
    }
    span {
      color: #ffffff;
      color: var(--mk-sys-font-color);
      font-size: 0.95rem;
      .username {
        vertical-align: middle;
@@ -216,7 +221,7 @@
  // left: 11.8%;
  .menu-wrap {
    .title {
      color: #1890ff;
      color: var(--mk-sys-color);
      font-size: 15px;
      font-weight: 600;
    }
@@ -224,18 +229,14 @@
      max-width: 60vw;
      padding: 5px 0 5px 15px;
      div {
        // float: left;
        display: inline-block;
        vertical-align: top;
        margin-bottom: 8px;
        width: 120px;
        // overflow: hidden;
        // white-space: nowrap;
        // text-overflow: ellipsis;
        cursor: pointer;
      }
      div:hover {
        color: #40a9ff;
        color: var(--mk-sys-color5);
      }
      div:not(:last-child) {
        margin-right: 15px;
@@ -247,4 +248,30 @@
      clear: both;
    }
  }
}
body[class*='-white'] {
  .header-container {
    box-shadow: 0 1px 1px #d9d9d9;
    .header-menu::-webkit-scrollbar-track {
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
      border: 1px solid rgba(0, 0, 0, 0.07);
      background: rgba(0, 0, 0, 0);
      border-radius: 3px;
    }
  }
}
body[class*='-black'] {
  .header-container {
    .header-menu {
      li {
        &:hover, &.active {
          span {
            color: #ffffff;
          }
        }
      }
    }
  }
}
src/components/header/resetpwd/index.jsx
@@ -73,7 +73,7 @@
    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
      callback('密码中必须含有数字和字母。')
    } else if ((level === 'char_num' || level === 'char_num_90') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
    } else if ((level === 'char_num' || level === 'char_num_90' || level === 'char_num_90_sms') && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*|[^!@#$%^&*()_]*)$/.test(value)) {
      callback('密码中必须含有数字、字母和特殊字符。')
    } else {
      callback()
src/components/keyInterface/index.jsx
@@ -19,6 +19,7 @@
    url: '',
    key: '',
    visible: false,
    apptoken: '',
    setting: null
  }
@@ -57,7 +58,7 @@
      }
    }
    this.setState({visible: true, setting: _setting || {}})
    this.setState({visible: true, setting: _setting || {ssoInterface: 'http://sso.mk9h.cn/cloud/webapi/dostars'}})
  }
  decrypt = (token, value) => {
@@ -104,7 +105,7 @@
            return
          }
        }
        this.setState({key: key, setting: _setting})
        this.setState({key: key, apptoken: values.apptoken, setting: _setting})
        return
      }
@@ -136,7 +137,7 @@
      this.props.onChange(content)
      this.setState({setting: message, url: values.interface, visible: false})
      this.setState({setting: message, url: values.interface, apptoken: '', visible: false})
      if (this.props.type !== 'develop') {
        this.setState({key: ''})
@@ -153,7 +154,7 @@
    if (type === 'develop') {
      this.setState({setting: null, url: ''})
    } else {
      this.setState({key: '', setting: null, url: ''})
      this.setState({key: '', apptoken: '', setting: null, url: ''})
    }
    this.props.onChange('')
@@ -163,14 +164,15 @@
    const { type } = this.props
    if (type !== 'develop') {
      this.setState({key: ''})
      this.setState({key: '', apptoken: ''})
    }
    this.setState({visible: false})
  }
  render() {
    const { type } = this.props
    const { getFieldDecorator } = this.props.form
    const { url, visible, setting, key } = this.state
    const { url, visible, setting, key, apptoken } = this.state
    return (
      <div className="mk-key-wrap">
@@ -191,9 +193,12 @@
        >
          {key && setting ?
            <Form>
              {apptoken && type !== 'develop' ? <Form.Item style={{color: 'red'}} label="正式系统appkey">
                {apptoken}
              </Form.Item> : null}
              <Form.Item label="接口地址">
                {getFieldDecorator('interface', {
                  initialValue: setting.interface,
                  initialValue: setting.interface || 'http://******/webapi/dostars',
                  rules: [
                    {
                      required: true,
@@ -204,7 +209,7 @@
                      message: '只可使用英文、数字以及:_./'
                    }
                  ]
                })(<TextArea rows={2}/>)}
                })(<TextArea placeholder="http://******/webapi/dostars" rows={2}/>)}
              </Form.Item>
              <Form.Item label="sso地址">
                {getFieldDecorator('ssoInterface', {
@@ -215,9 +220,9 @@
                      message: '只可使用英文、数字以及:_./'
                    }
                  ]
                })(<TextArea rows={2}/>)}
                })(<TextArea placeholder="http://sso.mk9h.cn/cloud/webapi/dostars" rows={2}/>)}
              </Form.Item>
              <Form.Item label="appkey">
              <Form.Item label="目标系统appkey">
                {getFieldDecorator('appkey', {
                  initialValue: setting.appkey || '',
                  rules: [
@@ -282,7 +287,7 @@
              </Form.Item>
            </Form> : null}
          {!key ? <Form style={{marginTop: '20px', marginBottom: '50px'}}>
            <Form.Item label="appkey">
            <Form.Item label="正式系统appkey">
              {getFieldDecorator('apptoken', {
                initialValue: '',
                rules: [
src/components/keyInterface/index.scss
@@ -43,7 +43,7 @@
  .ant-form-item {
    display: flex;
    .ant-form-item-label {
      width: 20%;
      width: 22%;
    }
    .ant-form-item-control-wrapper {
      width: 70%;
src/components/mk-icon/index.jsx
@@ -471,7 +471,20 @@
        MkIcons[type](resProps)
      )
    } else {
      return <span className={'anticon anticon-mk ' + (resProps.className || '')} style={resProps.style || null} dangerouslySetInnerHTML={{ __html: type }}></span>
      let svg = type
      if (!/<svg/.test(svg)) {
        try {
          svg = window.decodeURIComponent(window.atob(svg))
          if (!/<svg/.test(svg)) {
            svg = ''
          }
        } catch (e) {
          svg = ''
        }
      }
      return <span className={'anticon anticon-mk ' + (resProps.className || '')} style={resProps.style || null} dangerouslySetInnerHTML={{ __html: svg }}></span>
    }
  }
}
src/components/normalform/modalform/index.jsx
@@ -105,7 +105,6 @@
      let supItem = fieldMap.get(key)
      let fields = []
      controlFields[key].forEach(item => {
        if (!fieldMap.has(item.field)) return
src/components/normalform/modalform/styleInput/index.jsx
@@ -128,7 +128,7 @@
    const { value, options, unit } = this.state
    return (
      <div className="style-input-wrap">
      <div className="mk-style-input-wrap">
        <Input value={value} addonAfter={
          options.length > 1 ?
          <Select value={unit} onChange={this.changeUnit}>
src/components/normalform/modalform/styleInput/index.scss
@@ -1,4 +1,4 @@
.style-input-wrap {
.mk-style-input-wrap {
  line-height: 32px;
  .ant-select {
    width: 60px!important;
@@ -6,7 +6,6 @@
  .single-unit {
    width: 38px;
    text-align: left;
    color: rgba(255, 255, 255, 0.65);
  }
  div[title="vh"], div[title="vw"] {
    color: #1890ff;
src/components/sidemenu/index.scss
@@ -1,10 +1,12 @@
@import '../../assets/css/iconfont.css';
// @import '../../assets/css/iconfont.css';
.mk-side-menu {
  flex: 0 0 235px;
  width: 235px;
  padding: 48px 0 40px;
  transition: width 0.2s, flex 0.2s;
  border-right: 1px solid #d9d9d9;
  background: var(--mk-sys-background);
  .ant-menu-item {
    padding-left: 0!important;
    cursor: default;
@@ -29,12 +31,6 @@
    .edit-check {
      top: -5px;
    }
  }
  .ant-menu-sub.ant-menu-inline > .ant-menu-item.ant-menu-item-active {
    background: #06b4f7;
  }
  .ant-menu-sub.ant-menu-inline > .ant-menu-item.ant-menu-item-selected {
    background: #06b4f7;
  }
  .ant-menu-inline .ant-menu-item {
    font-size: 1.1rem;
@@ -92,6 +88,46 @@
    width: 48px;
    left: 187px;
  }
  > .ant-menu {
    background: var(--mk-sys-background);
    > .ant-menu-submenu {
      color: var(--mk-sys-font-color);
      background: transparent;
      > .ant-menu-submenu-title {
        &:hover {
          color: var(--mk-sys-font-color);
        }
        > .ant-menu-submenu-arrow:before {
          background: var(--mk-sys-font-color);
        }
        > .ant-menu-submenu-arrow:after {
          background: var(--mk-sys-font-color);
        }
      }
      > .ant-menu-sub {
        background: transparent;
        box-shadow: none;
        .ant-menu-item {
          a {
            color: var(--mk-sys-light-font-color);
          }
        }
        .ant-menu-item.ant-menu-item-active, .ant-menu-item.ant-menu-item-selected {
          background: var(--mk-sys-color5);
          color: #ffffff;
          a {
            color: #ffffff;
          }
        }
      }
    }
    > .ant-menu-submenu.ant-menu-submenu-open {
      > .ant-menu-submenu-title {
        background: var(--mk-sys-light-background);
      }
    }
  }
}
// .mk-side-menu.mk-iframe { // tab页中为iframe时
src/components/tabview/index.jsx
@@ -23,7 +23,6 @@
const Iframe = asyncComponent(() => import('@/tabviews/iframe'))
const RoleManage = asyncComponent(() => import('@/tabviews/rolemanage'))
const FormTab = asyncComponent(() => import('@/tabviews/formtab'))
const TabManage = asyncComponent(() => import('@/tabviews/tabmanage'))
class TabViews extends Component {
  static propTpyes = {
@@ -211,8 +210,6 @@
      return (<RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'FormTab') {
      return (<FormTab MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
    } else if (view.type === 'TabManage') {
      return (<TabManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
    } else if (view.type === 'iframe') {
      return (<Iframe key={view.MenuID} MenuID={view.MenuID} MenuNo={view.MenuNo} title={view.MenuName} MenuName={view.MenuName} url={window.GLOB.baseurl + 'zh-CN/' + view.LinkUrl}/>)
    } else {
@@ -264,11 +261,11 @@
    const { tabviews, activeId } = this.state
    return (
      <section id="mk-tabview-wrap" className={'mk-tabview-wrap' + (this.props.collapse ? ' collapsed' : '') + (tabviews && tabviews.length > 0 ? ' hastab' : '')}>
      <section className={'mk-tabview-wrap' + (this.props.collapse ? ' collapsed' : '')}>
        <div className="content-header">
          {tabviews && tabviews.length > 0 &&
            <Tabs activeKey={activeId}>
              {tabviews.map((view, index) => {
              {tabviews.map(view => {
                return (
                  <Tabs.TabPane
                    tab={
@@ -292,7 +289,6 @@
                        </div>
                      </div>
                    </BackTop>
                    {/* {options.sysType === 'local' && window.GLOB.systemType !== 'production' ? <div className="mk-water-mark">测试系统</div> : null} */}
                  </Tabs.TabPane>
                )
              })}
src/index.js
@@ -8,7 +8,7 @@
import options, { styles } from '@/store/options.js'
import '@/assets/css/main.scss'
import '@/assets/css/action.scss'
import '@/assets/css/minkeicon.css'
// import '@/assets/css/minkeicon.css'
import '@/assets/css/viewstyle.scss'
if (window.location.href.indexOf('#/design') > -1) { // 编辑页面刷新时,跳转至主页
@@ -179,6 +179,7 @@
    let _systemMsg = localStorage.getItem(_href + 'system')
    GLOB.navBar = 'shutter' // 默认为百叶窗
    let className = 'mk-blue-black'
    if (_systemMsg) {
      try {
@@ -207,13 +208,15 @@
          document.getElementsByTagName('head')[0].appendChild(link)
        }
        if (GLOB.style && styles[GLOB.style]) {
          document.body.className = styles[GLOB.style] + ' ' + (GLOB.showline === 'false' ? 'hidden-split-line' : '')
          className = styles[GLOB.style] + ' ' + (GLOB.showline === 'false' ? 'hidden-split-line' : '')
        }
      } catch (e) {
        console.warn('Parse Failure')
      }
    }
    document.body.className = className
    if (/^https/.test(window.location.protocol) || (process.env.NODE_ENV !== 'production' && /^https/.test(config.host))) { // https转换
      let meta = document.createElement('meta')
      meta.content = 'upgrade-insecure-requests'
src/menu/components/card/balcony/index.scss
@@ -17,17 +17,7 @@
  .model-menu-card-cell-list {
    flex: 1;
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/card/balcony/options.jsx
@@ -257,7 +257,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -72,6 +72,14 @@
    _style_ = {clear: 'left'}
  }
  let className = card.width || ''
  if (card.hidden === 'true') {
    className += ' mk-hidden'
  }
  if (card.checkType) {
    className += ' ' + card.checkType
  }
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
@@ -82,7 +90,7 @@
        {hasProfile ? <ProfileOutlined className="profile" title="setting" onClick={() => profileCard(id)} /> : null}
      </div>
    } trigger="hover">
      <div ref={node => drag(drop(node))} style={_style_} className={'ant-col card-button-cell ant-col-' + card.width + (card.hidden === 'true' ? ' mk-hidden' : '')} onDoubleClick={(e) => {e.stopPropagation(); doubleClickCard(id)}}>
      <div ref={node => drag(drop(node))} style={_style_} className={'ant-col card-button-cell ant-col-' + className} onDoubleClick={(e) => {e.stopPropagation(); doubleClickCard(id)}}>
        <div style={{opacity: isDragging ? 0.3 : 1, ...card.wrapStyle}}>
          {btnElement}
        </div>
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -180,6 +180,19 @@
          {val}
        </div>
      )
    } else if (card.eleType === 'color') {
      _style.overflow = 'hidden'
      let _bgstyle = {backgroundColor: card.value || '#1890ff'}
      if (PicRadio[card.lenWidRadio]) {
        _bgstyle.paddingTop = PicRadio[card.lenWidRadio]
      } else {
        _bgstyle.paddingTop = '100%'
      }
      return (
        <div style={_bgstyle}></div>
      )
    }
  }
@@ -191,7 +204,7 @@
  }
  let able = true
  if ((appType === 'mob' || appType === 'pc') && (parent.setting.click === 'menu' || parent.setting.click === 'menus')) {
  if ((appType === 'mob' || appType === 'pc') && parent.setting && (parent.setting.click === 'menu' || parent.setting.click === 'menus')) {
    able = false
  }
src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -140,4 +140,10 @@
    width: 26px;
    height: 26px;
  }
  .card-cell > div {
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
  }
}
src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -26,6 +26,7 @@
  qrcode: ['eleType', 'datatype', 'width', 'qrWidth', 'color', 'url', 'noValue'],
  currentDate: ['eleType', 'width', 'dateFormat', 'prefix', 'postfix', 'fixStyle'],
  formula: ['eleType', 'width', 'height', 'prefix', 'postfix', 'eval', 'formula', 'noValue', 'fixStyle'],
  color: ['eleType', 'datatype', 'width', 'lenWidRadio', 'noValue', 'copyable'],
}
class MainSearch extends Component {
@@ -104,7 +105,7 @@
  getOptions = (eleType, datatype, link, showType, showInfo, fixStyle, posterType) => {
    let _options = fromJS(cardTypeOptions[eleType]).toJS() // 选项列表
    
    if (['text', 'number', 'picture', 'slider', 'barcode', 'qrcode', 'video'].includes(eleType)) {
    if (['text', 'number', 'picture', 'slider', 'barcode', 'qrcode', 'video', 'color'].includes(eleType)) {
      if (datatype === 'dynamic') {
        _options.push('field')
        if (eleType === 'number') {
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -18,6 +18,7 @@
    { value: 'qrcode', text: '二维码'},
    { value: 'currentDate', text: '当前时间'},
    { value: 'formula', text: '公式'},
    { value: 'color', text: '颜色'},
  ]
  let anchors = []
src/menu/components/card/cardcellcomponent/index.jsx
@@ -155,6 +155,8 @@
      }
    } else if (element.eleType === 'picture') {
      options = ['border', 'margin']
    } else if (element.eleType === 'color') {
      options = ['border', 'margin', 'padding']
    } else if (element.eleType === 'text') {
      options[0] = 'font2'
      options.push('display')
src/menu/components/card/cardcellcomponent/index.scss
@@ -29,6 +29,14 @@
      }
    }
    .ant-checkbox .ant-checkbox-inner {
      border-color: #b8b8b8;
    }
  }
  .card-button-cell:not(.square) {
    .ant-checkbox .ant-checkbox-inner {
      border-radius: 15px;
    }
    .ant-checkbox-checked::after {
      border-radius: 15px;
    }
  }
src/menu/components/card/cardcomponent/index.jsx
@@ -320,7 +320,7 @@
              <div className="mk-popover-control">
                <PlusOutlined className="plus" title="添加元素" onClick={this.addElement} />
                <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton} />
                <NormalForm title="卡片设置" width={950} update={this.updateSetting} getForms={this.getSettingForms}>
                <NormalForm title={cards.subtype === 'datacard' && card.$cardType !== 'extendCard' ? '循环卡片设置' : '属性卡片设置'} width={950} update={this.updateSetting} getForms={this.getSettingForms}>
                  <EditOutlined className="edit" title="编辑"/>
                </NormalForm>
                <CopyComponent type="cardcell" card={card}/>
@@ -338,7 +338,7 @@
                {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
              </div>
            } trigger="hover">
              <ToolOutlined />
              <ToolOutlined style={cards.subtype === 'datacard' && card.$cardType === 'extendCard' ? {color: '#26C281'} : null}/>
            </Popover>
          </div>
        </div>
src/menu/components/card/cardcomponent/index.scss
@@ -45,4 +45,20 @@
      }
    }
  }
}
}
.card-control {
  position: absolute;
  top: 0px;
  left: 0px;
  .anticon-tool {
    position: absolute;
    left: 1px;
    top: 1px;
    padding: 1px;
    z-index: 2;
    font-size: 16px;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.55);
  }
}
src/menu/components/card/cardcomponent/options.jsx
@@ -103,6 +103,15 @@
      forbid: subtype !== 'propcard'
    },
    {
      type: 'select',
      field: 'bgField',
      label: '背景图',
      initval: setting.bgField || '',
      tooltip: '动态背景,背景图片由字段值控制。请注意调整背景样式。',
      required: false,
      options: columns
    },
    {
      type: ops.length === 0 ? 'radio' : 'select',
      field: 'click',
      label: '点击事件',
src/menu/components/card/cardsimplecomponent/index.jsx
@@ -10,7 +10,7 @@
import { getTableSetting, getCarouselSetting } from './options'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
// import './index.scss'
import './index.scss'
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
const NodesWrap = asyncComponent(() => import('./node-wrap'))
@@ -212,7 +212,7 @@
    let _style = {...card.style}
    if (cards.type === 'carousel') {
      _style.height = cards.style.height
      _style.height = cards.wrap.height
    }
    let control = true
@@ -223,34 +223,32 @@
    _style = resetStyle(_style)
    return (
      <div className="ant-col ant-col-24">
        <div className="card-item" style={_style}>
          <CardCellComponent cards={cards} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
          <div className="card-control">
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <PlusOutlined className="plus" title="添加元素" onClick={this.addElement}/>
                <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton}/>
                {cards.type !== 'timeline' ? <NormalForm title="卡片设置" width={800} update={this.updateSetting} getForms={this.getSettingForms}>
                  <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
                </NormalForm> : <NodesWrap card={card} updateMenus={this.updateNodes}/>}
                {cards.type !== 'timeline' ? <CopyComponent type="cardcell" card={card}/> : null}
                <PasteController options={['action', 'customCardElement']} updateConfig={this.paste} />
                <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
                {control ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                  <div className="mk-popover-control">
                    <ArrowLeftOutlined className="plus" title="前移" onClick={() => this.props.move(card, 'left')} />
                    <ArrowRightOutlined className="close" title="后移" onClick={() => this.props.move(card, 'right')} />
                  </div>
                } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}>
                  <SwapOutlined id={card.uuid + 'swap'}/>
                </Popover> : null}
                {control ? <DeleteOutlined className="close" title="删除卡片" onClick={() => this.props.deleteElement(card)} /> : null}
              </div>
            } trigger="hover">
              <ToolOutlined/>
            </Popover>
          </div>
      <div className="card-item" style={_style}>
        <CardCellComponent cards={cards} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
        <div className="card-control">
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              <PlusOutlined className="plus" title="添加元素" onClick={this.addElement}/>
              <PlusSquareOutlined className="plus" title="添加按钮" onClick={this.addButton}/>
              {cards.type !== 'timeline' ? <NormalForm title="卡片设置" width={800} update={this.updateSetting} getForms={this.getSettingForms}>
                <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
              </NormalForm> : <NodesWrap card={card} updateMenus={this.updateNodes}/>}
              {cards.type !== 'timeline' ? <CopyComponent type="cardcell" card={card}/> : null}
              <PasteController options={['action', 'customCardElement']} updateConfig={this.paste} />
              <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
              {control ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                <div className="mk-popover-control">
                  <ArrowLeftOutlined className="plus" title="前移" onClick={() => this.props.move(card, 'left')} />
                  <ArrowRightOutlined className="close" title="后移" onClick={() => this.props.move(card, 'right')} />
                </div>
              } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}>
                <SwapOutlined id={card.uuid + 'swap'}/>
              </Popover> : null}
              {control ? <DeleteOutlined className="close" title="删除卡片" onClick={() => this.props.deleteElement(card)} /> : null}
            </div>
          } trigger="hover">
            <ToolOutlined/>
          </Popover>
        </div>
      </div>
    )
src/menu/components/card/cardsimplecomponent/index.scss
@@ -0,0 +1,15 @@
.card-control {
  position: absolute;
  top: 0px;
  left: 0px;
  .anticon-tool {
    position: absolute;
    left: 1px;
    top: 1px;
    padding: 1px;
    z-index: 2;
    font-size: 16px;
    cursor: pointer;
    background: rgba(255, 255, 255, 0.55);
  }
}
src/menu/components/card/data-card/index.jsx
@@ -69,7 +69,12 @@
            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
          },
          backStyle: {},
          elements: [],
          elements: [{
            uuid: Utils.getuuid(),
            eleType: 'text',
            datatype: 'static',
            value: '循环区域'
          }],
          backElements: [],
          menus: []
        }]
src/menu/components/card/data-card/index.scss
@@ -8,17 +8,7 @@
  min-height: 20px;
  overflow-y: auto;
  
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/card/data-card/options.jsx
@@ -149,7 +149,7 @@
      options: [
        {value: 'page', label: '页码'},
        {value: 'switch', label: '左右切换', forbid: appType === 'mob' || subtype === 'tablecard'},
        {value: 'slide', label: '滑动加载', forbid: appType !== 'mob'},
        {value: 'slide', label: '滑动加载', forbid: appType !== 'mob' || sessionStorage.getItem('editMenuType') === 'popview'},
        {value: 'more', label: '查看更多'},
      ],
      controlFields: [
@@ -196,18 +196,33 @@
      forbid: subtype !== 'propcard'
    },
    {
      type: 'select',
      field: 'selected',
      label: '数据选中',
      initval: wrap.selected || 'false',
      tooltip: '初始化:数据加载时选中首行数据,仅执行一次。数据加载:每次数据加载时均选中首行(当按钮执行完成并返回主键值时,默认选中主键值对应行)。选中标记:返回数据中存在 selected 字段,且值为 true 的数据被选中。',
      required: false,
      options: [
        {value: 'false', label: '无'},
        {value: 'init', label: '初始化'},
        {value: 'always', label: '数据加载'},
        {value: 'sign', label: '选中标记'}
      ],
      forbid: subtype !== 'datacard'
    },
    {
      type: 'radio',
      field: 'selected',
      label: '首行选中',
      label: '数据选中',
      initval: wrap.selected || 'false',
      tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。',
      tooltip: '初始化:数据加载时选中首行数据,仅执行一次。数据加载:每次数据加载时均选中首行。',
      required: false,
      options: [
        {value: 'false', label: '无'},
        {value: 'init', label: '初始化'},
        {value: 'always', label: '数据加载'},
      ],
      forbid: subtype === 'tablecard'
      forbid: subtype !== 'propcard'
    },
    {
      type: 'select',
@@ -303,15 +318,15 @@
    {
      type: 'radio',
      field: 'goback',
      label: '空值返回',
      label: appType === 'mob' ? '空值返回' : '空值关闭',
      initval: wrap.goback || 'false',
      tooltip: '当查询数据为空时,返回上一界面。',
      tooltip: appType === 'mob' ? '当查询数据为空时,返回上一界面。' : '当查询数据为空时,关闭当前标签页。',
      required: false,
      options: [
        {value: 'true', label: '是'},
        {value: 'false', label: '否'},
        {value: 'true', label: '是'},
      ],
      forbid: subtype !== 'propcard' || appType !== 'mob'
      forbid: subtype !== 'propcard' || appType === 'pc'
    },
    {
      type: 'radio',
@@ -484,7 +499,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/card/prop-card/index.scss
@@ -7,17 +7,7 @@
  background-size: cover;
  min-height: 20px;
  
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/card/table-card/index.scss
@@ -24,17 +24,7 @@
      z-index: 1;
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/carousel/data-card/index.scss
@@ -7,17 +7,7 @@
  background-size: cover;
  min-height: 30px;
  
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/carousel/data-card/options.jsx
@@ -211,7 +211,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/carousel/prop-card/index.scss
@@ -7,17 +7,7 @@
  background-size: cover;
  min-height: 30px;
  
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/chart/antv-G6/chartcompile/formconfig.jsx
@@ -87,7 +87,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
@@ -218,7 +218,7 @@
      controlFields: [
        {field: 'dirField', values: ['mindmap']},
        {field: 'nodeColor', values: ['mindmap']},
        {field: 'collapsed', values: ['indentTree', 'kapmap']},
        // {field: 'collapsed', values: ['indentTree', 'kapmap']},
      ]
    },
    {
@@ -316,7 +316,7 @@
      label: '节点颜色',
      initval: card.nodeColor || '#1890ff',
      tooltip: '右侧节点的标记颜色。',
      isHex: true,
      colorType: 'hex',
      required: false
    },
    {
@@ -325,7 +325,7 @@
      label: '左节点颜色',
      initval: card.leftColor || '#26C281',
      tooltip: '左侧节点的标记颜色。',
      isHex: true,
      colorType: 'hex',
      required: false
    },
    {
src/menu/components/chart/antv-G6/index.jsx
@@ -60,7 +60,8 @@
  purple: '#722ed1',
  magenta: '#eb2f96',
  grass_green: '#aeb303',
  deep_red: '#c32539'
  deep_red: '#c32539',
  deep_blue: '#1d3661'
}
let systemColor = '#1890ff'
@@ -93,29 +94,7 @@
  },
  'single-node',
)
G6.registerNode(
  'dice-mind-map-sub', {
    jsx: (cfg) => {
      const width = Util.getTextSize(cfg.label, 14)[0] + 24
      return `
        <group>
          <rect style={{width: ${width}, height: 22, cursor: pointer}}>
            <text style={{ fontSize: 14, fill: ${cfg.selected ? systemColor : '#000000'}, marginLeft: 12, marginTop: 6, cursor: pointer }}>${cfg.label}</text>
          </rect>
          <rect style={{ fill: ${cfg.color}, width: ${width}, height: 2, x: 0, y: 22, cursor: pointer }} />
        </group>
      `
    },
    getAnchorPoints() {
      return [
        [0, 0.965],
        [1, 0.965]
      ]
    }
  },
  'single-node',
)
G6.registerNode(
  'dice-mind-map-leaf', {
    jsx: (cfg) => {
@@ -203,38 +182,6 @@
    ev.preventDefault()
  }
})
const dataMapTransform = (data) => {
  const changeData = (d, level = 0, color) => {
    const data = { ...d }
    switch (level) {
      case 0:
        data.type = 'dice-mind-map-root'
        break
      case 1:
        data.type = 'dice-mind-map-sub'
        break
      default:
        data.type = 'dice-mind-map-leaf'
        break
    }
    if (color) {
      data.color = color
    }
    if (level === 1 && !d.direction) {
      data.direction = 'right'
    }
    if (d.children) {
      data.children = d.children.map((child) => changeData(child, level + 1, data.color))
    }
    return data
  }
  return changeData(data)
}
// 缩进文件树
G6.registerNode('indentedRoot', {
@@ -1137,9 +1084,27 @@
        if (item.direction === 'left') {
          item.color = card.plot.leftColor || '#26C281'
        } else {
          item.direction = 'right'
          item.color = card.plot.nodeColor || '#1890ff'
        }
      })
      data.collapsed = false
      data.type = 'dice-mind-map-root'
      const collapse = (item) => {
        if (!item.children) return
        item.children.forEach(cell => {
          cell.collapsed = card.plot.collapsed === 'true'
          cell.direction = cell.direction || 'right'
          cell.type = 'dice-mind-map-leaf'
          cell.color = cell.color || item.color
          collapse(cell)
        })
      }
      collapse(data)
    } else if (card.plot.subtype === 'indentTree') {
      data.isRoot = true
      data.collapsed = false
@@ -1184,11 +1149,12 @@
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
    const height = getHeight(plot.height)
    const graph = new G6.TreeGraph({
      container: card.uuid + 'canvas',
      width: this.wrap.scrollWidth - 30,
      height: getHeight(plot.height),
      height: height,
      modes: {
        default: [
          {
@@ -1235,6 +1201,10 @@
    graph.data(data)
    graph.render()
    graph.fitView()
    if (plot.collapsed === 'true') {
      graph.zoomTo(1, { x: 0, y: height / 2 })
    }
  }
  indentrender = () => {
@@ -1306,11 +1276,18 @@
    const { card } = this.state
    const plot = card.plot
    const data = this.getdata()
    const width = this.wrap.scrollWidth - 30
    const height = getHeight(plot.height)
    let modes = ['drag-canvas', 'zoom-canvas', 'dice-mindmap']
    if (plot.collapsed === 'true') {
      modes = [{ type: 'collapse-expand' },'drag-canvas', 'zoom-canvas', 'dice-mindmap']
    }
    const tree = new G6.TreeGraph({
      container: card.uuid + 'canvas',
      width: this.wrap.scrollWidth - 30,
      height: getHeight(plot.height),
      width: width,
      height: height,
      fitView: true,
      layout: {
        type: 'mindmap',
@@ -1341,13 +1318,19 @@
      },
      minZoom: 0.5,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', 'dice-mindmap']
        default: modes
      }
    })
    tree.data(dataMapTransform(data))
    tree.data(data)
    tree.render()
    if (plot.collapsed === 'true' && plot.dirField) {
      tree.zoomTo(1, { x: width / 2, y: height / 2 })
    } else if (plot.collapsed === 'true') {
      tree.zoomTo(1, { x: 0, y: height / 2 })
    }
  }
  updateComponent = (card) => {
src/menu/components/chart/antv-bar/chartcompile/formconfig.jsx
@@ -87,7 +87,7 @@
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'select',
src/menu/components/chart/antv-dashboard/chartcompile/formconfig.jsx
@@ -61,7 +61,7 @@
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'select',
src/menu/components/chart/antv-pie/chartcompile/formconfig.jsx
@@ -119,7 +119,7 @@
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'select',
src/menu/components/chart/antv-scatter/chartcompile/formconfig.jsx
@@ -61,7 +61,7 @@
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'select',
src/menu/components/chart/chart-custom/chartcompile/formconfig.jsx
@@ -72,7 +72,7 @@
        {value: 'true', text: '启用'},
        {value: 'false', text: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'select',
src/menu/components/code/sandbox/options.jsx
@@ -71,7 +71,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/editor/braft-editor/options.jsx
@@ -99,7 +99,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/form/formaction/formconfig.jsx
@@ -97,6 +97,7 @@
      key: 'procMode',
      label: '参数处理',
      initVal: card.procMode || 'system',
      tooltip: '当返回值存在 mk_ex_invoke 且值为 false 时,不会调用外部接口。',
      required: true,
      options: [{
        value: 'system',
src/menu/components/form/simple-form/index.scss
@@ -6,18 +6,8 @@
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 30px;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/form/simple-form/options.jsx
@@ -179,7 +179,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'cascader',
src/menu/components/form/step-form/index.scss
@@ -6,18 +6,8 @@
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 30px;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/form/step-form/options.jsx
@@ -130,7 +130,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'cascader',
src/menu/components/form/tab-form/index.scss
@@ -6,18 +6,8 @@
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 30px;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/group/normal-group/options.jsx
@@ -109,7 +109,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'radio',
src/menu/components/group/paste/index.jsx
@@ -24,7 +24,7 @@
  pasteSubmit = () => {
    let appType = sessionStorage.getItem('appType')
    let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'dashboard', 'scatter', 'chart', 'sandbox']
    let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let types = {
      login: '登录',
      navbar: '导航栏',
@@ -37,7 +37,7 @@
    }
    if (appType !== 'mob') {
      options.push('editable', 'antvG6')
      options.push('editable', 'antvG6', 'tree', 'dashboard', 'chart')
    }
    this.pasteFormRef.handleConfirm().then(res => {
src/menu/components/iframe/index.scss
@@ -25,8 +25,7 @@
    height: 45px;
    padding-top: 5px;
    .ant-input-group-wrapper {
      width: 40%;
      max-width: 400px;
      width: 65%;
      float: right;
    }
  }
src/menu/components/iframe/options.jsx
@@ -79,7 +79,20 @@
      ],
      controlFields: [
        {field: 'linkUrl', values: ['fixed']},
        {field: 'focus', values: ['input']},
      ]
    },
    {
      type: 'radio',
      field: 'focus',
      label: '自动聚焦',
      initval: wrap.focus || 'true',
      required: false,
      options: [
        {value: 'true', label: '是'},
        {value: 'false', label: '否'},
      ],
      forbid: appType === 'mob'
    },
    {
      type: 'textarea',
@@ -107,7 +120,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/module/account/index.jsx
New file
@@ -0,0 +1,147 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover } from 'antd'
import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, CaretDownOutlined } from '@ant-design/icons'
import moment from 'moment'
import asyncIconComponent from '@/utils/asyncIconComponent'
import MKEmitter from '@/utils/events.js'
import getWrapForm from './options'
import './index.scss'
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
class Account extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
    updateConfig: PropTypes.func,
  }
  state = {
    card: null,
    date: moment().format('YYYY年MM月')
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    if (card.isNew) {
      let _card = {
        uuid: card.uuid,
        type: card.type,
        format: 'array',    // 组件属性 - 数据格式
        pageable: false,    // 组件属性 - 是否可分页
        switchable: true,   // 组件属性 - 数据是否可切换
        width: card.width || 24,
        name: '账套',
        subtype: card.subtype,
        wrap: { name: '账套', width: card.width || 24 },
        style: { paddingLeft: '20px', paddingRight: '20px', paddingTop: '10px', paddingBottom: '10px' },
      }
      this.updateComponent(_card)
    } else {
      this.setState({
        card: fromJS(card).toJS()
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  /**
   * @description 卡片行外层信息更新(数据源,样式等)
   */
  updateComponent = (card) => {
    card.width = card.wrap.width
    card.name = card.wrap.name
    this.setState({
      card: card
    })
    this.props.updateConfig(card)
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', ['background', 'border', 'padding', 'margin', 'shadow', 'clear'], card.style, this.getStyle)
  }
  getStyle = (style) => {
    let _card = {...this.state.card, style}
    this.updateComponent(_card)
  }
  getWrapForms = () => {
    const { card } = this.state
    return getWrapForm(card.wrap)
  }
  updateWrap = (res) => {
    if (res.linkmenu) {
      let list = null
      try {
        list = JSON.parse(sessionStorage.getItem('thdMenuList')) || []
      } catch (e) {
        list = []
      }
      let id = res.linkmenu[res.linkmenu.length - 1]
      res.MenuID = id
      list.forEach(item => {
        if (item.MenuID === id) {
          res.MenuName = item.MenuName
          res.MenuNo = item.MenuNo
          res.tabType = item.type
        }
      })
    }
    this.updateComponent({...this.state.card, wrap: res})
  }
  render() {
    const { card, date } = this.state
    return (
      <div className="menu-account-box" style={card.style} id={card.uuid}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <NormalForm title="基本设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
              <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
          </div>
        } trigger="hover">
          <ToolOutlined />
        </Popover>
        <div className="account-box">
          <div className="company">北京明科普华信息技术有限公司 <CaretDownOutlined /></div>
          <div className="date">{date}</div>
        </div>
      </div>
    )
  }
}
export default Account
src/menu/components/module/account/index.scss
New file
@@ -0,0 +1,52 @@
.menu-account-box {
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  color: #000000;
  .anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
    right: 1px;
    top: 1px;
    cursor: pointer;
    padding: 5px;
    background: rgba(255, 255, 255, 0.55);
  }
  .account-box {
    display: flex;
    .company {
      border: 1px solid #d9d9d9;
      padding: 3px 10px 3px 5px;
      border-radius: 4px;
      margin-right: 15px;
      overflow: hidden;
      white-space: nowrap;
      text-overflow: ellipsis;
      .anticon-caret-down {
        margin-left: 20px;
      }
    }
    .date {
      padding-top: 3px;
      flex: 1;
    }
  }
}
.menu-account-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.menu-account-box:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
src/menu/components/module/account/options.jsx
New file
@@ -0,0 +1,61 @@
/**
 * @description Wrap表单配置信息
 */
export default function (wrap) {
  let menulist = sessionStorage.getItem('fstMenuList')
  if (menulist) {
    try {
      menulist = JSON.parse(menulist)
    } catch (e) {
      menulist = []
    }
  } else {
    menulist = []
  }
  const wrapForm = [
    {
      type: 'text',
      field: 'name',
      label: '组件名称',
      initval: wrap.name || '',
      tooltip: '用于组件间的区分。',
      required: true
    },
    {
      type: 'number',
      field: 'width',
      label: '宽度',
      initval: wrap.width || 24,
      tooltip: '栅格布局,每行等分为24列。',
      min: 1,
      max: 24,
      precision: 0,
      required: true
    },
    {
      type: 'radio',
      field: 'addable',
      label: '可新增',
      initval: wrap.addable || 'false',
      required: true,
      options: [
        {value: 'true', label: '是'},
        {value: 'false', label: '否'},
      ],
      controlFields: [
        {field: 'linkmenu', values: ['true']},
      ],
    },
    {
      type: 'cascader',
      field: 'linkmenu',
      label: '关联菜单',
      initVal: wrap.linkmenu || [],
      required: true,
      options: menulist
    },
  ]
  return wrapForm
}
src/menu/components/module/voucher/index.jsx
@@ -1,18 +1,17 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Popover } from 'antd'
import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import { Popover, Button } from 'antd'
import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined, DownOutlined, CalendarOutlined } from '@ant-design/icons'
// import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import MKEmitter from '@/utils/events.js'
import getWrapForm from './options'
import VoucherTable from './voucherTable'
import './index.scss'
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
// const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
class Voucher extends Component {
  static propTpyes = {
@@ -39,9 +38,9 @@
        width: card.width || 12,
        name: '凭证',
        subtype: card.subtype,
        setting: { interType: 'system' },
        // setting: { interType: 'system' },
        wrap: { name: '凭证', title: '', width: card.width || 12, type: 'edit' },
        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px' },
        style: { marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px', paddingBottom: '20px' },
        headerStyle: {},
        columns: [],
        scripts: [],
@@ -112,7 +111,6 @@
    return (
      <div className="menu-voucher-box" style={card.style} id={card.uuid}>
        {/* <NormalHeader config={card} updateComponent={this.updateComponent}/> */}
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <NormalForm title="基本设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
@@ -125,7 +123,31 @@
          <ToolOutlined />
        </Popover>
        <div className="voucher-box">
          jjj
          <div className="voucher-header">
            <Button className="add-background header-btn">新增</Button>
            <Button className="add-background header-btn">保存</Button>
            <Button className="print-background header-btn">打印</Button>
            <Button className="system-background header-btn">导入</Button>
            <Button className="out-background header-btn">导出</Button>
          </div>
          <div className="voucher-body">
          <div className="pre-wrap">
            <div className="voucher-code">
              <div>记<DownOutlined/></div>
              <div>1</div>
              号
            </div>
            <div className="voucher-date">
              日期:<div>请选择日期 <CalendarOutlined /></div>
            </div>
            <div className="voucher-affix">
              附单据 <div>2</div> 张
              <Button type="link" className="">附件</Button>
              <Button type="link" className="">备注</Button>
            </div>
          </div>
          <VoucherTable config={card}/>
        </div>
        </div>
      </div>
    )
src/menu/components/module/voucher/index.scss
@@ -18,12 +18,97 @@
    padding: 5px;
    background: rgba(255, 255, 255, 0.55);
  }
  .empty-content {
    text-align: center;
    font-size: 30px;
    margin: 0;
    line-height: 90px;
    color: #bcbcbc;
  .voucher-header {
    padding: 10px;
    border-bottom: 1px solid #eeeeee;
    .header-btn {
      height: 28px;
      min-width: 80px;
      margin-right: 10px;
    }
  }
  .voucher-body {
    padding: 0 15px;
    .voucher-code {
      display: inline-block;
      width: 160px;
      margin-right: 15px;
      div {
        display: inline-block;
        min-width: 50px;
        margin-right: 10px;
        border: 1px solid #d9d9d9;
        padding: 4px 10px;
        border-radius: 4px;
        .anticon-down {
          position: relative;
          left: 3px;
          color: #c8c8c8;
          font-size: 12px;
          margin-left: 5px;
        }
      }
    }
    .pre-wrap {
      padding: 10px 0px;
    }
    .voucher-date {
      display: inline-block;
      div {
        display: inline-block;
        min-width: 50px;
        margin-right: 10px;
        border: 1px solid #d9d9d9;
        padding: 4px 10px;
        border-radius: 4px;
        color: #c8c8c8;
        .anticon {
          position: relative;
          left: 3px;
          color: #c8c8c8;
          margin-left: 5px;
        }
      }
    }
    .voucher-affix {
      float: right;
      width: 250px;
      div {
        display: inline-block;
        min-width: 50px;
        margin-right: 10px;
        border: 1px solid #d9d9d9;
        padding: 4px 10px;
        border-radius: 4px;
      }
    }
  }
  .add-background {
    background: #26C281;
    border-color: #26C281;
    color: #ffffff;
  }
  .print-background {
    background-color: #8E44AD;
    border-color: #8E44AD;
    color: #ffffff;
  }
  .out-background {
    background-color: rgb(50, 197, 210);
    border-color: rgb(50, 197, 210);
    color: #ffffff;
  }
  .system-background {
    background: #1890ff;
    border-color: #1890ff;
    color: #ffffff;
  }
}
.menu-voucher-box::after {
src/menu/components/module/voucher/options.jsx
@@ -4,21 +4,21 @@
 * @description Wrap表单配置信息
 */
export default function (wrap, id) {
  let roleList = sessionStorage.getItem('sysRoles')
  let appType = sessionStorage.getItem('appType')
  let menu = window.GLOB.customMenu
  let modules = MenuUtils.getSupModules(menu.components, id, menu.interfaces)
  if (roleList) {
    try {
      roleList = JSON.parse(roleList)
    } catch (e) {
      roleList = []
  let books = []
  let bookids = []
  menu.components.forEach(item => {
    if (item.subtype === 'account') {
      books.push({
        value: item.uuid,
        label: item.name
      })
      bookids.push(item.uuid)
    }
  } else {
    roleList = []
  }
  })
  modules = modules.filter(item => !bookids.includes(item.value))
  const wrapForm = [
    // {
@@ -59,6 +59,15 @@
      required: true
    },
    {
      type: 'select',
      field: 'supBook',
      label: '账套',
      initval: wrap.supBook || '',
      required: true,
      options: books,
      allowClear: true
    },
    {
      type: 'cascader',
      field: 'supModule',
      label: '上级组件',
@@ -66,15 +75,6 @@
      required: false,
      options: modules,
      allowClear: true,
    },
    {
      type: 'multiselect',
      field: 'blacklist',
      label: '黑名单',
      initval: wrap.blacklist || [],
      required: false,
      options: roleList,
      forbid: !!appType
    },
  ]
src/menu/components/module/voucher/voucherTable/index.jsx
New file
@@ -0,0 +1,361 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Table } from 'antd'
import Utils from '@/utils/utils.js'
import './index.scss'
class BodyRow extends React.Component {
  render() {
    let { data, ...resProps } = this.props
    let style = {}
    let className = ''
    return <tr {...resProps} className={className} style={style}/>
  }
}
class BodyCell extends React.Component {
  state = {}
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  render() {
    let { col, record, className } = this.props
    let children = null
    let colSpan = 1
    if (col.field === 'remark') {
      let val = record.remark || ''
      if (record.type === 'total') {
        children = <div className="content-wrap" style={{lineHeight: '60px'}}>合计: {val}</div>
        colSpan = 2
      } else {
        children = <div className="content-wrap">{val}</div>
      }
    } else if (col.field === 'subject') {
      if (record.type === 'total') {
        colSpan = 0
      } else {
        let val = record.subject || ''
        children = <div className="content-wrap">{val}</div>
      }
    } else if (col.field === 'debtor') {
      let val = record.debtor
      let down = false
      let vals = []
      if (typeof(val) === 'number') {
        if (val < 0) {
          down = true
          val = Math.abs(val)
        }
        vals = (val * 100).toFixed(0).split('').reverse()
      }
      children = <div className={'money-uint' + (down ? ' down' : '')}>
        <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
        <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
      </div>
    } else if (col.field === 'creditor') {
      let val = record.creditor
      let down = false
      let vals = []
      if (typeof(val) === 'number') {
        if (val < 0) {
          down = true
          val = Math.abs(val)
        }
        vals = (val * 100).toFixed(0).split('').reverse()
      }
      children = <div className={'money-uint' + (down ? ' down' : '')}>
        <span>{vals[10] || ''}</span> <span>{vals[9] || ''}</span> <span>{vals[8] || ''}</span> <span>{vals[7] || ''}</span> <span>{vals[6] || ''}</span> <span>{vals[5] || ''}</span>
        <span>{vals[4] || ''}</span> <span>{vals[3] || ''}</span> <span>{vals[2] || ''}</span> <span>{vals[1] || ''}</span> <span className="last">{vals[0] || ''}</span>
      </div>
    }
    if (!colSpan) return null
    return (<td colSpan={colSpan} className={className}>{children}</td>)
  }
}
class VoucherTable extends Component {
  static propTpyes = {
    config: PropTypes.object,        // 菜单Id
    BID: PropTypes.any,              // 主表ID
    total: PropTypes.any,            // 总数
    loading: PropTypes.bool,         // 表格加载中
    refreshdata: PropTypes.func,     // 表格中排序列、页码的变化时刷新
  }
  state = {
    data: [],
    edData: [],
    edColumns: [],
    tableId: '',          // 表格ID
    pageSize: 10,         // 每页数据条数
    columns: null,        // 显示列
    loading: false,
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    let data = [
      {remark: '提现', subject: '1001 库存现金', debtor: 124, creditor: ''},
      {remark: '购入固定资产', subject: '1001 库存现金', debtor: '', creditor: 124},
      {remark: '转结销售成本', subject: '1001 库存现金', debtor: -524, creditor: ''},
      {remark: '提现', subject: '1001 库存现金', debtor: 34, creditor: ''},
    ]
    data = this.initData(data)
    data.push(this.getTotalLine(data))
    let columns = [
      {
        title: '摘要',
        dataIndex: 'remark',
        key: 'remark',
        width: '22%',
        onCell: record => ({
          record,
          col: {uuid: 'remark', field: 'remark', tableId: config.uuid},
        })
      },
      {
        title: '会计科目',
        dataIndex: 'subject',
        key: 'subject',
        width: '34%',
        onCell: record => ({
          record,
          col: {uuid: 'subject', field: 'subject', tableId: config.uuid},
        })
      },
      {
        title: () => (<>
          <div className="money-title">借方金额</div>
          <div className="money-uint">
            <span>亿</span> <span>千</span> <span>百</span> <span>十</span> <span>万</span> <span>千</span>
            <span>百</span> <span>十</span> <span>元</span> <span>角</span> <span className="last">分</span>
          </div>
        </>),
        dataIndex: 'debtor',
        key: 'debtor',
        width: '22%',
        onCell: record => ({
          record,
          col: {uuid: 'debtor', field: 'debtor', tableId: config.uuid},
        })
      },
      {
        title: () => (<>
          <div className="money-title">贷方金额</div>
          <div className="money-uint">
            <span>亿</span> <span>千</span> <span>百</span> <span>十</span> <span>万</span> <span>千</span>
            <span>百</span> <span>十</span> <span>元</span> <span>角</span> <span className="last">分</span>
          </div>
        </>),
        dataIndex: 'creditor',
        key: 'creditor',
        width: '22%',
        onCell: record => ({
          record,
          col: {uuid: 'creditor', field: 'creditor', tableId: config.uuid},
        })
      }
    ]
    this.setState({
      data: data,
      edData: fromJS(data).toJS(),
      columns,
      tableId: config.uuid
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  initData = (data) => {
    let _data = data.map((item, i) => {
      item.uuid = Utils.getuuid()
      item.index = i
      return item
    })
    if (_data.length < 4) {
      for (let i = _data.length - 1; i < 4; i++) {
        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
      }
    }
    return _data
  }
  getTotalLine = (data) => {
    let totalLine = {uuid: Utils.getuuid(), type: 'total'}
    let debtor = ''
    let creditor = ''
    data.forEach(item => {
      if (typeof(item.debtor) === 'number') {
        if (debtor === '') {
          debtor = 0
        }
        debtor += item.debtor
      } else if (typeof(item.creditor) === 'number') {
        if (debtor === '') {
          debtor = 0
        }
        if (creditor === '') {
          creditor = 0
        }
        creditor += item.creditor
      }
    })
    totalLine.debtor = debtor
    totalLine.creditor = creditor
    totalLine.remark = this.changeMoneyToChinese(debtor)
    return totalLine
  }
  changeMoneyToChinese = (money) => {
    let cnNums = ['零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖']
    let cnIntRadice = ['', '拾', '佰', '仟']
    let cnIntUnits = ['', '万', '亿', '兆']
    let cnDecUnits = ['角', '分', '毫', '厘']
    let cnInteger = '整'
    let cnIntLast = '元'
    let maxNum = 999999999999999.9999 // 最大处理的数字
    let IntegerNum = null
    let DecimalNum = null
    let ChineseStr = ''
    let parts = null // 分离金额后用的数组,预定义
    let Symbol = ''  // 正负值标记
    if (money === '') return ''
    if (money >= maxNum) return '超出最大处理数字'
    if (money === 0) {
      ChineseStr = cnNums[0] + cnIntLast + cnInteger;
      return ChineseStr
    }
    if(money < 0) {
      money = -money
      Symbol = '负'
    }
    money = money.toString() // 转换为字符串
    if (money.indexOf('.') === -1) {
      IntegerNum = money
      DecimalNum = ''
    } else {
      parts = money.split('.')
      IntegerNum = parts[0]
      DecimalNum = parts[1].substr(0, 4)
    }
    if (parseInt(IntegerNum, 10) > 0) { // 获取整型部分转换
      let zeroCount = 0
      let IntLen = IntegerNum.length
      for (let i = 0; i < IntLen; i++) {
        let n = IntegerNum.substr(i, 1)
        let p = IntLen - i - 1
        let q = p / 4
        let m = p % 4
        if (n === '0') {
          zeroCount++
        } else {
          if (zeroCount > 0) {
            ChineseStr += cnNums[0]
          }
          zeroCount = 0 // 归零
          ChineseStr += cnNums[parseInt(n)] + cnIntRadice[m]
        }
        if (m === 0 && zeroCount < 4) {
          ChineseStr += cnIntUnits[q]
        }
      }
      ChineseStr += cnIntLast
    }
    if (DecimalNum !== '') { // 小数部分
      let decLen = DecimalNum.length
      for (let i = 0; i < decLen; i++) {
        let n = DecimalNum.substr(i, 1)
        if (n !== '0') {
          ChineseStr += cnNums[Number(n)] + cnDecUnits[i]
        }
      }
    }
    if (ChineseStr === '') {
      ChineseStr += cnNums[0] + cnIntLast + cnInteger
    } else if (DecimalNum === '') {
      ChineseStr += cnInteger
    }
    ChineseStr = Symbol + ChineseStr
    return ChineseStr
  }
  render() {
    const { edData, columns} = this.state
    const components = {
      body: {
        row: BodyRow,
        cell: BodyCell
      }
    }
    return (
      <div className="voucher-table-wrap">
        <Table
          rowKey="uuid"
          components={components}
          columns={columns}
          dataSource={edData}
          bordered={true}
          onRow={(record, index) => {
            return {
              data: record
            }
          }}
          pagination={false}
        />
      </div>
    )
  }
}
export default VoucherTable
src/menu/components/module/voucher/voucherTable/index.scss
New file
@@ -0,0 +1,259 @@
.voucher-table-wrap {
  position: relative;
  padding: 0px;
  .normal-table-footer {
    padding: 10px 0px;
    color: rgba(0, 0, 0, 0.65);
  }
  .normal-table-footer.pagination {
    position: absolute;
    bottom: 10px;
  }
  >.ant-table-wrapper {
    position: relative;
    z-index: 1;
  }
  .ant-table {
    color: inherit;
    font-size: inherit;
  }
  .money-uint {
    display: flex;
    span {
      display: inline-block;
      flex: 1;
      text-align: center;
      font-size: 12px;
    }
    span:not(.last) {
      border-right: 1px solid #e9e9e9;
    }
    span:nth-child(3), span:nth-child(6) {
      border-color: #91d5ff;
    }
    span:nth-child(9) {
      border-color: #ffa39e;
    }
  }
  table {
    max-width: 100%;
    width: 100%;
    .ant-table-thead {
      tr {
        th {
          position: relative;
          background-color: transparent;
          padding: 0;
          height: 60px;
          line-height: 60px;
          text-align: center;
          .ant-table-header-column {
            display: block;
            width: 100%;
            height: 100%;
            .ant-table-column-title {
              display: block;
              width: 100%;
              height: 100%;
              font-weight: bold;
              font-size: 13px;
            }
          }
          .money-title {
            line-height: 30px;
            font-weight: bold;
            font-size: 13px;
          }
          .money-uint {
            line-height: 30px;
            border-top: 1px solid #dadada;
          }
        }
      }
    }
    .ant-table-selection-column {
      width: 60px;
      min-width: 60px;
      max-width: 60px;
    }
    .ant-table-tbody {
      tr td {
        position: relative;
        background-color: transparent;
        padding: 0;
        height: 60px;
        vertical-align: top;
        .content-wrap {
          padding: 5px;
          height: 100%;
          font-size: 13px;
          font-weight: bold;
        }
        .money-uint {
          height: 100%;
          line-height: 60px;
          span {
            font-size: 14px;
            font-weight: bold;
          }
        }
        .money-uint.down {
          span {
            color: #ff4d4f;
          }
        }
      }
    }
  }
  .ant-input {
    height: 60px;
    border-radius: 0;
    resize: none;
  }
  .ant-input-number {
    height: 60px;
    border-radius: 0;
    .ant-input-number-handler-wrap {
      display: none;
    }
    .ant-input-number-input {
      border-radius: 0;
      height: 60px;
    }
  }
  .editing_table_cell {
    .ant-input {
      padding: 0px;
      position: absolute;
      top: 0px;
      left: 0px;
      right: 0px;
      bottom: 0px;
      border: 1px solid #1890ff;
    }
    .ant-input-number-input {
      position: absolute;
      top: 0px;
      left: 0px;
      right: 0px;
      bottom: 0px;
      border: 1px solid #1890ff;
    }
    .anticon {
      color: #ff4d4f;
      position: absolute;
      right: 3px;
      top: calc(50% - 8px);
    }
  }
  td.pointer {
    position: relative;
  }
  td.pointer {
    .mk-mask {
      display: none;
      cursor: pointer;
      position: absolute;
      top: 0;
      left: 0;
      bottom: 0;
      right: 0;
    }
  }
}
.edit-custom-table.editable {
  td {
    background-color: #ffffff!important;
  }
  td.pointer .mk-mask {
    display: block;
  }
  .mk-operation {
    display: none;
  }
  .ant-table-placeholder {
    display: none;
  }
}
.edit-custom-table:not(.fixed-height) {
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
  }
  ::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  ::-webkit-scrollbar-track {/*滚动条里面轨道*/
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
}
.edit-custom-table.fixed-height {
  .ant-table-body {
    border-bottom: 1px solid rgba(0, 0, 0, .05);
    .ant-table-fixed {
      border-bottom: 0;
    }
  }
}
.edit-custom-table.hidden {
  thead {
    display: none;
  }
}
.edit-custom-table.ghost {
  .ant-table-thead > tr {
    > th {
      color: inherit;
      background: transparent;
      .ant-table-column-sorter .ant-table-column-sorter-inner {
        color: inherit;
      }
    }
    > th:hover {
      background: transparent;
    }
  }
  .ant-table-body {
    overflow-x: auto;
    tr {
      td {
        background: transparent!important;
      }
    }
    tr:hover td {
      background: transparent!important;
    }
  }
}
.image-scale-modal {
  width: 70vw;
  min-height: 80vh;
  top: 10vh;
  .ant-modal-body {
    min-height: calc(80vh - 110px);
    line-height: calc(80vh - 160px);
    text-align: center;
  }
  .ant-modal-footer {
    text-align: center;
    span {
      display: inline-block;
      color: #1890ff;
      padding: 5px 15px;
      cursor: pointer;
    }
  }
}
src/menu/components/search/main-search/index.jsx
@@ -207,7 +207,6 @@
    this.searchFormRef.handleConfirm().then(res => {
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      card.search = card.search.map(item => { // 数据更新及重复检测
        if (item.uuid !== res.uuid && res.field && item.field) {
@@ -233,8 +232,6 @@
          if (setFields.length < itemFields.length + resFields.length && (res.type !== 'date' || item.type !== 'date')) {
            fieldrepet = true
          } else if (item.label === res.label) {
            labelrepet = true
          }
        }
@@ -249,13 +246,6 @@
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 5
        })
        return
      } else if (labelrepet) {
        notification.warning({
          top: 92,
          message: '名称已存在!',
          duration: 5
        })
        return
src/menu/components/search/main-search/index.scss
@@ -102,6 +102,9 @@
    }
  }
  .mk-search-item-wrap.action {
    .ant-form-item {
      white-space: nowrap;
    }
    .ant-form-item-label, .ant-form-item-control-wrapper {
      display: inline-block;
    }
src/menu/components/search/main-search/options.jsx
@@ -54,7 +54,7 @@
    {
      type: 'radio',
      field: 'drawerPlacement',
      label: '抽屉方向',
      label: '弹出方向',
      initval: wrap.drawerPlacement || 'right',
      required: false,
      options: [
@@ -129,7 +129,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -18,7 +18,7 @@
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'swipe', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'anchors', 'width', 'openmenu', 'refreshTab', 'hidden'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'width', 'hidden'],
  excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'color', 'execSuccess', 'execError', 'syncComponent', 'switchTab', 'pagination', 'search', 'width', 'hidden'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'hidden'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'popClose', 'width', 'display', 'ratio', 'syncComponent', 'clickouter', 'maskStyle', 'closeButton', 'hidden'],
  tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'color', 'linkmenu', 'width', 'hidden'],
  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'swipe', 'icon', 'class', 'color', 'width', 'hidden'],
@@ -241,7 +241,7 @@
      if (this.record.formType === 'switch') {
        shows.push('field', 'size', 'openVal', 'closeVal', 'openText', 'closeText')
      } else if (this.record.formType === 'radio') {
        shows.push('field', 'openVal', 'closeVal')
        shows.push('field', 'checkType', 'openVal', 'closeVal')
      } else {
        shows.push('field')
      }
@@ -356,7 +356,9 @@
    } else if (openType === 'popview') {
      reOptions.Ot = requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value))
      if (this.record.display === 'drawer') {
      if (appType === 'mob') {
        shows.push('placement')
      } else if (this.record.display === 'drawer') {
        shows.push('placement')
      }
      if (this.record.popClose === 'grid') {
@@ -419,6 +421,9 @@
        }
        if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
          shows.push('resetPageIndex')
        }
        if (this.record.execMode === 'pop' || this.record.execMode === 'prompt') {
          shows.push('position')
        }
      } else if (_funcType === 'mkBinding' || _funcType === 'mkUnBinding') {
        shows.push('execSuccess', 'execError')
@@ -549,14 +554,13 @@
      } else if (value === 'excelIn') {
        _fieldval.intertype = 'system'
        _fieldval.Ot = 'notRequired'
        _fieldval.execSuccess = 'grid'
        _fieldval.label = '导入Excel'
        _fieldval.class = 'dgreen'
        this.record.Ot = 'notRequired'
        this.record.label = '导入Excel'
        this.record.class = 'dgreen'
        this.record.execSuccess = 'grid'
      } else if (value === 'excelOut') {
        _fieldval.intertype = 'system'
        _fieldval.label = '导出Excel'
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -126,8 +126,9 @@
    }
  }
  if (appType === 'mob') {
    opentypes = opentypes.filter(item => ['pop', 'prompt', 'exec', 'excelOut', 'innerpage', 'funcbutton'].includes(item.value))
    opentypes = opentypes.filter(item => ['pop', 'prompt', 'exec', 'excelOut', 'popview', 'innerpage', 'funcbutton'].includes(item.value))
    funTypes = [
      { value: 'print', text: '标签打印' },
      { value: 'scan', text: '扫码' },
      { value: 'pay', text: '支付' },
      { value: 'refund', text: '退款' },
@@ -147,7 +148,7 @@
  } else if (appType === 'pc') {
    opentypes = opentypes.filter(item => item.value !== 'tab')
    funTypes = [
      { value: 'refund', text: '退款' },
      { value: 'print', text: '标签打印' },
      { value: 'changeuser', text: '切换用户' },
    ]
    pageTemps = [
@@ -311,6 +312,7 @@
      key: 'procMode',
      label: '参数处理',
      initVal: card.procMode || (card.innerFunc ? 'inner' : 'system'),
      tooltip: '当返回值存在 mk_ex_invoke 且值为 false 时,不会调用外部接口。',
      required: true,
      options: [{
        value: 'system',
@@ -827,23 +829,13 @@
      }, {
        value: 'drawer',
        text: '抽屉'
      }]
    },
    {
      type: 'number',
      key: 'ratio',
      min: 1,
      max: 3000,
      precision: 0,
      label: '比例',
      initVal: card.ratio || 85,
      tooltip: '模态框或抽屉的宽度,小于100为窗口宽度(或高度)百分比,大于100为像素值。',
      required: true
      }],
      forbid: appType === 'mob',
    },
    {
      type: 'radio',
      key: 'placement',
      label: '抽屉方向',
      label: '弹出方向',
      initVal: card.placement || 'right',
      required: false,
      options: [{
@@ -861,6 +853,17 @@
      }]
    },
    {
      type: 'number',
      key: 'ratio',
      min: 1,
      max: 3000,
      precision: 0,
      label: '比例',
      initVal: card.ratio || 85,
      tooltip: '模态框或抽屉的宽度,小于100为窗口宽度(或高度)百分比,大于100为像素值。',
      required: true
    },
    {
      type: 'radio',
      key: 'clickouter',
      label: '点击蒙层',
@@ -873,6 +876,36 @@
        value: 'close',
        text: '关闭'
      }]
    },
    {
      type: 'radio',
      key: 'maskStyle',
      label: '蒙层样式',
      initVal: card.maskStyle || 'default',
      required: false,
      options: [{
        value: 'default',
        text: '默认'
      }, {
        value: 'transparent',
        text: '透明'
      }],
      forbid: appType !== 'mob'
    },
    {
      type: 'radio',
      key: 'closeButton',
      label: '关闭按钮',
      initVal: card.closeButton || 'false',
      required: false,
      options: [{
        value: 'false',
        text: '隐藏'
      }, {
        value: 'true',
        text: '显示'
      }],
      forbid: appType !== 'mob'
    },
    {
      type: 'radio',
@@ -995,6 +1028,19 @@
      }, {
        value: 'small',
        text: '小'
      }]
    },
    {
      type: 'radio',
      key: 'checkType',
      label: '选框样式',
      initVal: card.checkType || 'circle',
      options: [{
        value: 'circle',
        text: '圆角'
      }, {
        value: 'square',
        text: '方角'
      }]
    },
    {
@@ -1211,6 +1257,7 @@
      key: 'procMode',
      label: '参数处理',
      initVal: card.procMode || (card.innerFunc ? 'inner' : 'system'),
      tooltip: '当返回值存在 mk_ex_invoke 且值为 false 时,不会调用外部接口。',
      required: true,
      options: [{
        value: 'system',
@@ -1662,7 +1709,7 @@
    {
      type: 'radio',
      key: 'placement',
      label: '抽屉方向',
      label: '弹出方向',
      initVal: card.placement || 'right',
      required: false,
      options: [{
src/menu/components/share/markcomponent/index.jsx
@@ -9,7 +9,6 @@
import MarkForm from './markform'
import MkIcon from '@/components/mk-icon'
import { minkeIconSystem } from '@/utils/option.js'
import '@/assets/css/table.scss'
import './index.scss'
const EditTable = asyncComponent(() => import('@/templates/zshare/editTable'))
src/menu/components/share/searchcomponent/index.jsx
@@ -153,7 +153,6 @@
    this.searchFormRef.handleConfirm().then(res => {
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      _searchlist = _searchlist.filter(item => !item.origin || item.uuid === res.uuid) // 去除系统项
@@ -181,8 +180,6 @@
          if (setFields.length < itemFields.length + resFields.length && (res.type !== 'date' || item.type !== 'date')) {
            fieldrepet = true
          } else if (item.label === res.label) {
            labelrepet = true
          }
        }
@@ -197,13 +194,6 @@
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 5
        })
        return
      } else if (labelrepet) {
        notification.warning({
          top: 92,
          message: '名称已存在!',
          duration: 5
        })
        return
src/menu/components/table/base-table/columns/index.jsx
@@ -3,7 +3,7 @@
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Popover, Modal, message, notification } from 'antd'
import { PlusOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined } from '@ant-design/icons'
import { PlusOutlined, EditOutlined, CopyOutlined, DeleteOutlined, FontColorsOutlined, CloseCircleOutlined, AntDesignOutlined, InfoOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
@@ -68,7 +68,7 @@
              }
              <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} />
              {column && column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
              {column && column.type === 'custom' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
              {column && (column.type === 'custom' || column.type === 'action') ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
              <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} />
              {column && ['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
            </div>
@@ -140,6 +140,34 @@
  }))(HeaderCol),
)
class HeaderEmptyCol extends Component {
  render() {
    const { connectDragSource, connectDropTarget } = this.props
    return connectDragSource(
      connectDropTarget(<div style={{border: '1px solid #e8e8e8', textAlign: 'center', height: '100px', lineHeight: '100px', color: '#bcbcbc'}}>请添加显示列</div>)
    )
  }
}
const ColEmptyTarget = {
  drop(props, monitor) {
    const item = monitor.getItem()
    if (item.$init) {
      props.dropCol(item, 0)
    }
  }
}
const DragableEmptyCol = DropTarget('col', ColEmptyTarget, connect => ({
  connectDropTarget: connect.dropTarget()
}))(
  DragSource('col', rowSource, connect => ({
    connectDragSource: connect.dragSource(),
  }))(HeaderEmptyCol)
)
class EditableColumnCell extends Component {
  updateCard = (vals, btn) => {
    const { column } = this.props
@@ -167,7 +195,7 @@
      )
    } else if (column && column.type === 'action') {
      return (
        <td style={{padding: '0 5px', textAlign: column.Align}} className={'action-column ' + className}>
        <td style={{padding: 0, textAlign: column.Align, ...(column.style || {})}} className={'action-column ' + className}>
          <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
        </td>
      )
@@ -396,8 +424,10 @@
    if (col.type === 'colspan') {
      col.subcols = card.subcols || []
    } else if (col.type === 'custom') {
      col.style = card.style || {}
      col.elements = card.type === 'custom' ? (card.elements || []) : []
    } else if (col.type === 'action') {
      col.style = card.style || {}
      col.elements = card.type === 'action' ? (card.elements || []) : []
    }
@@ -560,6 +590,27 @@
    })
  }
  copyFields = () => {
    const { config } = this.props
    let m = []
    let n = []
    config.columns.forEach(col => {
      m.push(`${col.field}(${col.label})`)
      n.push(col.field)
    })
    let oInput = document.createElement('input')
    oInput.value = `/*${m.join(',')}*/
      ${n.join(',')}`
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    document.body.removeChild(oInput)
    message.success('复制成功。')
  }
  componentDidMount () {
    MKEmitter.addListener('plusColumns', this.plusColumns)
  }
@@ -599,11 +650,12 @@
    }
    return (
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''}`} id={tableId}>
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
        <div className="col-control">
          <FieldsComponent config={config} type="columns" />
          <CopyOutlined title="复制显示列" onClick={this.copycolumn} />
          <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
          <InfoOutlined title="复制字段" style={{color: 'orange'}} onClick={this.copyFields}/>
        </div>
        <DndProvider>
          {groups ? groups.map((group, i) => {
@@ -626,7 +678,7 @@
              } : false}
            />
          }) :
          <Table
          (columns.length === 0 ? <DragableEmptyCol dropCol={this.dropCol}/> : <Table
            rowKey="uuid"
            size={config.wrap.size || 'middle'}
            bordered={config.wrap.bordered !== 'false'}
@@ -642,7 +694,7 @@
              total: 58,
              showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
            }}
          />}
          />)}
        </DndProvider>
        <EditColumn column={card} fields={fields} submitCol={this.submitCol} cancelCol={this.cancelCol}/>
      </div>
src/menu/components/table/base-table/columns/index.scss
@@ -105,16 +105,17 @@
  }
  table tr {
    th .ant-table-column-title {
      // color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
    td {
      color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
  }
  table tbody tr {
    color: var(--mk-table-color);
  }
}
.normal-table-columns.false {
  .ant-pagination {
src/menu/components/table/base-table/index.jsx
@@ -99,6 +99,39 @@
    MKEmitter.removeListener('completeSave', this.completeSave)
  }
  // updateFix = (card) => {
  //   let fixs = {}
  //   card.cols.forEach(col => {
  //     if (!col.field) return
  //     if (col.postfix || col.prefix) {
  //       fixs[col.field] = col
  //     }
  //   })
  //   card.cols.forEach(col => {
  //     if (col.type === 'custom') {
  //       col.elements.forEach(cell => {
  //         if (cell.datatype === 'dynamic') {
  //           cell.height = ''
  //           cell.innerHeight = 'auto'
  //           if (fixs[cell.field]) {
  //             if (!cell.prefix && fixs[cell.field].prefix) {
  //               cell.prefix = fixs[cell.field].prefix
  //             }
  //             if (!cell.postfix && fixs[cell.field].postfix) {
  //               cell.postfix = fixs[cell.field].postfix
  //             }
  //           }
  //         }
  //       })
  //     }
  //   })
  //   return card
  // }
  completeSave = () => {
    const { card } = this.state
src/menu/components/table/base-table/options.jsx
@@ -55,18 +55,32 @@
      ]
    },
    {
      type: 'radio',
      type: 'select',
      field: 'selected',
      label: '首行选中',
      label: '数据选中',
      initval: wrap.selected || 'false',
      tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。',
      tooltip: '初始化:数据加载时选中首行数据,仅执行一次。数据加载:每次数据加载时均选中首行(当按钮执行完成并返回主键值时,默认选中主键值对应行)。选中标记:返回数据中存在 selected 字段,且值为 true 的数据被选中。注:启用无人值守时无效。',
      required: false,
      options: [
        {value: 'false', label: '无'},
        {value: 'init', label: '初始化'},
        {value: 'always', label: '数据加载'},
      ]
        {value: 'sign', label: '选中标记'}
      ],
    },
    // {
    //   type: 'radio',
    //   field: 'selected',
    //   label: '首行选中',
    //   initval: wrap.selected || 'false',
    //   tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。',
    //   required: false,
    //   options: [
    //     {value: 'false', label: '无'},
    //     {value: 'init', label: '初始化'},
    //     {value: 'always', label: '数据加载'},
    //   ]
    // },
    {
      type: 'radio',
      field: 'tableMode',
@@ -100,6 +114,30 @@
      required: false
    },
    {
      type: 'radio',
      field: 'vertical',
      label: '垂直对齐',
      initval: wrap.vertical || 'middle',
      tooltip: '单元格的垂直对齐方式。',
      required: false,
      options: [
        {value: 'top', label: '向上'},
        {value: 'middle', label: '居中'},
        {value: 'bottom', label: '向下'},
      ]
    },
    {
      type: 'number',
      field: 'btnlimit',
      label: '按钮限制',
      initval: wrap.btnlimit || '',
      tooltip: '按钮数量限制,超出的按钮会在更多中下拉显示,注:更多中的按钮不要绑定双击事件。',
      min: 3,
      max: 3000,
      precision: 0,
      required: false
    },
    {
      type: 'number',
      field: 'height',
      label: '表格高度',
src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -214,7 +214,11 @@
    let resource = this.props.form.getFieldValue('dataSource') || ''
    resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    if (field === text) {
      resource = `select '' as ${field} union all \n${resource}`
    } else {
      resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    }
    this.props.form.setFieldsValue({dataSource: resource})
  }
src/menu/components/table/edit-table/columns/index.jsx
@@ -75,7 +75,7 @@
            <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} />
            {column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
            {column.type === 'action' ? <PasteComponent options={['action']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
            {column.type === 'custom' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
            {column.type === 'custom' || column.type === 'action' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
            <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} />
            {['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
          </div>
@@ -148,7 +148,7 @@
      )
    } else if (column && column.type === 'action') {
      return (
        <td style={{padding: '0 5px', textAlign: column.Align}} className={'action-column ' + className}>
        <td style={{padding: 0, textAlign: column.Align, ...(column.style || {})}} className={'action-column ' + className}>
          <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
        </td>
      )
@@ -359,8 +359,10 @@
    const { card } = this.state
    
    if (col.type === 'custom') {
      col.style = card.style || {}
      col.elements = card.type === 'custom' ? (card.elements || []) : []
    } else if (col.type === 'action') {
      col.style = card.style || {}
      col.elements = card.type === 'action' ? (card.elements || []) : []
    }
@@ -592,7 +594,7 @@
    })
    return (
      <div className={`edit-table-columns ${config.setting.laypage} ${config.wrap.mode || ''}`} id={tableId}>
      <div className={`edit-table-columns ${config.setting.laypage} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
        <div className="col-control">
          <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
src/menu/components/table/edit-table/columns/index.scss
@@ -32,6 +32,7 @@
        .col-copy {
          margin-bottom: 0;
          display: inline-block;
          color: inherit;
          .ant-typography-copy {
            position: absolute;
            left: 2px;
@@ -132,16 +133,17 @@
  }
  table tr {
    th .ant-table-column-title, th .ant-table-column-title > span {
      // color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
    td {
      color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
  }
  table tbody tr {
    color: var(--mk-table-color);
  }
}
.edit-table-columns.false {
  .ant-pagination {
src/menu/components/table/edit-table/options.jsx
@@ -225,6 +225,19 @@
      tooltip: '默认值 #e8e8e8。',
      required: false
    },
    {
      type: 'radio',
      field: 'vertical',
      label: '垂直对齐',
      initval: wrap.vertical || 'middle',
      tooltip: '单元格的垂直对齐方式。',
      required: false,
      options: [
        {value: 'top', label: '向上'},
        {value: 'middle', label: '居中'},
        {value: 'bottom', label: '向下'},
      ]
    },
    // {
    //   type: 'color',
    //   field: 'color',
@@ -264,7 +277,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/table/normal-table/columns/index.jsx
@@ -70,7 +70,7 @@
              <EditOutlined className="edit" title="编辑" onClick={() => this.props.editColumn(column)} />
              {column && column.type === 'custom' ? <PasteComponent options={['customCardElement']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
              {column && column.type === 'action' ? <PasteComponent options={['action']} updateConfig={(res, resolve) => this.props.pasteCell(column, res, resolve)} /> : null}
              {column && column.type === 'custom' ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
              {column && (column.type === 'custom' || column.type === 'action') ? <FontColorsOutlined className="style" title="调整样式" onClick={() => this.props.changeStyle(column)}/> : null}
              <DeleteOutlined className="close" title="删除" onClick={this.deleteCol} />
              {column && ['text', 'number', 'formula'].includes(column.type) ? <MarkColumn field={column.field || ''} columns={fields} marks={column.marks} onSubmit={this.updateMarks} /> : null }
            </div>
@@ -170,7 +170,7 @@
      )
    } else if (column && column.type === 'action') {
      return (
        <td style={{padding: '0 5px', textAlign: column.Align}} className={'action-column ' + className}>
        <td style={{padding: 0, textAlign: column.Align, ...(column.style || {})}} className={'action-column ' + className}>
          <CardCellComponent cards={config} cardCell={column} elements={column.elements} updateElement={this.updateCard}/>
        </td>
      )
@@ -400,8 +400,10 @@
    if (col.type === 'colspan') {
      col.subcols = card.subcols || []
    } else if (col.type === 'custom') {
      col.style = card.style || {}
      col.elements = card.type === 'custom' ? (card.elements || []) : []
    } else if (col.type === 'action') {
      col.style = card.style || {}
      col.elements = card.type === 'action' ? (card.elements || []) : []
    }
@@ -605,7 +607,7 @@
    const columns = this.handlecolumns(this.state.columns, fields, config)
    return (
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''}`} id={tableId}>
      <div className={`normal-table-columns ${config.setting.laypage} ${config.wrap.tableType} ${config.wrap.mode || ''} table-vertical-${config.wrap.vertical || ''}`} id={tableId}>
        <div className="col-control">
          <CopyOutlined title="复制显示列" onClick={this.copycolumn} />
          <MarkColumn columns={fields} type="line" marks={lineMarks} onSubmit={this.updateLineMarks} />
src/menu/components/table/normal-table/columns/index.scss
@@ -23,6 +23,7 @@
        .col-copy {
          margin-bottom: 0;
          display: inline-block;
          color: inherit;
          .ant-typography-copy {
            position: absolute;
            left: 2px;
@@ -124,16 +125,17 @@
  }
  table tr {
    th .ant-table-column-title {
      // color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
    td {
      color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
  }
  table tbody tr {
    color: var(--mk-table-color);
  }
}
.normal-table-columns.false {
  .ant-pagination {
src/menu/components/table/normal-table/options.jsx
@@ -129,18 +129,32 @@
      ]
    },
    {
      type: 'radio',
      type: 'select',
      field: 'selected',
      label: '首行选中',
      label: '数据选中',
      initval: wrap.selected || 'false',
      tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。',
      tooltip: '初始化:数据加载时选中首行数据,仅执行一次。数据加载:每次数据加载时均选中首行(当按钮执行完成并返回主键值时,默认选中主键值对应行)。选中标记:返回数据中存在 selected 字段,且值为 true 的数据被选中。',
      required: false,
      options: [
        {value: 'false', label: '无'},
        {value: 'init', label: '初始化'},
        {value: 'always', label: '数据加载'},
      ]
        {value: 'sign', label: '选中标记'}
      ],
    },
    // {
    //   type: 'radio',
    //   field: 'selected',
    //   label: '首行选中',
    //   initval: wrap.selected || 'false',
    //   tooltip: '当按钮执行完成并返回主键值时,默认选中主键值对应行。',
    //   required: false,
    //   options: [
    //     {value: 'false', label: '无'},
    //     {value: 'init', label: '初始化'},
    //     {value: 'always', label: '数据加载'},
    //   ]
    // },
    // {
    //   type: 'radio',
    //   field: 'show',
@@ -160,6 +174,19 @@
      initval: wrap.borderColor || '#e8e8e8',
      tooltip: '默认值 #e8e8e8。',
      required: false
    },
    {
      type: 'radio',
      field: 'vertical',
      label: '垂直对齐',
      initval: wrap.vertical || 'middle',
      tooltip: '单元格的垂直对齐方式。',
      required: false,
      options: [
        {value: 'top', label: '向上'},
        {value: 'middle', label: '居中'},
        {value: 'bottom', label: '向下'},
      ]
    },
    // {
    //   type: 'color',
@@ -191,6 +218,18 @@
    //   required: false,
    //   forbid: appType === 'mob'
    // },
    {
      type: 'number',
      field: 'btnlimit',
      label: '按钮限制',
      initval: wrap.btnlimit || '',
      tooltip: '按钮数量限制,超出的按钮会在更多中下拉显示,注:更多中的按钮不要绑定双击事件。',
      min: 3,
      max: 3000,
      precision: 0,
      required: false,
      forbid: appType !== ''
    },
    {
      type: 'select',
      field: 'doubleClick',
@@ -257,7 +296,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/tabs/antv-tabs/options.jsx
@@ -237,7 +237,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/tabs/paste/index.jsx
@@ -60,7 +60,7 @@
  pasteSubmit = () => {
    const { Tab } = this.props
    let appType = sessionStorage.getItem('appType')
    let options = ['tabs', 'group', 'datacard', 'propcard', 'timeline', 'balcony', 'normaltable', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'tablecard', 'line', 'bar', 'pie', 'dashboard', 'scatter', 'chart', 'sandbox']
    let options = ['tabs', 'group', 'datacard', 'propcard', 'timeline', 'balcony', 'normaltable', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
    let types = {
      login: '登录',
      navbar: '导航栏',
@@ -70,7 +70,7 @@
    if (appType === 'mob') {
      options.push('menubar')
    } else {
      options.push('editable', 'antvG6')
      options.push('editable', 'antvG6', 'tree', 'dashboard', 'chart')
    }
    this.pasteFormRef.handleConfirm().then(res => {
src/menu/components/timeline/normal-timeline/index.scss
@@ -10,17 +10,8 @@
  .model-menu-card-cell-list {
    flex: 1;
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/menu/components/timeline/normal-timeline/options.jsx
@@ -140,7 +140,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/components/tree/antd-tree/index.jsx
@@ -173,7 +173,7 @@
            <NormalForm title="基本设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
              <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <CopyComponent type="normaltable" card={card}/>
            <CopyComponent type="tree" card={card}/>
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <ClockComponent config={card} updateConfig={this.updateComponent}/>
            <UserComponent config={card}/>
src/menu/components/tree/antd-tree/options.jsx
@@ -131,7 +131,7 @@
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ],
      forbid: !appType
      forbid: !appType || sessionStorage.getItem('editMenuType') === 'popview'
    },
    {
      type: 'multiselect',
src/menu/datasource/verifycard/index.jsx
@@ -433,13 +433,9 @@
      if (_loading) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
          message: '存在未保存脚本!',
          duration: 5
        })
        this.setState({
          loading: false
        })
        return
      }
      this.setState({
src/menu/datasource/verifycard/settingform/index.jsx
@@ -86,12 +86,17 @@
  }
  handleConfirm = () => {
    const { config } = this.props
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          values.sync = values.sync || 'false'
          if (['navbar', 'balcony', 'menubar', 'interface'].includes(config.type)) {
            values.onload = 'true'
          }
          // 数据源前端验证
          if (values.interType === 'system' && values.execute !== 'false' && values.dataresource) {
            let _quot = values.dataresource.match(/'{1}/g)
src/menu/datasource/verifycard/utils.jsx
@@ -132,7 +132,7 @@
    let _search = defSearch
    if (setting.queryType === 'statistics' && _dataresource) {
    if (_dataresource) {
      _regoptions.forEach(item => {
        _dataresource = _dataresource.replace(item.reg, '0')
      })
src/menu/menushell/card.jsx
@@ -28,6 +28,7 @@
const CustomChart = asyncComponent(() => import('@/menu/components/chart/chart-custom'))
const Timeline = asyncComponent(() => import('@/menu/components/timeline/normal-timeline'))
const Voucher = asyncComponent(() => import('@/menu/components/module/voucher'))
const Account = asyncComponent(() => import('@/menu/components/module/account'))
const Iframe = asyncComponent(() => import('@/menu/components/iframe'))
const AntvG6 = asyncComponent(() => import('@/menu/components/chart/antv-G6'))
@@ -121,6 +122,8 @@
      return (<AntvG6 card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'module' && card.subtype === 'voucher') {
      return (<Voucher card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'module' && card.subtype === 'account') {
      return (<Account card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
  return (
src/menu/menushell/index.jsx
@@ -100,6 +100,7 @@
        timeline: '时间轴',
        antvG6: '树图',
        iframe: 'iframe',
        module: '模块',
        card: '卡片'
      }
      let i = 1
src/menu/modalconfig/index.jsx
@@ -499,7 +499,7 @@
            <Card title="表单配置" bordered={false} extra={
              <div>
                <Button type="danger" onClick={this.clearConfig}>清空</Button>
                <EditComponent options={['form']} config={this.state.config} plusFields={this.plusFields}/>
                <EditComponent options={['form']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
                <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>保存</Button>
                <Button onClick={this.cancelConfig}>返回</Button>
              </div>
src/menu/modulecell/index.jsx
@@ -22,6 +22,7 @@
          { value: 'qrcode', text: '二维码', type: 'action', class: 'element', $init: true},
          { value: 'currentDate', text: '当前时间', type: 'action', class: 'element', $init: true},
          { value: 'formula', text: '公式', type: 'action', class: 'element', $init: true},
          { value: 'color', text: '颜色', type: 'action', class: 'element', $init: true},
          { value: 'sequence', text: '序号', type: 'action', class: 'element', $init: true }
        ]
      },
src/menu/modulesource/option.jsx
@@ -30,7 +30,8 @@
import mindmap from '@/assets/mobimg/mindmap.png'
import indent from '@/assets/mobimg/indent.jfif'
import kapmap from '@/assets/mobimg/kapmap.jfif'
// import Voucher from '@/assets/mobimg/voucher.jpg'
import Voucher from '@/assets/mobimg/voucher.png'
import Account from '@/assets/mobimg/account.png'
// 组件配置信息
export const menuOptions = [
@@ -68,5 +69,6 @@
  { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '自定义', width: 24 },
  { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '分组', width: 24, forbid: ['billPrint'] },
  { type: 'menu', url: Iframe, component: 'iframe', subtype: 'iframe', title: 'iframe', width: 24, forbid: ['billPrint'] },
  // { type: 'menu', url: Voucher, component: 'module', subtype: 'voucher', title: '凭证', width: 24, forbid: ['billPrint'] },
  { type: 'menu', url: Account, component: 'module', subtype: 'account', title: '账套', width: 24, forbid: ['billPrint'] },
  { type: 'menu', url: Voucher, component: 'module', subtype: 'voucher', title: '凭证', width: 24, forbid: ['billPrint'] },
]
src/menu/pastecontroller/index.jsx
@@ -59,12 +59,16 @@
  pasteSubmit = () => {
    let appType = sessionStorage.getItem('appType')
    let options = ['tabs', 'timeline', 'datacard', 'propcard', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'balcony', 'group', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'dashboard', 'scatter', 'iframe', 'sandbox']
    let options = ['tabs', 'timeline', 'datacard', 'propcard', 'mainsearch', 'simpleform', 'stepform', 'tabform', 'balcony', 'group', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'iframe', 'sandbox']
    if (appType === 'mob') {
      options.push('menubar', 'topbar')
      if (sessionStorage.getItem('editMenuType') !== 'popview') {
        options.push('menubar', 'topbar')
      } else {
        options.push('menubar')
      }
    } else {
      options.push('editable', 'antvG6')
      options.push('editable', 'antvG6', 'tree', 'dashboard', 'chart')
    }
    this.pasteFormRef.handleConfirm().then(res => {
src/menu/stylecontroller/index.jsx
@@ -98,13 +98,27 @@
    }
    this.callback = callback
    let card = fromJS(style).toJS()
    let borposition = 'outer'
    if (!card.borderWidth) {
      if (card.borderLeftWidth) {
        borposition = 'left'
      } else if (card.borderRightWidth) {
        borposition = 'right'
      } else if (card.borderTopWidth) {
        borposition = 'top'
      } else if (card.borderBottomWidth) {
        borposition = 'bottom'
      }
    }
    this.setState({
      visible: true,
      fonts: fonts,
      card: fromJS(style).toJS(),
      card: card,
      options: options,
      borposition: 'outer',
      borposition: borposition,
      backgroundImage
    })
    window.GLOB.styling = true
@@ -674,7 +688,7 @@
                    label={<BorderOutlined title="边框位置"/>}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <Radio.Group className="border-position" defaultValue={'outer'} onChange={(e) => this.setState({borposition: e.target.value})}>
                    <Radio.Group className="border-position" defaultValue={borposition} onChange={(e) => this.setState({borposition: e.target.value})}>
                      <Radio value="outer"><BorderOuterOutlined title="外边框"/></Radio>
                      <Radio value="left"><BorderLeftOutlined title="左边框"/></Radio>
                      <Radio value="right"><BorderRightOutlined title="右边框"/></Radio>
src/menu/tablenodes/index.jsx
@@ -173,6 +173,7 @@
        if (result.tb_list) {
          result.tb_list.sort((a, b) => a.tbname > b.tbname ? 1 : -1)
          let length = result.tb_list.length
          result.tb_list.forEach((item, i) => {
            let cell = {
              label: item.tbname,
@@ -180,6 +181,8 @@
              id: 'table' + i,
              direction: 'right',
              color: '#1890ff',
              collapsed: false,
              collable: true,
              children: []
            }
@@ -198,10 +201,17 @@
                    id: item.tbname + 'menu' + i,
                    direction: 'right',
                    color: '#1890ff',
                    type: 'dice-mind-map-leaf',
                    param: _param
                  })
                }
              })
            }
            if (cell.children.length > 5 && length > 1) {
              cell.collapsed = true
            } else if (cell.children.length === 0) {
              cell.collable = false
            }
            data.children.push(cell)
@@ -284,12 +294,12 @@
          const stroke = cfg.style.stroke || '#096dd9';
    
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
              <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${cfg.label}</text>
            </rect>
          </group>
        `;
            <group>
              <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
                <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${cfg.label}</text>
              </rect>
            </group>
          `;
        },
        getAnchorPoints() {
          return [
@@ -308,13 +318,13 @@
          const color = cfg.color;
    
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 26, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, fill: 'transparent' }}>
              <text style={{ fontSize: 12, fill: ${cfg.fontcolor ? cfg.fontcolor : 'black'}, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, marginLeft: 12, marginTop: 6 }}>${cfg.label}</text>
            </rect>
            <rect style={{ fill: ${color}, width: ${width}, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, height: 2, x: 0, y: 32 }} />
          </group>
        `;
            <group>
              <rect draggable="true" style={{width: ${width}, height: 26, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, fill: 'transparent' }}>
                <text style={{ fontSize: 12, fill: ${cfg.fontcolor ? cfg.fontcolor : 'black'}, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, marginLeft: 12, marginTop: 6 }}>${cfg.label} ${cfg.collable ? '+' : ''}</text>
              </rect>
              <rect style={{ fill: ${color}, width: ${width}, cursor: ${cfg.direction !== 'left' ? 'pointer' : 'default'}, height: 2, x: 0, y: 32 }} />
            </group>
          `;
        },
        getAnchorPoints() {
          return [
@@ -406,7 +416,7 @@
          data.color = color;
        }
    
        if (d.children) {
        if (d.children && !d.collapsed) {
          data.children = d.children.map((child) => changeData(child, level + 1, data.color));
        }
        return data;
@@ -447,9 +457,21 @@
          lineWidth: 2,
        },
      },
      minZoom: 0.5,
      minZoom: 0.3,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', 'dice-mindmap'],
        default: [
          {
            type: 'collapse-expand',
            trigger: 'click',
            shouldBegin: (e, self) => {
              if (e.item && e.item.getModel().collable) return true;
              return false;
            },
          },
          'drag-canvas',
          'zoom-canvas',
          'dice-mindmap'
        ],
      },
    });
    
@@ -483,6 +505,7 @@
          </div>
          <div className="footer">
            <Button key="cancel" onClick={() => { this.setState({ visible: false })}}>关闭</Button>
            <span className="tip">注:点击表名可展开/收起菜单</span>
          </div>
        </Modal>
      </div>
src/menu/tablenodes/index.scss
@@ -42,7 +42,16 @@
  }
  .footer {
    position: relative;
    text-align: center;
    .tip {
      position: absolute;
      font-size: 12px;
      color: #1890ff;
      right: 10px;
      top: 20px;
    }
  }
  .tb-search {
    position: absolute;
src/mob/colorsketch/index.jsx
@@ -8,7 +8,7 @@
const presetColors = [
  '#1890ff', '#f5222d', '#fa541c', '#fa8c16', '#faad14', '#fadb14', '#a0d911', '#52c41a', '#13c2c2', '#2f54eb', '#722ed1',
  '#eb2f96', '#aeb303', '#c32539', '#ffbb96', '#ffd591', '#ffe58f', '#fffb8f', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff',
  '#eb2f96', '#aeb303', '#c32539', '#1d3661', '#ffd591', '#ffe58f', '#fffb8f', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff',
  '#adc6ff', '#d3adf7', '#EBE9E9', '#d9d9d9', '#434343', '#000000', '#ffffff', 'transparent'
]
src/mob/components/menubar/common-menubar/index.scss
@@ -6,17 +6,7 @@
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 20px;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  >.anticon-tool {
    position: absolute;
    z-index: 2;
src/mob/components/menubar/normal-menubar/index.scss
@@ -7,16 +7,6 @@
  background-size: cover;
  min-height: 20px;
  
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  >.anticon-tool {
    position: absolute;
    z-index: 2;
src/mob/components/menubar/normal-menubar/options.jsx
@@ -74,7 +74,8 @@
      options: [
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ]
      ],
      forbid: sessionStorage.getItem('editMenuType') === 'popview'
    },
  ]
src/mob/components/navbar/normal-navbar/index.jsx
@@ -123,7 +123,7 @@
    _style.height = card.wrap.height
    return (
      <div className="normal-navbar-edit-box" style={_style} id={card.uuid}>
      <div className={'normal-navbar-edit-box ' + (card.wrap.menuStyle || '')} style={_style} id={card.uuid}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <PlusOutlined className="plus" title="添加菜单" onClick={() => MKEmitter.emit('addmobmenu')}/>
src/mob/components/navbar/normal-navbar/index.scss
@@ -41,24 +41,7 @@
        margin-bottom: 0;
      }
    }
    .am-tab-bar-tab.tab-zoomIn {
      .am-tab-bar-tab-icon {
        padding: 10px;
        display: inline-block;
        background: #1890ff;
        color: #ffffff;
        border-radius: 40px;
        width: 42px;
        height: 42px;
        font-size: 15px;
        transform: translate(0px, -25px);
      }
      .am-tab-bar-tab-title {
        font-size: 1.2em;
        color: #1890ff;
        transform: translate(0px, -22px);
      }
    }
  }
  .anticon-tool {
@@ -72,6 +55,43 @@
    background: rgba(255, 255, 255, 0.55);
  }
}
.normal-navbar-edit-box:not(.class1) {
  .menu .am-tab-bar-tab.tab-zoomIn {
    .am-tab-bar-tab-icon {
      padding: 10px;
      display: inline-block;
      background: #1890ff;
      color: #ffffff;
      border-radius: 40px;
      width: 42px;
      height: 42px;
      font-size: 15px;
      transform: translate(0px, -25px);
    }
    .am-tab-bar-tab-title {
      font-size: 1.2em;
      color: #1890ff;
      transform: translate(0px, -22px);
    }
  }
}
.normal-navbar-edit-box.class1 {
  background-color: #1890ff!important;
  border-top-left-radius: 40px;
  border-top-right-radius: 40px;
  .am-tab-bar-tab-icon {
    color: #ffffff;
    position: relative;
    top: 5px;
  }
  .menu .am-tab-bar-tab .anticon {
    font-size: 20px;
  }
  .am-tab-bar-tab-title {
    display: none;
  }
}
.normal-navbar-edit-box::after {
  display: block;
  content: ' ';
src/mob/components/navbar/normal-navbar/options.jsx
@@ -30,14 +30,62 @@
      ]
    },
    {
      type: 'number',
      type: 'styleInput',
      field: 'height',
      label: '高度',
      initval: wrap.height || 50,
      min: 30,
      max: 200,
      precision: 0,
      required: true
      required: true,
      options: ['px']
    },
    {
      type: 'radio',
      field: 'switch',
      label: '切换方式',
      initval: wrap.switch || 'default',
      tooltip: '默认时在H5中会切换页面,APP中会切换标签页,使用标签页时会强制使用标签切换。',
      required: false,
      options: [
        {value: 'default', label: '默认'},
        {value: 'tab', label: '标签页'},
      ],
      controlFields: [
        {field: 'position', values: ['tab']},
      ]
    },
    {
      type: 'radio',
      field: 'position',
      label: '菜单位置',
      initval: wrap.position || 'bottom',
      required: false,
      options: [
        {value: 'bottom', label: '底部'},
        {value: 'left', label: '左侧'},
        {value: 'right', label: '右侧'},
      ],
      controlFields: [
        {field: 'marginTop', values: ['left', 'right']},
      ]
    },
    {
      type: 'radio',
      field: 'menuStyle',
      label: '菜单样式',
      initval: wrap.menuStyle || 'default',
      tooltip: '使用APP中原生菜单栏时无效。',
      required: false,
      options: [
        {value: 'default', label: '默认'},
        {value: 'class1', label: '样式二'},
      ]
    },
    {
      type: 'styleInput',
      field: 'marginTop',
      label: '顶部缩进',
      initval: wrap.marginTop || '',
      required: false,
      options: ['px', 'vh']
    },
    {
      type: 'radio',
src/mob/components/sharecode/options.jsx
@@ -48,7 +48,7 @@
      field: 'color',
      label: '颜色',
      initval: wrap.color || '#000000',
      isHex: true,
      colorType: 'hex',
      required: true
    },
  ]
src/mob/components/tabs/antv-tabs/options.jsx
@@ -185,7 +185,8 @@
      options: [
        {value: 'true', label: '启用'},
        {value: 'false', label: '禁用'},
      ]
      ],
      forbid: sessionStorage.getItem('editMenuType') === 'popview'
    },
  ]
src/mob/header/index.jsx
@@ -1,5 +1,4 @@
import React, {Component} from 'react'
import { Radio } from 'antd'
import avatar from '@/assets/img/avatar.jpg'
import MainLogo from '@/assets/img/main-logo.png'
@@ -8,26 +7,13 @@
class MobHeader extends Component {
  state = {
    avatar: sessionStorage.getItem('CloudAvatar') || avatar,
    userName: sessionStorage.getItem('CloudUserName'),
    typename: sessionStorage.getItem('typename')
  }
  changeView = (e) => {
    let val = e.target.value
    this.props.changeView(val)
    userName: sessionStorage.getItem('CloudUserName')
  }
  render () {
    const { typename } = this.state
    return (
      <header className="mob-header-container">
        <div className="header-logo"><img src={MainLogo} alt=""/></div>
        {typename === 'pad' ? <div className="change-view">
          <Radio.Group defaultValue="vertical" onChange={this.changeView}>
            <Radio value="vertical">竖屏</Radio>
            <Radio value="horizontal">横屏</Radio>
          </Radio.Group>
        </div> : null}
        <div className="header-user">
          <img src={this.state.avatar} alt=""/>
          <span>
src/mob/mobshell/index.jsx
@@ -143,6 +143,7 @@
        timeline: '时间轴',
        officialAccount: '关注公众号',
        sharecode: '分享码',
        iframe: 'iframe',
        login: '登录'
      }
      let i = 1
src/mob/modulesource/index.jsx
@@ -16,7 +16,7 @@
  }
  UNSAFE_componentWillMount () {
    const { components } = this.props
    const { components, viewType } = this.props
    let options = []
    
    if (components) {
@@ -29,6 +29,10 @@
      }
    }
    if (viewType === 'popview') {
      options = options.filter(item => !['topbar', 'navbar', 'login', 'officialAccount'].includes(item.component))
    }
    this.setState({
      menuOptions: options
    })
src/pc/components/login/normal-login/index.scss
@@ -8,18 +8,8 @@
  background-size: cover;
  min-height: 100px;
  max-width: 100%;
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
@@ -44,7 +34,7 @@
        // margin-top: 45px;
        .login-form-button {
          width: 100%;
          height: 40px;
          height: 42px;
          line-height: 1;
          font-size: 18px;
          margin-bottom: 15px;
@@ -52,7 +42,7 @@
        }
        .sign-form-button {
          width: 100%;
          height: 40px;
          height: 42px;
          line-height: 1;
          font-size: 18px;
          margin-bottom: 15px;
src/pc/components/login/normal-login/loginform.jsx
@@ -139,15 +139,20 @@
    const { wrap } = this.props
    const { activeWay, loginWays, scanWay } = this.state
    let style = {}
    if (wrap.borderRadius) {
      style.borderRadius = wrap.borderRadius
    }
    return (
      <Form className="login-edit-form">
        <div className="login-way-title">{activeWay.label}</div>
        {wrap.topTip !== 'hidden' ? <div className="login-way-title">{activeWay.label}</div> : null}
        {scanWay && activeWay.type !== 'app_scan' ? <div className="scan-icon" onClick={() => this.onChangeTab(scanWay)}><QrcodeOutlined /></div> : null}
        {activeWay.type === 'uname_pwd' ? <div className={'form-item-wrap ' + (activeWay.shortcut === 'none' ? 'no-short' : '')}>
          <Form.Item>
            <Input
              prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
              placeholder="用户名"
              placeholder="用户名/手机号/邮箱"
              autoComplete="off"
            />
          </Form.Item>
@@ -161,7 +166,7 @@
            <Checkbox>自动登录</Checkbox>
          </Form.Item> : null}
          <Form.Item className="btn-login">
            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="login-form-button">
            <Button type="primary" style={style} onDoubleClick={() => this.changeMenu()} className="login-form-button">
              登录
            </Button>
          </Form.Item>
@@ -185,7 +190,7 @@
            />
          </Form.Item>
          <Form.Item className="btn-login">
            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="login-form-button">
            <Button type="primary" style={style} onDoubleClick={() => this.changeMenu()} className="login-form-button">
              登录
            </Button>
          </Form.Item>
src/pc/components/login/normal-login/options.jsx
@@ -73,12 +73,42 @@
    {
      type: 'styleInput',
      field: 'height',
      label: '高度',
      label: '最小高度',
      initval: wrap.height || '',
      tooltip: '组件占用的最小高度,用于页面布局。',
      required: false,
      options: ['px', 'vh', 'vw', '%']
    },
    // {
    //   type: 'styleInput',
    //   field: 'maxWidth',
    //   label: '最大宽度',
    //   initval: wrap.maxWidth || '',
    //   tooltip: '组件占用的最大宽度,用于页面布局。',
    //   required: false,
    //   options: ['px', 'vh', 'vw', '%']
    // },
    {
      type: 'radio',
      field: 'topTip',
      label: '顶部提示',
      initval: wrap.topTip || 'show',
      tooltip: '登录或注册方式提示信息。',
      required: false,
      options: [
        {value: 'show', label: '显示'},
        {value: 'hidden', label: '隐藏'}
      ]
    },
    {
      type: 'styleInput',
      field: 'borderRadius',
      label: '圆角',
      initval: wrap.borderRadius || '',
      tooltip: '登录或注册时,确定按钮的圆角。',
      required: false,
      options: ['px', 'vh', 'vw', '%']
    },
    {
      type: 'radio',
      field: 'classify',
src/pc/components/login/normal-login/signform.jsx
@@ -133,9 +133,14 @@
    const { wrap } = this.props
    const { activeWay, signWays, appType } = this.state
    let style = {}
    if (wrap.borderRadius) {
      style.borderRadius = wrap.borderRadius
    }
    return (
      <Form className="login-edit-form">
        {appType === 'pc' ? <div className="login-way-title">{activeWay.label}</div> : null}
        {appType === 'pc' && wrap.topTip !== 'hidden' ? <div className="login-way-title">{activeWay.label}</div> : null}
        {activeWay.type === 'uname_pwd' ? <div className="form-item-wrap">
          <Form.Item>
            <Input
@@ -151,7 +156,7 @@
            <Checkbox>{wrap.tip}</Checkbox>{wrap.groups.map((item, i) => (<span><span className="protocol" key={i}>《{item.label}》</span>{wrap.groups.length > i + 1 ? (wrap.groups.length > i + 2 ? '、' : '和') : null}</span>))}
          </div> : null}
          <Form.Item className="btn-login">
            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="sign-form-button">
            <Button type="primary" style={style} onDoubleClick={() => this.changeMenu()} className="sign-form-button">
            注册
            </Button>
          </Form.Item>
@@ -178,7 +183,7 @@
            <Checkbox>{wrap.tip}</Checkbox>{wrap.groups.map((item, i) => (<span><span className="protocol" key={i}>《{item.label}》</span>{wrap.groups.length > i + 1 ? (wrap.groups.length > i + 2 ? '、' : '和') : null}</span>))}
          </div> : null}
          <Form.Item className="btn-login">
            <Button type="primary" onDoubleClick={() => this.changeMenu()} className="sign-form-button">
            <Button type="primary" style={style} onDoubleClick={() => this.changeMenu()} className="sign-form-button">
              注册
            </Button>
          </Form.Item>
src/pc/components/navbar/normal-navbar/index.scss
@@ -58,17 +58,8 @@
      }
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
  >.anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
src/pc/menushell/index.jsx
@@ -114,7 +114,8 @@
        balcony: '浮动卡',
        timeline: '时间轴',
        antvG6: '树图',
        login: '登录'
        login: '登录',
        iframe: 'iframe'
      }
      let i = 1
      
src/store/options.js
@@ -44,4 +44,6 @@
  bg_white_style_grass_green: 'mk-grass-green-white',
  bg_black_style_deep_red: 'mk-deep-red-black',
  bg_white_style_deep_red: 'mk-deep-red-white',
  bg_black_style_deep_blue: 'mk-deep-blue-black',
  bg_white_style_deep_blue: 'mk-deep-blue-white',
}
src/tabviews/basetable/index.jsx
@@ -291,6 +291,8 @@
        })
        return true
      } else {
        item.name = (this.props.MenuName || '')
      }
      // 搜索条件初始化
src/tabviews/custom/components/card/balcony/index.jsx
@@ -31,6 +31,8 @@
    checked: false
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -59,16 +61,21 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      } else if (_sync && initdata) {
        _data = initdata
        if (Array.isArray(_data)) {
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      }
    } else if (_config.wrap.datatype === 'public' && window.GLOB.CacheData.get(_config.wrap.publicId)) {
      _data = window.GLOB.CacheData.get(_config.wrap.publicId)
      _data = fromJS(_data).toJS()
      this.loaded = true
    } else if (_config.wrap.datatype === 'static') {
      this.loaded = true
    }
    _data.$$BID = BID || ''
@@ -143,6 +150,17 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {this.loadData(true)})
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res[0]
        _data.$$uuid = _data[config.setting.primaryKey] || ''
        this.setState({data: _data})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -182,6 +200,8 @@
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.loaded = true
      this.setState({sync: false, data: _data})
    }
  }
@@ -195,6 +215,8 @@
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.loaded = true
      this.setState({data: _data})
    }
@@ -303,6 +325,7 @@
      this.setState({
        data: {$$BID: BID || '', $$BData: BData, $$empty: true},
      })
      this.loaded = true
      return
    }
@@ -321,6 +344,11 @@
    if (result.status) {
      let _data = {}
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      if (!result.data || !result.data[0]) {
        _data.$$empty = true
      } else {
src/tabviews/custom/components/card/balcony/index.scss
@@ -46,9 +46,9 @@
  .loading-mask {
    position: absolute;
    left: 40px;
    left: 0px;
    top: 0;
    right: 40px;
    right: 0px;
    bottom: 0px;
    display: flex;
    align-items: center;
src/tabviews/custom/components/card/cardItem/index.jsx
@@ -162,9 +162,14 @@
  render() {
    const { card, data, cards } = this.props
    let style = {...card.style}
    if (card.setting.bgField) {
      style.backgroundImage = `url('${data[card.setting.bgField] || ''}')`
    }
    return (
      <div className={'card-item-box ' + (card.setting.btnControl || '')} style={card.style} onClick={this.openView} onDoubleClick={this.doubleClick}>
      <div className={'card-item-box ' + (card.setting.btnControl || '')} style={style} onClick={this.openView} onDoubleClick={this.doubleClick}>
        <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.elements}/>
        {card.setting.type === 'multi' ? <div className={'back-side ' + card.setting.transform} style={card.backStyle}>
          <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.backElements}/>
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Col, Tooltip, notification, Typography } from 'antd'
import { Col, Tooltip, notification, Typography, message } from 'antd'
import moment from 'moment'
import Api from '@/api'
@@ -237,6 +237,7 @@
      if (card.eleType === 'sequence') {
        let _style = {}
        let className = ''
        if (card.marks) {
          _style.width = card.innerHeight
          _style.height = card.innerHeight
@@ -245,11 +246,12 @@
          let mark = getMark(card.marks, data, _style)
  
          _style = mark.style
          className = mark.signType
        }
        contents.push(
          <Col key={card.uuid} style={_style_} span={card.width}>
            <div style={card.style}>
              <div className="ant-mk-text line1" style={{height: card.innerHeight || 'auto'}}><span className="sequence-wrap" style={_style}>{data.$Index || ''}</span></div>
              <div className={'ant-mk-text line1' + className} style={{height: card.innerHeight || 'auto'}}><span className="sequence-wrap" style={_style}>{data.$Index || ''}</span></div>
            </div>
          </Col>
        )
@@ -362,6 +364,7 @@
          }
        }
  
        let className = ''
        if (card.marks) {
          let mark = getMark(card.marks, data, _style)
  
@@ -374,6 +377,7 @@
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          }
          className = mark.signType
        }
  
        if (card.link || (card.anchors && card.anchors.length > 0)) {
@@ -387,7 +391,7 @@
        contents.push(
          <Col key={card.uuid} style={_style_} span={card.width}>
            <div style={_style} onClick={(e) => {this.openNewView(e, card)}}>
              <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
              <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight || 'auto'}}>{val}</div>
            </div>
          </Col>
        )
@@ -437,6 +441,7 @@
          }
        }
        
        let className = ''
        if (card.marks) {
          let mark = getMark(card.marks, data, _style)
  
@@ -449,12 +454,13 @@
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          }
          className = mark.signType
        }
  
        contents.push(
          <Col key={card.uuid} style={_style_} span={card.width}>
            <div style={_style}>
              <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
              <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight || 'auto'}}>{val}</div>
            </div>
          </Col>
        )
@@ -747,6 +753,7 @@
          }
        }
  
        let className = ''
        if (card.marks) {
          let mark = getMark(card.marks, data, _style)
  
@@ -759,12 +766,58 @@
              val = <span>{val} <MkIcon style={mark.innerStyle} type={mark.icon} /></span>
            }
          }
          className = mark.signType
        }
  
        contents.push(
          <Col key={card.uuid} style={_style_} span={card.width}>
            <div style={_style}>
              <div className={'ant-mk-text line' + (card.height || '')} style={{height: card.innerHeight || 'auto'}}>{val}</div>
              <div className={'ant-mk-text line' + (card.height || '') + className} style={{height: card.innerHeight || 'auto'}}>{val}</div>
            </div>
          </Col>
        )
      } else if (card.eleType === 'color') {
        let color = ''
        if (card.datatype === 'static') {
          color = card.value
        } else {
          color = data[card.field] || ''
        }
        if (color === '' && card.noValue === 'hide') { // 空值隐藏
          return null
        }
        let _bgstyle = {backgroundColor: color}
        if (PicRadio[card.lenWidRadio]) {
          _bgstyle.paddingTop = PicRadio[card.lenWidRadio]
        } else {
          _bgstyle.paddingTop = '100%'
        }
        if (card.copyable === 'true') {
          _bgstyle.cursor = 'pointer'
        }
        contents.push(
          <Col key={card.uuid} style={_style_} span={card.width}>
            <div className="ant-mk-color" style={card.style}>
              <div style={_bgstyle} onClick={(e) => {
                if (card.copyable === 'true') {
                  e.stopPropagation()
                  let oInput = document.createElement('input')
                  oInput.value = color
                  document.body.appendChild(oInput)
                  oInput.select()
                  document.execCommand('Copy')
                  document.body.removeChild(oInput)
                  message.success('复制成功。')
                }
              }}></div>
            </div>
          </Col>
        )
@@ -896,6 +949,7 @@
                  BData={data.$$BData || ''}
                  disabled={_disabled}
                  setting={cards.setting}
                  columns={cards.columns}
                  selectedData={_data}
                />
              </Col>
src/tabviews/custom/components/card/cardcellList/index.scss
@@ -77,6 +77,11 @@
  .line10 {
    -webkit-line-clamp: 10;
  }
  .ant-col:not(.mk-cell-btn) > div {
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
  }
  .mk-cell-btn {
    > div {width: 100%;max-width: 100%;}
    button:not(.ant-switch) {
@@ -87,8 +92,13 @@
      padding: 0;
      overflow: hidden;
    }
    .ant-checkbox-inner, .ant-checkbox-checked::after {
      border-radius: 15px;
    .ant-checkbox-wrapper:not(.square) {
      .ant-checkbox-inner, .ant-checkbox-checked::after {
        border-radius: 15px;
      }
    }
    .ant-checkbox-inner {
      border-color: #b8b8b8;
    }
  }
  .ant-mk-slider {
@@ -158,6 +168,9 @@
    vertical-align: top;
    line-height: inherit;
  }
  .ant-mk-color {
    overflow: hidden;
  }
  .ant-switch-large {
    min-width: 60px;
    height: 30px;
src/tabviews/custom/components/card/data-card/index.jsx
@@ -46,6 +46,8 @@
    supComs: null
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -102,16 +104,16 @@
    let _data = null
    let _sync = _config.setting.sync === 'true'
    if (_config.setting.sync === 'true' && data) {
    if (_sync && data) {
      _data = data[_config.dataName] || []
      _sync = false
    } else if (_config.setting.sync === 'true' && initdata) {
    } else if (_sync && initdata) {
      _data = initdata || []
      _sync = false
    }
    let selected = 'false'
    if (_config.wrap.selected === 'always' || _config.wrap.selected === 'init') {
    if (_config.wrap.selected === 'always' || _config.wrap.selected === 'init' || _config.wrap.selected === 'sign') {
      selected = _config.wrap.selected
    } else {
      _config.wrap.selected = 'false'
@@ -173,6 +175,8 @@
    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''} ${_config.wrap.scale}`
    this.loaded = _data !== null
    this.setState({
      supComs,
      selected,
@@ -214,6 +218,27 @@
        })
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.setting.primaryKey] || ''
          item.$Index = index + 1 + ''
          if (config.wrap.controlField) {
            if (config.wrap.controlVal.includes(item[config.wrap.controlField])) {
              item.$disabled = true
            }
          }
          return item
        })
        this.setState({data: _data})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -252,6 +277,8 @@
          }
        }
      }
      this.loaded = true
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -342,17 +369,58 @@
  }
  checkTopLine = (id) => {
    const { config, data } = this.state
    const { config, data, selected } = this.state
    if (!data || data.length === 0) {
      this.setState({
        activeKey: '',
        selectKeys: [],
        selectedData: []
      })
      MKEmitter.emit('resetSelectLine', config.uuid, '', '')
      if (config.setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
      return
    }
    if (selected === 'sign') {
      let index = ''
      let keys = []
      let items = []
      let last = ''
      data.forEach((item, i) => {
        if (!item.$disabled && item.selected === 'true') {
          items.push(item)
          keys.push(i)
          index = i
          last = item
        }
      })
      this.setState({
        activeKey: index,
        selectKeys: keys,
        selectedData: items
      })
      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
      if (config.setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, items, data.length === keys.length)
      }
      return
    }
    let index = 0
    if (id && data) {
    if (id) {
      index = data.findIndex(item => item.$$uuid === id)
      if (index === -1) {
        index = 0
      }
    }
    if (!data || data.length === 0 || data[index].$disabled) {
    if (data[index].$disabled) {
      this.setState({
        activeKey: '',
        selectKeys: [],
@@ -485,6 +553,8 @@
    const { config, arr_field, pageIndex, search, BID, BData, selected } = this.state
    if (config.setting.supModule && !BID && config.wrap.supKey !== 'false') { // BID 不存在时,不做查询
      this.loaded = true
      this.setState({
        activeKey: '',
        selectKeys: [],
@@ -542,6 +612,11 @@
        start = config.setting.pageSize * (pageIndex - 1) + 1
      }
      this.loaded = true
      if (config.$cache && pageIndex === 1) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      if (selected !== 'false' || (id && config.wrap.selected !== 'false')) {
        setTimeout(() => {
          this.checkTopLine(id)
src/tabviews/custom/components/card/data-card/index.scss
@@ -24,7 +24,7 @@
      >.card-item-box {
        cursor: not-allowed;
        color: #bcbcbc;
        .ant-mk-text, .ant-mk-date, .anticon {
        .ant-mk-text, .anticon {
          color: #bcbcbc!important;
          span {
            color: #bcbcbc!important;
src/tabviews/custom/components/card/prop-card/index.jsx
@@ -31,6 +31,8 @@
    selected: 'false',
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -60,16 +62,21 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      } else if (_sync && initdata) {
        _data = initdata
        if (Array.isArray(_data)) {
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      }
    } else if (_config.wrap.datatype === 'public' && window.GLOB.CacheData.get(_config.wrap.publicId)) {
      _data = window.GLOB.CacheData.get(_config.wrap.publicId)
      _data = fromJS(_data).toJS()
      this.loaded = true
    } else if (_config.wrap.datatype === 'static') {
      this.loaded = true
    }
    _data.$$BID = BID || ''
@@ -172,6 +179,17 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {this.loadData(true)})
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res[0]
        _data.$$uuid = _data[config.setting.primaryKey] || ''
        this.setState({data: _data})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -210,6 +228,8 @@
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.loaded = true
      this.setState({sync: false, data: _data}, () => {
        if (selected !== 'false') {
          this.checkTopLine()
@@ -234,6 +254,8 @@
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.loaded = true
      this.setState({data: _data}, () => {
        if (selected !== 'false') {
@@ -360,6 +382,7 @@
      this.setState({
        data: {$$BID: BID || '', $$BData: BData, $$empty: true},
      })
      this.loaded = true
      return
    }
@@ -383,6 +406,11 @@
    if (result.status) {
      let _data = {}
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      if (!result.data || !result.data[0]) {
        _data.$$empty = true
      } else {
@@ -397,12 +425,18 @@
        data: _data,
        loading: false
      }, () => {
        if (selected !== 'false') {
          this.checkTopLine()
        if (config.wrap.goback === 'true' && _data.$$empty) {
          this.timer && this.timer.stop()
          MKEmitter.emit('closeTabView', config.$pageId)
        } else {
          this.transferLine()
          if (selected !== 'false') {
            this.checkTopLine()
          } else {
            this.transferLine()
          }
          this.autoExec()
        }
        this.autoExec()
      })
      if (config.timer && config.clearField) {
src/tabviews/custom/components/card/prop-card/index.scss
@@ -63,9 +63,9 @@
  .loading-mask {
    position: absolute;
    left: 40px;
    left: 0px;
    top: 0;
    right: 40px;
    right: 0px;
    bottom: 0px;
    display: flex;
    align-items: center;
src/tabviews/custom/components/card/table-card/index.jsx
@@ -34,6 +34,8 @@
    BData: ''
  }
  loaded = false
  /**
   * @description 初始化处理
   * 1、 initdata 为打印时使用的数据集
@@ -104,6 +106,8 @@
    _config.wrap.pagestyle = _config.wrap.pagestyle || 'page'
    this.loaded = _data !== null
    this.setState({
      sync: _sync,
      BID: BID || '',
@@ -137,6 +141,21 @@
        }, () => {
          this.loadData('timer')
        })
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.setting.primaryKey] || ''
          item.$Index = index + 1 + ''
          return item
        })
        this.setState({data: _data})
      })
    }
  }
@@ -177,6 +196,8 @@
        item.$Index = index + 1 + ''
        return item
      })
      this.loaded = true
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -263,6 +284,8 @@
        data: [],
        total: 0
      })
      this.loaded = true
      return
    }
@@ -297,6 +320,11 @@
        start = config.setting.pageSize * (pageIndex - 1) + 1
      }
      this.loaded = true
      if (config.$cache && pageIndex === 1) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      let data = []
      if (type === 'plus') {
src/tabviews/custom/components/card/table-card/index.scss
@@ -68,9 +68,9 @@
  .loading-mask {
    position: absolute;
    left: 40px;
    left: 0px;
    top: 0;
    right: 40px;
    right: 0px;
    bottom: 0px;
    display: flex;
    align-items: center;
src/tabviews/custom/components/carousel/data-card/index.jsx
@@ -32,6 +32,8 @@
    visible: false
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -62,6 +64,7 @@
    }
    if (_data) {
      this.loaded = true
      _data = _data.map((item, index) => {
        item.key = index
        item.$$uuid = item[_config.setting.primaryKey] || ''
@@ -129,6 +132,21 @@
        this.loadData('timer')
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.setting.primaryKey] || ''
          item.$Index = index + 1 + ''
          return item
        })
        this.setState({data: _data})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -152,6 +170,8 @@
        item.$Index = index + 1
        return item
      })
      this.loaded = true
      this.setState({sync: false, data: _data}, () => {
        this.openModal()
@@ -256,6 +276,8 @@
        data: [],
        loading: false
      })
      this.loaded = true
      return
    }
@@ -276,6 +298,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
src/tabviews/custom/components/carousel/prop-card/index.jsx
@@ -31,6 +31,8 @@
    visible: false
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -51,7 +53,7 @@
      BID = BData.$BID || ''
    }
    
    if (_config.setting && _config.wrap.datatype === 'dynamic') {
    if (_config.wrap.datatype === 'dynamic') {
      _sync = _config.setting.sync === 'true'
      if (_sync && data) {
@@ -60,13 +62,17 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      } else if (_sync && initdata) {
        _data = initdata
        if (Array.isArray(_data)) {
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        this.loaded = true
      }
    } else if (_config.wrap.datatype === 'static') {
      this.loaded = true
    }
    _data.$$uuid = _data[_config.setting.primaryKey] || ''
@@ -130,6 +136,17 @@
        this.loadData('timer')
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        let _data = res[0]
        _data.$$uuid = _data[config.setting.primaryKey] || ''
        this.setState({data: _data})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -166,6 +183,8 @@
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      _data.$$BID = BID || ''
      _data.$$BData = BData || ''
      this.loaded = true
      this.setState({sync: false, data: _data}, () => {
        if (config.wrap.display === 'modal') {
@@ -271,6 +290,8 @@
      this.setState({
        data: {$$BID: BID || '', $$BData: BData, $$empty: true}
      })
      this.loaded = true
      return
    }
@@ -294,6 +315,11 @@
    if (result.status) {
      let _data = {}
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      if (!result.data || !result.data[0]) {
        _data.$$empty = true
      } else {
src/tabviews/custom/components/carousel/prop-card/index.scss
@@ -21,9 +21,9 @@
  .loading-mask {
    position: absolute;
    left: 40px;
    left: 0px;
    top: 0;
    right: 40px;
    right: 0px;
    bottom: 0px;
    display: flex;
    align-items: center;
src/tabviews/custom/components/chart/antv-G6/index.jsx
@@ -27,7 +27,8 @@
  purple: '#722ed1',
  magenta: '#eb2f96',
  grass_green: '#aeb303',
  deep_red: '#c32539'
  deep_red: '#c32539',
  deep_blue: '#1d3661'
}
let systemColor = '#1890ff'
@@ -60,29 +61,7 @@
  },
  'single-node',
)
G6.registerNode(
  'dice-mind-map-sub', {
    jsx: (cfg) => {
      const width = Util.getTextSize(cfg.label, 14)[0] + 24
      return `
        <group>
          <rect style={{width: ${width}, height: 22, cursor: pointer}}>
            <text style={{ fontSize: 14, fill: ${cfg.selected ? systemColor : '#000000'}, marginLeft: 12, marginTop: 6, cursor: pointer }}>${cfg.label}</text>
          </rect>
          <rect style={{ fill: ${cfg.color}, width: ${width}, height: 2, x: 0, y: 22, cursor: pointer }} />
        </group>
      `
    },
    getAnchorPoints() {
      return [
        [0, 0.965],
        [1, 0.965]
      ]
    }
  },
  'single-node',
)
G6.registerNode(
  'dice-mind-map-leaf', {
    jsx: (cfg) => {
@@ -139,38 +118,6 @@
    ev.preventDefault()
  }
})
const dataMapTransform = (data) => {
  const changeData = (d, level = 0, color) => {
    const data = { ...d }
    switch (level) {
      case 0:
        data.type = 'dice-mind-map-root'
        break
      case 1:
        data.type = 'dice-mind-map-sub'
        break
      default:
        data.type = 'dice-mind-map-leaf'
        break
    }
    if (color) {
      data.color = color
    }
    if (level === 1 && !d.direction) {
      data.direction = 'right'
    }
    if (d.children) {
      data.children = d.children.map((child) => changeData(child, level + 1, data.color))
    }
    return data
  }
  return changeData(data)
}
// 缩进文件树
G6.registerNode('indentedRoot', {
@@ -857,7 +804,6 @@
  state = {
    config: null,
    data: null,
    BID: '',
    BData: '',
    plot: null,
@@ -867,11 +813,12 @@
    empty: true
  }
  data = []
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = _config.setting.sync === 'true'
    let BID = ''
@@ -887,10 +834,10 @@
    }
    if (_sync && data) {
      _data = data[config.dataName] || []
      this.data = data[config.dataName] || []
      _sync = false
    } else if (_sync && initdata) {
      _data = initdata || []
      this.data = initdata || []
      _sync = false
    }
@@ -903,7 +850,6 @@
    this.setState({
      config: _config,
      data: _data,
      BID: BID || '',
      BData: BData || '',
      arr_field: _config.columns.map(col => col.field).join(','),
@@ -914,44 +860,13 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true' && _data) {
        this.handleData()
      }
    })
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { sync, config } = this.state
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = []
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName]
      }
      this.setState({sync: false, data: _data}, () => {
        this.handleData()
      })
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
      })
    if (this.data.length > 0) {
      this.handleData()
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    const { config } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    let that = this
    if (config.plot.subtype === 'mindmap') {
@@ -1081,6 +996,53 @@
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
    const { sync, config } = this.state
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = []
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName]
      }
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      }
      this.setState({sync: false})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.data.length > 0) return
        if (!is(fromJS(this.data), fromJS(res))) {
          this.data = res
          this.handleData()
        }
      })
    }
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
@@ -1115,11 +1077,10 @@
    const { config, arr_field, BID } = this.state
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: {}
      }, () => {
      if (!is(fromJS(this.data), fromJS([]))) {
        this.data = []
        this.handleData()
      })
      }
      return
    }
@@ -1139,14 +1100,18 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let data = result.data || []
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data,
        loading: false
      }, () => {
        this.handleData()
      })
      if (!is(fromJS(this.data), fromJS(result.data || []))) {
        this.data = result.data || []
        this.handleData()
      }
    } else {
      this.setState({
        loading: false
@@ -1167,7 +1132,7 @@
  }
  getdata = () => {
    const { plot, data, config, BData } = this.state
    const { plot, config, BData } = this.state
    
    let root = {
      label: 'Root',
@@ -1193,7 +1158,7 @@
    let _options = []
    let logMap = new Map()
    data.forEach(item => {
    this.data.forEach(item => {
      let pval = item[plot.parentField]
      let val = item[plot.valueField]
      let label = item[plot.labelField] || ''
@@ -1223,6 +1188,8 @@
    root.children = root.children || []
    if (plot.subtype === 'mindmap') {
      root.type = 'dice-mind-map-root'
      if (plot.dirField) {
        root.children = root.children.map(item => {
          item.direction = item[plot.dirField] === plot.dirSign ? 'left' : 'right'
@@ -1235,9 +1202,24 @@
        if (item.direction === 'left') {
          item.color = plot.leftColor || '#26C281'
        } else {
          item.direction = 'right'
          item.color = plot.nodeColor || '#1890ff'
        }
      })
      const collapse = (item) => {
        if (!item.children) return
        item.children.forEach(cell => {
          cell.collapsed = plot.collapsed === 'true'
          cell.direction = cell.direction || 'right'
          cell.type = 'dice-mind-map-leaf'
          cell.color = cell.color || item.color
          collapse(cell)
        })
      }
      collapse(root)
    } else if (plot.subtype === 'indentTree') {
      root.isRoot = true
      root.collapsed = false
@@ -1292,14 +1274,20 @@
  }
  handleData = () => {
    const { plot, data } = this.state
    let _element = document.getElementById(this.state.chartId)
    if (_element) {
      _element.innerHTML = ''
    }
    if (!data || data.length === 0) {
    setTimeout(() => {
      this.viewrender()
    }, 100)
  }
  viewrender = () => {
    const { plot } = this.state
    if (this.data.length === 0) {
      this.setState({empty: true})
    } else {
      this.setState({empty: false})
@@ -1368,6 +1356,10 @@
    graph.data(data)
    graph.render()
    graph.fitView()
    if (plot.collapsed === 'true') {
      graph.zoomTo(1, { x: 0, y: plot.height / 2 })
    }
  }
  indentrender = () => {
@@ -1437,10 +1429,16 @@
  ponitrender = () => {
    const { config, plot, chartId } = this.state
    const data = this.getdata()
    const width = this.wrap.scrollWidth - 30
    let modes = ['drag-canvas', 'zoom-canvas', config.uuid]
    if (plot.collapsed === 'true') {
      modes = [{ type: 'collapse-expand' }, 'drag-canvas', 'zoom-canvas', config.uuid]
    }
    const tree = new G6.TreeGraph({
      container: chartId,
      width: this.wrap.scrollWidth - 30,
      width: width,
      height: plot.height,
      fitView: true,
      layout: {
@@ -1472,13 +1470,19 @@
      },
      minZoom: 0.5,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', config.uuid]
        default: modes
      }
    })
    tree.data(dataMapTransform(data))
    tree.data(data)
    tree.render()
    if (plot.collapsed === 'true' && plot.dirField) {
      tree.zoomTo(1, { x: width / 2, y: plot.height / 2 })
    } else if (plot.collapsed === 'true') {
      tree.zoomTo(1, { x: 0, y: plot.height / 2 })
    }
  }
  handleClick = (data = null) => {
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -37,17 +37,17 @@
    transfield: {},            // 字段名称翻译
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: null,                // 数据
    search: null,              // 搜索条件
    vFields: [],               // 数值字段
    vstFields: null,           // 统计数据值字段信息
    chart: null
  }
  data = []
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = config.setting.sync === 'true'
    let BID = ''
@@ -62,11 +62,11 @@
      BID = BData.$BID || ''
    }
    if (config.setting.sync === 'true' && data) {
      _data = data[config.dataName] || []
    if (_sync && data) {
      this.data = data[config.dataName] || []
      _sync = false
    } else if (config.setting.sync === 'true' && initdata) {
      _data = initdata || []
    } else if (_sync && initdata) {
      this.data = initdata || []
      _sync = false
    }
@@ -335,7 +335,6 @@
    this.setState({
      config: _config,
      data: _data,
      BID: BID || '',
      vFields: vFields,
      vstFields: vstFields,
@@ -349,10 +348,12 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true' && _data) {
        this.handleData()
      }
    })
    if (this.data.length > 0) {
      this.handleData()
    }
  }
  /**
@@ -367,9 +368,12 @@
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, data: _data}, () => {
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      this.setState({sync: false})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -382,7 +386,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -393,6 +397,17 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.data.length > 0) return
        if (!is(fromJS(this.data), fromJS(res))) {
          this.data = res
          this.handleData()
        }
      })
    }
  }
@@ -488,11 +503,10 @@
    const { config, arr_field, BID, search } = this.state
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: []
      }, () => {
      if (!is(fromJS(this.data), fromJS([]))) {
        this.data = []
        this.handleData()
      })
      }
      return
    }
@@ -522,19 +536,18 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let reset = true
      if (hastimer && is(fromJS(result.data), fromJS(this.state.data))) {
        reset = false
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data,
        loading: false
      }, () => {
        if (!reset) return
        this.handleData()
      })
      if (!is(fromJS(this.data), fromJS(result.data || []))) {
        this.data = result.data || []
        this.handleData()
      }
    } else {
      this.setState({
        loading: false
@@ -575,15 +588,15 @@
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { data, plot, vFields, config } = this.state
    const { plot, vFields, config } = this.state
    if (!data || data.length === 0) {
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    let _cdata = fromJS(this.data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
@@ -717,7 +730,7 @@
   * @description 统计数据预处理
   */
  getStaticMsg = () => {
    const { plot, vstFields, data } = this.state
    const { plot, vstFields } = this.state
    let percent = false
    let decimal = vstFields ? vstFields.decimal : 0
@@ -726,13 +739,13 @@
      percent = true
    }
    if (!data || data.length === 0) {
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    let _cdata = fromJS(this.data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
src/tabviews/custom/components/chart/antv-dashboard/index.jsx
@@ -65,15 +65,15 @@
    chartId: Utils.getuuid(),  // 图表Id
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: {},                  // 数据
    chart: null
  }
  data = {}
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = _config.setting.sync === 'true'
    let BID = ''
@@ -89,21 +89,18 @@
    }
    if (_sync && data) {
      _data = data[config.dataName] || []
      this.data = data[config.dataName] || []
      _sync = false
    } else if (_sync && initdata) {
      _data = initdata || []
      this.data = initdata || []
      _sync = false
    }
    if (_config.subtype === 'ratioboard') {
      _data = _data || []
    } else {
      if (_data && Array.isArray(_data)) {
        _data = _data[0] || {}
      } else {
        _data = {}
    if (_config.subtype !== 'ratioboard') {
      if (Array.isArray(this.data)) {
        this.data = this.data[0] || {}
      }
      this.data.value = this.data[config.plot.valueField] || 0
    }
    _config.plot.height = Utils.getHeight(_config.plot.height)
@@ -116,7 +113,6 @@
    this.setState({
      config: _config,
      data: _data,
      BID: BID || '',
      arr_field: _config.columns.map(col => col.field).join(','),
      plot: _config.plot,
@@ -126,10 +122,12 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true') {
        this.handleData()
      }
    })
    if (config.setting.sync === 'true' && !_sync) {
      this.handleData()
    }
  }
  /**
@@ -141,24 +139,22 @@
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = null
      if (config.subtype === 'ratioboard') {
        _data = []
        if (nextProps.data && nextProps.data[config.dataName]) {
          _data = nextProps.data[config.dataName] || []
        }
      } else {
        _data = {}
        if (nextProps.data && nextProps.data[config.dataName]) {
          _data = nextProps.data[config.dataName] || {}
        }
        if (_data.hasOwnProperty(config.plot.valueField)) {
          _data.value = _data[config.plot.valueField]
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName]
        if (config.subtype !== 'ratioboard') {
          if (Array.isArray(_data)) {
            _data = _data[0] || {}
          }
          _data.value = _data[config.plot.valueField] || 0
        }
      }
      this.setState({sync: false, data: _data}, () => {
      if (_data && !is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      this.setState({sync: false})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -171,7 +167,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -180,6 +176,25 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res) return
        let _data = null
        if (config.subtype === 'ratioboard') {
          _data = res
        } else {
          _data = res[0]
          _data.value = _data[config.plot.valueField] || 0
        }
        if (!is(fromJS(this.data), fromJS(_data))) {
          this.data = _data
          this.handleData()
        }
      })
    }
  }
@@ -221,7 +236,10 @@
    if (_element) {
      _element.innerHTML = ''
    }
    this.viewrender()
    setTimeout(() => {
      this.viewrender()
    }, 100)
  }
  async loadData (hastimer) {
@@ -229,11 +247,17 @@
    const { config, arr_field, BID } = this.state
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: {}
      }, () => {
      let _data = null
      if (config.subtype === 'ratioboard') {
        _data = []
      } else {
        _data = {value: 0}
      }
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      return
    }
@@ -255,27 +279,25 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let data = null
      if (config.subtype === 'ratioboard') {
        data = result.data || []
      } else {
        data = {}
        if (result.data && result.data[0] && result.data[0].hasOwnProperty(config.plot.valueField)) {
          data.value = result.data[0][config.plot.valueField]
        }
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      let reset = true
      if (hastimer && is(fromJS(data), fromJS(this.state.data))) {
        reset = false
      let _data = null
      if (config.subtype === 'ratioboard') {
        _data = result.data || []
      } else {
        _data = result.data && result.data[0] ? result.data && result.data[0] : {}
        _data.value = _data.value[config.plot.valueField] || 0
      }
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      }
      this.setState({
        data,
        loading: false
      }, () => {
        if (!reset) return
        this.handleData()
      })
    } else {
      this.setState({
@@ -307,7 +329,7 @@
  }
  getratiodata = () => {
    const { data, plot } = this.state
    const { plot } = this.state
    let colors = {}
    if (plot.colors && plot.colors.length > 0) {
@@ -316,7 +338,7 @@
      })
    }
    return data.map(item => {
    return this.data.map(item => {
      let val = +item[plot.valueField]
      let type = item[plot.labelField] || ''
      if (isNaN(val)) {
@@ -426,22 +448,15 @@
   * @description 仪表盘渲染
   */
  dashboardrender = () => {
    const { plot, chartId, data } = this.state
    const { plot, chartId } = this.state
    let _data = fromJS(data).toJS()
    let _data = fromJS(this.data).toJS()
    _data.value = +_data.value
    if (_data.hasOwnProperty('value')) {
      if (_data.value === '' || _data.value === null) {
        delete _data.value
      } else {
        _data.value = +_data.value
        if (isNaN(_data.value)) {
          delete _data.value
        } else if (_data.value > plot.maxValue) {
          _data.value = plot.maxValue
        }
      }
    if (isNaN(_data.value)) {
      _data.value = 0
    } else if (_data.value > plot.maxValue) {
      _data.value = plot.maxValue
    }
    const chart = new Chart({
@@ -559,8 +574,9 @@
      })
    }
    if (data.hasOwnProperty('value')) {
      let val = data.value
    let val = +this.data.value
    if (!isNaN(val)) {
      if (plot.percent !== 'false' && plot.maxValue) {
        val = +(val / plot.maxValue * 100).toFixed(2) + ' %'
      }
src/tabviews/custom/components/chart/antv-pie/index.jsx
@@ -32,16 +32,16 @@
    title: '',                 // 组件标题
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: null,                // 数据
    search: null,              // 搜索条件
    chart: null
  }
  data = []
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = config.setting.sync === 'true'
    let BID = ''
@@ -56,11 +56,11 @@
      BID = BData.$BID || ''
    }
    if (config.setting.sync === 'true' && data) {
      _data = data[config.dataName] || []
    if (_sync && data) {
      this.data = data[config.dataName] || []
      _sync = false
    } else if (config.setting.sync === 'true' && initdata) {
      _data = initdata || []
    } else if (_sync && initdata) {
      this.data = initdata || []
      _sync = false
    }
@@ -83,7 +83,6 @@
    this.setState({
      config: _config,
      data: _data,
      BID: BID || '',
      arr_field: _config.columns.map(col => col.field).join(','),
      plot: _config.plot,
@@ -95,10 +94,12 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true' && _data) {
        this.handleData()
      }
    })
    if (this.data.length > 0) {
      this.handleData()
    }
  }
  /**
@@ -113,9 +114,12 @@
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, data: _data}, () => {
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      this.setState({sync: false})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -128,7 +132,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -137,6 +141,17 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.data.length > 0) return
        if (!is(fromJS(this.data), fromJS(res))) {
          this.data = res
          this.handleData()
        }
      })
    }
  }
@@ -174,12 +189,18 @@
  }
  handleData = () => {
    const { plot, chartId } = this.state
    let _element = document.getElementById(chartId)
    let _element = document.getElementById(this.state.chartId)
    if (_element) {
      _element.innerHTML = ''
    }
    setTimeout(() => {
      this.viewrender()
    }, 100)
  }
  viewrender = () => {
    const { plot } = this.state
    if (plot.shape === 'nest') {
      this.nestrender()
@@ -193,11 +214,10 @@
    const { config, arr_field, search, BID } = this.state
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: []
      }, () => {
      if (!is(fromJS(this.data), fromJS([]))) {
        this.data = []
        this.handleData()
      })
      }
      return
    }
@@ -227,19 +247,18 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let reset = true
      if (hastimer && is(fromJS(result.data), fromJS(this.state.data))) {
        reset = false
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data,
        loading: false
      }, () => {
        if (!reset) return
        this.handleData()
      })
      if (!is(fromJS(this.data), fromJS(result.data || []))) {
        this.data = result.data || []
        this.handleData()
      }
    } else {
      this.setState({
        loading: false
@@ -267,15 +286,15 @@
   * 3、柱状图数据补齐
   */
  getdata = () => {
    const { data, plot } = this.state
    const { plot } = this.state
    if (!data) {
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    let _cdata = fromJS(this.data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
@@ -360,15 +379,15 @@
  }
  getnestdata = () => {
    const { data, plot } = this.state
    const { plot } = this.state
    if (!data) {
    if (this.data.length === 0) {
      this.setState({empty: true})
      return []
    }
    let _data = []
    let _cdata = fromJS(data).toJS()
    let _cdata = fromJS(this.data).toJS()
    if (plot.repeat === 'average') {
      let _mdata = new Map()
src/tabviews/custom/components/chart/antv-scatter/index.jsx
@@ -33,15 +33,15 @@
    chartId: Utils.getuuid(),  // 图表Id
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: null,                // 数据
    search: null,              // 搜索条件
    chart: null
  }
  data = []
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = config.setting.sync === 'true'
    let BID = ''
@@ -56,11 +56,11 @@
      BID = BData.$BID || ''
    }
    if (config.setting.sync === 'true' && data) {
      _data = data[config.dataName] || []
    if (_sync && data) {
      this.data = data[config.dataName] || []
      _sync = false
    } else if (config.setting.sync === 'true' && initdata) {
      _data = initdata || []
    } else if (_sync && initdata) {
      this.data = initdata || []
      _sync = false
    }
@@ -74,9 +74,8 @@
    this.setState({
      config: _config,
      data: _data,
      BID: BID || '',
      empty: !_data,
      empty: this.data.length === 0,
      arr_field: _config.columns.map(col => col.field).join(','),
      plot: _config.plot,
      sync: _sync,
@@ -86,10 +85,12 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true' && _data) {
        this.handleData()
      }
    })
    if (this.data.length > 0) {
      this.handleData()
    }
  }
  /**
@@ -104,9 +105,12 @@
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, data: _data, empty: !_data,}, () => {
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      this.setState({sync: false, empty: _data.length === 0})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -119,7 +123,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -130,6 +134,19 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.data.length > 0) return
        if (!is(fromJS(this.data), fromJS(res))) {
          this.data = res
          this.handleData()
        }
        this.setState({empty: false})
      })
    }
  }
@@ -225,12 +242,12 @@
    const { config, arr_field, BID, search } = this.state
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: [],
        empty: false,
      }, () => {
      this.setState({ empty: true })
      if (!is(fromJS(this.data), fromJS([]))) {
        this.data = []
        this.handleData()
      })
      }
      return
    }
@@ -260,20 +277,19 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let reset = true
      if (hastimer && is(fromJS(result.data), fromJS(this.state.data))) {
        reset = false
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      
      this.setState({
        data: result.data,
        empty: false,
        empty: !result.data || result.data.length === 0,
        loading: false
      }, () => {
        if (!reset) return
        this.handleData()
      })
      if (!is(fromJS(this.data), fromJS(result.data || []))) {
        this.data = result.data || []
        this.handleData()
      }
    } else {
      this.setState({
        loading: false
@@ -302,21 +318,24 @@
    if (_element) {
      _element.innerHTML = ''
    }
    this.scatterrender()
    setTimeout(() => {
      this.scatterrender()
    }, 100)
  }
  /**
   * @description 散点图渲染
   */
  scatterrender = () => {
    const { plot, data, chartId } = this.state
    const { plot, chartId } = this.state
    const chart = new Chart({
      container: chartId,
      autoFit: true,
      height: plot.height
    })
    chart.data(data);
    chart.data(this.data);
    chart.scale({
      [plot.Xaxis]: { nice: true },
      [plot.Yaxis]: { nice: true },
src/tabviews/custom/components/chart/custom-chart/index.jsx
@@ -28,14 +28,14 @@
    loading: false,            // 数据加载状态
    sync: false,               // 是否统一请求数据
    plot: null,                // 图表设置
    data: null,                // 数据
    search: null,              // 搜索条件
  }
  data = []
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
    let _data = null
    let _sync = config.setting.sync === 'true'
    let BID = ''
@@ -50,11 +50,11 @@
      BID = BData.$BID || ''
    }
    if (config.setting.sync === 'true' && data) {
      _data = data[config.dataName] || []
    if (_sync && data) {
      this.data = data[config.dataName] || []
      _sync = false
    } else if (config.setting.sync === 'true' && initdata) {
      _data = initdata || []
    } else if (_sync && initdata) {
      this.data = initdata || []
      _sync = false
    }
@@ -63,8 +63,7 @@
    this.setState({
      config: _config,
      data: _data,
      empty: !_data || _data.length === 0,
      empty: this.data.length === 0,
      BID: BID || '',
      arr_field: _config.columns.map(col => col.field).join(','),
      plot: _config.plot,
@@ -75,10 +74,12 @@
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
      } else if (config.setting.sync === 'true' && _data) {
        this.handleData()
      }
    })
    if (this.data.length > 0) {
      this.handleData()
    }
  }
  /**
@@ -93,9 +94,12 @@
        _data = nextProps.data[config.dataName] || []
      }
      this.setState({sync: false, data: _data, empty: _data.length === 0}, () => {
      if (!is(fromJS(this.data), fromJS(_data))) {
        this.data = _data
        this.handleData()
      })
      }
      this.setState({sync: false, empty: _data.length === 0})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -108,7 +112,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, sync } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -119,6 +123,18 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && (config.setting.sync !== 'true' || sync)) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.data.length > 0) return
        if (!is(fromJS(this.data), fromJS(res))) {
          this.data = res
          this.handleData()
        }
        this.setState({empty: false})
      })
    }
  }
@@ -215,10 +231,13 @@
    if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: []
      }, () => {
        this.handleData()
        empty: true
      })
      if (!is(fromJS(this.data), fromJS([]))) {
        this.data = []
        this.handleData()
      }
      return
    }
@@ -248,20 +267,19 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let reset = true
      if (hastimer && is(fromJS(result.data), fromJS(this.state.data))) {
        reset = false
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data,
        loading: false,
        empty: result.data.length === 0
      }, () => {
        if (!reset) return
        this.handleData()
        empty: !result.data || result.data.length === 0
      })
      if (!is(fromJS(this.data), fromJS(result.data || []))) {
        this.data = result.data || []
        this.handleData()
      }
    } else {
      this.setState({
        loading: false
@@ -287,14 +305,14 @@
    
    setTimeout(() => {
      this.viewrender()
    }, 150)
    }, 100)
  }
  /**
   * @description 图表渲染分组
   */
  viewrender = () => {
    const { config, data } = this.state
    const { config } = this.state
    if (!config.plot.script) return
@@ -302,7 +320,7 @@
      try {
        // eslint-disable-next-line
        let func = new Function('Chart', 'DataSet', 'wrap', 'data', 'config', config.plot.script)
        func(Chart, DataSet, this.wrap, data, config)
        func(Chart, DataSet, this.wrap, this.data, config)
      } catch (e) {
        console.warn(e)
  
@@ -316,7 +334,7 @@
      try {
        // eslint-disable-next-line
        let func = new Function('echarts', 'DataSet', 'wrap', 'data', 'config', config.plot.script)
        func(echarts, DataSet, this.wrap, data, config)
        func(echarts, DataSet, this.wrap, this.data, config)
      } catch (e) {
        console.warn(e)
  
@@ -347,7 +365,7 @@
            <Spin />
          </div> : null
        }
        <NormalHeader config={config} BID={BID} refresh={this.refreshSearch} />
        <NormalHeader config={config} BID={BID} refresh={this.refreshSearch}/>
        <div className="canvas-wrap" style={{height: (config.plot.height + 30) + 'px'}}>
          <div className={'canvas' + (empty ? ' empty' : '')} style={{height: config.plot.height + 'px'}} ref={ref => this.wrap = ref}></div>
        </div>
src/tabviews/custom/components/code/sand-box/index.jsx
@@ -24,6 +24,8 @@
    html: '',
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
@@ -49,12 +51,15 @@
      if (_sync && data) {
        _data = data[_config.dataName] || {}
        _sync = false
        this.loaded = true
      } else if (_sync && initdata) {
        _data = initdata || {}
        _sync = false
        this.loaded = true
      }
    } else {
      _data = {}
      this.loaded = true
    }
    
    if (_config.css) {
@@ -84,7 +89,19 @@
  }
  componentDidMount () {
    const { config } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        this.setState({data: res[0]}, () => {
          this.renderView()
        })
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -110,9 +127,15 @@
        _data = nextProps.data[config.dataName]
      }
      this.setState({sync: false, data: _data}, () => {
        this.renderView()
      })
      this.loaded = true
      this.setState({sync: false, data: _data})
      if (!is(fromJS(this.state.data), fromJS(_data))) {
        setTimeout(() => {
          this.renderView()
        }, 10)
      }
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
@@ -143,6 +166,7 @@
        data: {},
        loading: false
      })
      this.loaded = true
      return
    }
@@ -164,12 +188,21 @@
    if (result.status) {
      let _data = result.data || {}
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: _data,
        loading: false
      }, () => {
        this.renderView()
      })
      if (!is(fromJS(this.state.data), fromJS(_data))) {
        setTimeout(() => {
          this.renderView()
        }, 10)
      }
    } else {
      this.setState({
        loading: false
src/tabviews/custom/components/group/normal-group/index.jsx
@@ -103,14 +103,15 @@
   * @description 主表数据加载
   */ 
  loadmaindata = (params) => {
    const { config } = this.props
    let BID = ''
    let BData = window.GLOB.CacheData.get(this.props.config.$pageId)
    let BData = window.GLOB.CacheData.get(config.$pageId)
    if (BData) {
      BID = BData.$BID || ''
    }
    let param = getStructuredParams(params, this.props.config, BID)
    let param = getStructuredParams(params, config, BID)
    Api.genericInterface(param).then(result => {
      if (result.status) {
@@ -119,6 +120,16 @@
        delete result.ErrMesg
        delete result.ErrCode
        if (config.$cache) {
          params.forEach((item) => {
            let _data = result[item.name] || ''
            if (_data && !Array.isArray(_data)) {
              _data = [_data]
            }
            Api.writeCacheConfig(item.uuid, _data)
          })
        }
        this.setState({
          data: result
        })
src/tabviews/custom/components/iframe/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Input, Modal, notification, Empty } from 'antd'
import { Input, Modal, notification, Empty, Spin } from 'antd'
import Api from '@/api'
import UtilsDM from '@/utils/utils-datamanage.js'
@@ -82,8 +82,17 @@
  }
  componentDidMount () {
    const { config } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    if (config.wrap.linkType === 'input' && config.wrap.focus !== 'false') {
      setTimeout(() => {
        let node = document.getElementById(config.uuid)
        node && node.select && node.select()
      }, 200)
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -183,13 +192,9 @@
      this.setState({
        linkUrl: _data[config.wrap.linkField] || '',
        data: _data,
        loading: false
        data: _data
      })
    } else {
      this.setState({
        loading: false
      })
      if (result.ErrCode === 'N') {
        Modal.error({
          title: result.message,
@@ -215,30 +220,43 @@
    }
    if (submit) {
      this.setState({linkUrl: val}, () => {
        let node = document.getElementById(this.state.config.uuid)
        node && node.select && node.select()
      this.setState({linkUrl: '', loading: true}, () => {
        this.setState({linkUrl: val})
      })
      setTimeout(() => {
        this.setState({loading: false}, () => {
          let node = document.getElementById(this.state.config.uuid)
          node && node.select && node.select()
        })
      }, 500)
    }
  }
  enterUrl = (val) => {
    this.setState({linkUrl: val}, () => {
      let node = document.getElementById(this.state.config.uuid)
      node && node.select && node.select()
    this.setState({linkUrl: '', loading: true}, () => {
      this.setState({linkUrl: val})
    })
    setTimeout(() => {
      this.setState({loading: false}, () => {
        let node = document.getElementById(this.state.config.uuid)
        node && node.select && node.select()
      })
    }, 500)
  }
  render() {
    const { config, linkUrl } = this.state
    const { config, linkUrl, loading } = this.state
    return (
      <div className="menu-iframe-box" style={config.style}>
        {config.wrap.title || config.wrap.linkType === 'input' ? <div className="iframe-header" style={config.headerStyle}>
          <span className="title">{config.wrap.title}</span>
          {config.wrap.linkType === 'input' ? <Search id={config.uuid} placeholder="请输入地址" onChange={this.inputUrl} onSearch={this.enterUrl} enterButton="确定"/> : null}
          {config.wrap.linkType === 'input' ? <Search id={config.uuid} disabled={loading} placeholder="请输入地址" onChange={this.inputUrl} onSearch={this.enterUrl} enterButton="确定"/> : null}
        </div> : null}
        <div className="iframe-wrap" style={{height: config.wrap.height}}>
          {loading ? <div className="mask"><Spin size="large" /></div> : null}
          {linkUrl ? <iframe title="mk" className="iframe" src={linkUrl} frameBorder="0"></iframe> : <Empty description={false}/>}
        </div>
      </div>
src/tabviews/custom/components/iframe/index.scss
@@ -33,9 +33,15 @@
    .ant-input-search {
      margin-top: 5px;
      width: 40%;
      max-width: 400px;
      width: 65%;
      float: right;
      .ant-btn[disabled] {
        background-color: var(--mk-sys-color)!important;
        border-color: var(--mk-sys-color)!important;
        color: #ffffff!important;
        opacity: 0.5;
      }
    }
  }
@@ -57,5 +63,21 @@
      vertical-align: top;
      margin-top: 0px;
    }
    .mask {
      position: absolute;
      width: 100%;
      height: 100%;
      left: 0px;
      top: 0px;
      background: #ffffff;
      z-index: 1;
      .ant-spin {
        position: absolute;
        left: calc(50% - 16px);
        top: calc(50% - 16px);
      }
    }
  }
}
src/tabviews/custom/components/module/account/index.jsx
New file
@@ -0,0 +1,148 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { notification, Select, Divider } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import Api from '@/api'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const { Option } = Select
class AccountModule extends Component {
  static propTpyes = {
    config: PropTypes.object
  }
  state = {
    activeItem: null,
    books: []
  }
  componentDidMount () {
    this.loadData()
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  loadData = () => {
    let param = {
      func: 's_get_fcc_book_data'
    }
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      let books = res.book || []
      let activeItem = null
      let map = new Map()
      books = books.filter(item => {
        if (!item.id) return false
        if (map.has(item.id)) return false
        map.set(item.id, true)
        if (item.selected === 'true' && !activeItem) {
          activeItem = item
        }
        if (item.months) {
          item.date = item.months.replace('-', '年') + '月'
        }
        return true
      })
      if (!activeItem && books.length > 0) {
        activeItem = books[0]
      }
      this.setState({books, activeItem})
      if (activeItem) {
        MKEmitter.emit('resetSelectLine', this.props.config.uuid, activeItem.id, activeItem)
      }
    })
  }
  changeBook = (value) => {
    const { books } = this.state
    let activeItem = books.filter(item => item.id === value)[0]
    this.setState({activeItem})
    if (activeItem) {
      MKEmitter.emit('resetSelectLine', this.props.config.uuid, activeItem.id, activeItem)
    }
  }
  addBook = () => {
    const { config } = this.props
    let menuId = config.wrap.MenuID
    let menu = window.GLOB.mkThdMenus.filter(m => m.MenuID === menuId)[0]
    if (!menu && config.wrap.MenuNo) {
      menu = {
        MenuID: menuId,
        MenuName: config.wrap.MenuName,
        MenuNo: config.wrap.MenuNo || '',
        type: config.wrap.tabType
      }
    }
    let newtab = {
      ...menu,
      param: {}
    }
    MKEmitter.emit('modifyTabs', newtab, true)
  }
  render() {
    const { config } = this.props
    const { activeItem, books } = this.state
    return (
      <div className="menu-account-wrap" style={config.style}>
        {config.wrap.MenuID ? <Select value={activeItem ? activeItem.id : ''} placeholder="请选择账套" onChange={this.changeBook} dropdownRender={menu => (
          <div>
            {menu}
            <Divider style={{ margin: '4px 0' }} />
            <div className="mk-add-book" onMouseDown={this.addBook}>
              <PlusOutlined /> 点击新增账套
            </div>
          </div>
        )}>
          {books.map(item => (
            <Option key={item.id}>{item.account_name}</Option>
          ))}
        </Select> : <Select value={activeItem ? activeItem.id : ''} placeholder="请选择账套" onChange={this.changeBook}>
          {books.map(item => (
            <Option key={item.id}>{item.account_name}</Option>
          ))}
        </Select>}
        {activeItem ? <span className="date">{activeItem.date}</span> : null}
      </div>
    )
  }
}
export default AccountModule
src/tabviews/custom/components/module/account/index.scss
New file
@@ -0,0 +1,27 @@
.menu-account-wrap {
  position: relative;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  color: #000000;
  .ant-select {
    min-width: 250px;
    max-width: 300px;
    color: #000000;
  }
  .date {
    margin-left: 15px;
  }
}
.mk-add-book {
  padding: 4px 8px 10px;
  cursor: pointer;
  text-align: center;
  color: var(--mk-sys-color);
}
src/tabviews/custom/components/module/voucher/assistTable/index.jsx
@@ -7,9 +7,6 @@
import Api from '@/api'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import '@/assets/css/table.scss'
import './index.scss'
class BodyRow extends React.Component {
@@ -211,7 +208,6 @@
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    data: [],
    edData: [],
    edColumns: [],
@@ -648,12 +644,12 @@
    if (res && res.ErrCode === 'S') { // 执行成功
      notification.success({
        top: 92,
        message: res.ErrMesg || this.state.dict['main.action.confirm.success'],
        message: res.ErrMesg || '执行成功',
        duration: submit.stime ? submit.stime : 2
      })
    } else if (res && res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.ErrMesg || this.state.dict['main.action.confirm.success']
        title: res.ErrMesg || '执行成功'
      })
    } else if (res && res.ErrCode === '-1') { // 完成后不提示
src/tabviews/custom/components/module/voucher/index.jsx
@@ -1,11 +1,12 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Button, Select, Input, DatePicker } from 'antd'
// import { EditOutlined, ToolOutlined, DeleteOutlined, FontColorsOutlined } from '@ant-design/icons'
import { Button, Select, Input, DatePicker, notification } from 'antd'
import moment from 'moment'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
// import MKEmitter from '@/utils/events.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const VoucherTable = asyncComponent(() => import('./voucherTable'))
@@ -17,14 +18,17 @@
  state = {
    BID: '',
    type: '',
    config: null,
    loading: false,
    data: null,
    searchkey: null,
    disableAdd: true,
    disableSave: true,
    typeOptions: []
    data: [],
    disableAdd: false,
    disableSave: false,
    typeOptions: [],
    subjects: [],
    charType: '',
    charInt: '',
    vouDate: null,
    book: null
  }
  UNSAFE_componentWillMount () {
@@ -33,8 +37,8 @@
    let BID = ''
    let BData = ''
    if (config.setting.supModule) {
      BData = window.GLOB.CacheData.get(config.setting.supModule)
    if (config.wrap.supModule) {
      BData = window.GLOB.CacheData.get(config.wrap.supModule)
    } else {
      BData = window.GLOB.CacheData.get(config.$pageId)
    }
@@ -45,14 +49,14 @@
    this.setState({
      config: fromJS(config).toJS(),
      BID: BID || '',
      type: config.wrap.type
      book: window.GLOB.CacheData.get(config.wrap.supBook) || null
    }, () => {
      this.loadData()
    })
  }
  componentDidMount () {
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -66,10 +70,83 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
  }
  resetParentParam = (MenuID, id, data) => {
    const { config } = this.state
    if (config.wrap.supBook === MenuID) {
      let month = data.months
      let vouDate = moment()
      if (month && month < moment().format('YYYY-MM')) {
        vouDate = moment(month, 'YYYY-MM').endOf('month')
      }
      this.setState({ book: data, vouDate }, () => {
        this.loadData()
      })
      return
    }
    if (!config.wrap.supModule || config.wrap.supModule !== MenuID) return
    if (id !== this.state.BID || id !== '') {
      this.setState({ BID: id, BData: data }, () => {
        this.loadData()
      })
    }
  }
  loadData = () => {
    const { book } = this.state
    if (!book) return
    let param = {
      func: 's_get_fcc_account_data',
      account_code: book.account_code || '',
      fcc_date: book.months ? book.months + '-01' : moment().format('YYYY-MM-DD')
    }
    Api.genericInterface(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      let typeOptions = res.char || []
      this.setState({
        typeOptions: typeOptions,
        charType: typeOptions[0] ? typeOptions[0].voucher_class : '',
        charInt: typeOptions[0] ? typeOptions[0].voucher_char_int : '',
        subjects: res.subjects || [],
      })
      setTimeout(() => {
        this.getVoucher()
      }, 200)
    })
  }
  getVoucher = () => {
    let data = [
      {remark: '提现', subjectscode: '1001', subjectsname: '库存现金', debtor: 124, creditor: ''},
      {remark: '购入固定资产', subjectscode: '1001', subjectsname: '库存现金', debtor: '', creditor: 124},
      {remark: '转结销售成本', subjectscode: '1001', subjectsname: '库存现金', debtor: -524, creditor: ''},
      {remark: '提现', subjectscode: '1001', subjectsname: '库存现金', debtor: 34, creditor: ''},
    ]
    this.setState({
      data: data
    })
  }
  triggeradd = () => {
@@ -85,29 +162,29 @@
  }
  render() {
    const { config, disableSave, disableAdd, typeOptions, data, type } = this.state
    const { config, disableSave, disableAdd, typeOptions, charType, charInt, data, vouDate, subjects } = this.state
    return (
      <div className="menu-voucher-wrap" style={config.style}>
        <div className="voucher-header">
          <Button className="system-background header-btn" disabled={disableAdd} onClick={this.triggeradd}>新增</Button>
          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggersave}>保存</Button>
          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggerprint}>打印</Button>
          <Button className="add-background header-btn" disabled={disableAdd} onClick={this.triggeradd}>新增</Button>
          <Button className="add-background header-btn" disabled={disableSave} onClick={this.triggersave}>保存</Button>
          <Button className="print-background header-btn" disabled={disableSave} onClick={this.triggerprint}>打印</Button>
          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggerprint}>导入</Button>
          <Button className="system-background header-btn" disabled={disableSave} onClick={this.triggerprint}>导出</Button>
          <Button className="out-background header-btn" disabled={disableSave} onClick={this.triggerprint}>导出</Button>
        </div>
        {type === 'edit' ? <div className="voucher-body">
        {config.wrap.type === 'edit' ? <div className="voucher-body">
          <div className="pre-wrap">
            <div className="voucher-code">
              <Select>
              <Select value={charType} dropdownClassName="mk-vcode-dropdown" onChange={(val, option) => this.setState({charType: val, charInt: option.props.charint})}>
                {typeOptions.map(option =>
                  <Select.Option value={option.value}>{option.label}</Select.Option>
                  <Select.Option key={option.voucher_char_int} value={option.voucher_class} charint={option.voucher_char_int}>{option.voucher_char}</Select.Option>
                )}
              </Select>
              <Input autoComplete="off" /> 号
              <Input value={charInt} autoComplete="off" onChange={(e) => this.setState({charInt: e.target.value})}/> 号
            </div>
            <div className="voucher-date">
              日期:<DatePicker onChange={this.onChange}/>
              日期:<DatePicker value={vouDate} onChange={(val) => this.setState({vouDate: val})}/>
            </div>
            <div className="voucher-affix">
              附单据 <Input autoComplete="off" /> 张
@@ -115,9 +192,9 @@
              <Button type="link" className="" onClick={this.triggerprint}>备注</Button>
            </div>
          </div>
          <VoucherTable config={config} data={data}/>
          <VoucherTable config={config} subjects={subjects} data={data}/>
        </div> : null}
        {type === 'check' ? <div className="voucher-body">
        {config.wrap.type === 'check' ? <div className="voucher-body">
          <div className="pre-wrap">
            <div className="voucher-code">
              记 1 号
src/tabviews/custom/components/module/voucher/index.scss
@@ -51,6 +51,35 @@
      }
    }
  }
  .add-background {
    background: #26C281;
    border-color: #26C281;
    color: #ffffff;
  }
  .print-background {
    background-color: #8E44AD;
    border-color: #8E44AD;
    color: #ffffff;
  }
  .out-background {
    background-color: rgb(50, 197, 210);
    border-color: rgb(50, 197, 210);
    color: #ffffff;
  }
  .system-background {
    background: var(--mk-sys-color);
    border-color: var(--mk-sys-color);
    color: #ffffff;
  }
}
.mk-vcode-dropdown {
  .ant-empty-image svg {
    max-width: 100%;
  }
  .ant-empty-description {
    display: none;
  }
}
src/tabviews/custom/components/module/voucher/voucherTable/index.jsx
@@ -1,15 +1,13 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Table, Modal, Input, InputNumber, notification, message } from 'antd'
// import { EditOutlined } from '@ant-design/icons'
import { Table, Modal, Input, InputNumber, notification, message, AutoComplete, Select } from 'antd'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import '@/assets/css/table.scss'
import './index.scss'
class BodyRow extends React.Component {
@@ -80,7 +78,7 @@
      if (col.field === 'creditor') {
        MKEmitter.emit('nextLine', col, record)
      } else {
        let cl = {remark: 'subject', subject: 'debtor', debtor: 'creditor'}
        let cl = {remark: 'subjectscode', subjectscode: 'debtor', debtor: 'creditor'}
        MKEmitter.emit('tdFocus', cl[col.uuid] + record.uuid)
      }
    }, 50)
@@ -91,10 +89,19 @@
    if (record.type === 'total') return
    this.setState({editing: true, value: record[col.field]}, () => {
      let node = document.getElementById(col.uuid + record.uuid)
      node && node.select()
    })
    if (col.field === 'subjectscode') {
      this.setState({editing: true}, () => {
        try {
          let node = document.getElementById(col.uuid + record.uuid)
          node.click()
        } catch(e) {}
      })
    } else {
      this.setState({editing: true, value: record[col.field]}, () => {
        let node = document.getElementById(col.uuid + record.uuid)
        node && node.select()
      })
    }
  }
  onBlur = () => {
@@ -102,6 +109,8 @@
    const { value } = this.state
    this.setState({editing: false})
    if (col.field === 'subjectscode') return
    if (value !== record[col.field]) {
      let line = {...record, [col.field]: value}
@@ -120,8 +129,28 @@
    this.setState({value: val})
  }
  complete = (val) => {
    this.setState({value: val}, () => {
      this.onBlur()
    })
  }
  onSelectChange = (val, option) => {
    const { col, record } = this.props
    this.setState({editing: false})
    let line = {...record, ...option.props.extra}
    MKEmitter.emit('changeRecord', col.tableId, line)
    setTimeout(() => {
      MKEmitter.emit('tdFocus', 'debtor' + record.uuid)
    }, 50)
  }
  render() {
    let { col, record, className } = this.props
    let { col, record, subjects, className } = this.props
    const { editing } = this.state
    let children = null
@@ -135,20 +164,44 @@
        colSpan = 2
      } else {
        if (editing) {
          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
          let options = ['现金', '发票']
          children = <AutoComplete
            dataSource={options.map((cell, i) => <AutoComplete.Option value={cell} key={i}>
              {cell}
            </AutoComplete.Option>)}
            filterOption={(input, option) => option.props.children.indexOf(input) > -1}
            onSelect={this.complete}
            defaultValue={val}
            onChange={(val) => this.onChange(val)}
            defaultOpen={true}
          >
            <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
          </AutoComplete>
        } else {
          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
        }
      }
    } else if (col.field === 'subject') {
    } else if (col.field === 'subjectscode') {
      if (record.type === 'total') {
        colSpan = 0
      } else {
        let val = record.subject || ''
        if (editing) {
          children = <Input.TextArea id={col.uuid + record.uuid} autoSize={false} defaultValue={val} onChange={(e) => this.onChange(e.target.value)} onPressEnter={this.enterPress} onBlur={this.onBlur}/>
          children = <Select
            showSearch
            defaultValue={record.subjectscode || ''}
            dropdownClassName="edit-table-dropdown"
            id={col.uuid + record.uuid}
            onBlur={this.onBlur}
            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            onSelect={this.onSelectChange}
          >
            {subjects.map((item, i) => (<Select.Option key={i} extra={item} value={item.subjectscode}>{item.subjectscode + ' ' + item.subjectsname}</Select.Option>))}
          </Select>
        } else {
          let val = ''
          if (record.subjectscode) {
            val = (record.subjectscode || '') + ' ' + (record.subjectsname || '')
          }
          children = <div className="content-wrap" onClick={this.focus}>{val}</div>
        }
      }
@@ -203,6 +256,7 @@
class VoucherTable extends Component {
  static propTpyes = {
    config: PropTypes.object,        // 菜单Id
    subjects: PropTypes.array,       // 会计科目
    BID: PropTypes.any,              // 主表ID
    data: PropTypes.any,             // 表格数据
    total: PropTypes.any,            // 总数
@@ -222,17 +276,7 @@
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    let data = [
      {remark: '提现', subject: '1001 库存现金', debtor: 124, creditor: ''},
      {remark: '购入固定资产', subject: '1001 库存现金', debtor: '', creditor: 124},
      {remark: '转结销售成本', subject: '1001 库存现金', debtor: -524, creditor: ''},
      {remark: '提现', subject: '1001 库存现金', debtor: 34, creditor: ''},
    ]
    data = this.initData(data)
    data.push(this.getTotalLine(data))
    const { config, subjects, data } = this.props
    let columns = [
      {
@@ -247,12 +291,13 @@
      },
      {
        title: '会计科目',
        dataIndex: 'subject',
        key: 'subject',
        dataIndex: 'subjectscode',
        key: 'subjectscode',
        width: '34%',
        onCell: record => ({
          record,
          col: {uuid: 'subject', field: 'subject', tableId: config.uuid},
          subjects,
          col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
        })
      },
      {
@@ -290,8 +335,7 @@
    ]
    this.setState({
      data: data,
      edData: fromJS(data).toJS(),
      edData: this.resetData(fromJS(data).toJS()),
      columns,
      tableId: config.uuid
    })
@@ -321,8 +365,43 @@
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (!is(fromJS(this.props.data), fromJS(nextProps.data))) {
      this.setState({data: nextProps.data || []})
      this.resetData(fromJS(nextProps.data).toJS())
    } else if (!is(fromJS(this.props.subjects), fromJS(nextProps.subjects))) {
      this.resetSubjects(nextProps.subjects)
    }
  }
  resetSubjects = (subjects) => {
    const { config } = this.props
    let columns = fromJS(this.state.columns).toJS()
    this.setState({
      columns: columns.map(col => {
        if (col.key === 'subjectscode') {
          return {
            title: '会计科目',
            dataIndex: 'subjectscode',
            key: 'subjectscode',
            width: '34%',
            onCell: record => ({
              record,
              subjects,
              col: {uuid: 'subjectscode', field: 'subjectscode', tableId: config.uuid},
            })
          }
        }
        return col
      })
    })
  }
  resetData = (data) => {
    data = this.initData(data)
    data.push(this.getTotalLine(data))
    this.setState({
      edData: data
    })
  }
  initData = (data) => {
@@ -335,7 +414,7 @@
    if (_data.length < 4) {
      for (let i = _data.length - 1; i < 4; i++) {
        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
      }
    }
    return _data
@@ -464,7 +543,7 @@
      MKEmitter.emit('tdFocus', 'remark' + edData[record.index + 1].uuid)
    } else {
      let _data = fromJS(edData).toJS()
      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subject: '', debtor: '', creditor: ''}
      let line = {uuid: Utils.getuuid(), index: _data.length - 1, remark: record.remark || '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''}
      _data.splice(_data.length - 1, 0, line)
@@ -498,7 +577,7 @@
    if (_data.length < 4) {
      for (let i = _data.length - 1; i < 4; i++) {
        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subject: '', debtor: '', creditor: ''})
        _data.push({uuid: Utils.getuuid(), index: i + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
      }
    }
@@ -521,7 +600,7 @@
    _data.pop()
    if (record.index === _data.length - 1) {
      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subject: '', debtor: '', creditor: ''})
      _data.push({uuid: Utils.getuuid(), index: record.index + 1, remark: '', subjectscode: '', subjectsname: '', debtor: '', creditor: ''})
    }
    _data.push(this.getTotalLine(_data))
src/tabviews/custom/components/module/voucher/voucherTable/index.scss
@@ -112,6 +112,18 @@
      }
    }
  }
  .ant-select-auto-complete {
    width: 100%;
    .ant-input {
      height: 60px;
      border-radius: 0;
      resize: none;
    }
    .ant-select-selection {
      height: 60px;
    }
  }
  .ant-input {
    height: 60px;
    border-radius: 0;
@@ -127,6 +139,22 @@
    .ant-input-number-input {
      border-radius: 0;
      height: 60px;
    }
  }
  .ant-select {
    padding: 0px;
    position: absolute;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    .ant-select-selection {
      height: 100%;
      border-radius: 0;
      .ant-select-arrow {
        display: none;
      }
    }
  }
  .editing_table_cell {
@@ -169,91 +197,10 @@
    }
  }
}
.edit-custom-table.editable {
  td {
    background-color: #ffffff!important;
  }
  td.pointer .mk-mask {
    display: block;
  }
  .mk-operation {
    display: none;
  }
  .ant-table-placeholder {
    display: none;
.edit-table-dropdown {
  .ant-select-dropdown-menu-item {
    white-space: unset;
    text-overflow: unset;
  }
}
.edit-custom-table:not(.fixed-height) {
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
  }
  ::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  ::-webkit-scrollbar-track {/*滚动条里面轨道*/
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
}
.edit-custom-table.fixed-height {
  .ant-table-body {
    border-bottom: 1px solid rgba(0, 0, 0, .05);
    .ant-table-fixed {
      border-bottom: 0;
    }
  }
}
.edit-custom-table.hidden {
  thead {
    display: none;
  }
}
.edit-custom-table.ghost {
  .ant-table-thead > tr {
    > th {
      color: inherit;
      background: transparent;
      .ant-table-column-sorter .ant-table-column-sorter-inner {
        color: inherit;
      }
    }
    > th:hover {
      background: transparent;
    }
  }
  .ant-table-body {
    overflow-x: auto;
    tr {
      td {
        background: transparent!important;
      }
    }
    tr:hover td {
      background: transparent!important;
    }
  }
}
.image-scale-modal {
  width: 70vw;
  min-height: 80vh;
  top: 10vh;
  .ant-modal-body {
    min-height: calc(80vh - 110px);
    line-height: calc(80vh - 160px);
    text-align: center;
  }
  .ant-modal-footer {
    text-align: center;
    span {
      display: inline-block;
      color: #1890ff;
      padding: 5px 15px;
      cursor: pointer;
    }
  }
}
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -8,10 +8,7 @@
import { getMark } from '@/utils/utils.js'
import MkIcon from '@/components/mk-icon'
import MKEmitter from '@/utils/events.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Encrypts from '@/components/encrypts'
import '@/assets/css/table.scss'
import './index.scss'
const { Paragraph } = Typography
@@ -385,7 +382,10 @@
        <CardCellComponent data={record} cards={config} elements={col.elements}/>
      )
    } else if (col.type === 'action') {
      style.padding = '0px 5px'
      style.padding = '0px'
      if (col.style) {
        style = {...style, ...col.style}
      }
      resProps.children = (
        <CardCellComponent data={record} cards={config} elements={col.elements}/>
      )
@@ -413,7 +413,6 @@
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    tableId: '',          // 表格ID
    selectedRowKeys: [],  // 表格中选中行
    pageIndex: 1,         // 初始页面索引
@@ -615,10 +614,32 @@
    this.props.refreshdata({pageIndex})
  }
  mkCheckTopLine = (menuId, id) => {
  mkCheckTopLine = (menuId, id, type) => {
    const { MenuID, data, setting } = this.props
    if (MenuID !== menuId || !data || data.length === 0) return
    if (type === 'sign') {
      let index = ''
      let keys = []
      let items = []
      data.forEach((item, i) => {
        if (!item.$disabled && item.selected === 'true') {
          items.push(item)
          keys.push(i)
          index = i
        }
      })
      this.changedata(index)
      this.setState({ selectedRowKeys: keys, activeIndex: index })
      this.props.chgSelectData(items)
      if (setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', MenuID, items, data.length === keys.length)
      }
      return
    }
    let index = 0
    if (id) {
@@ -717,7 +738,7 @@
  /**
   * 
   */
  onSelectChange = selectedRowKeys => {
  onSelectChange = (selectedRowKeys, e) => {
    const { setting, MenuID, data } = this.props
    let index = ''
@@ -816,13 +837,20 @@
    MKEmitter.emit('resetSelectLine', MenuID, _id, _data)
  }
  resetTable = (id, repage) => {
  resetTable = (id, repage, pageIndex) => {
    const { MenuID } = this.props
    if (id !== MenuID) return
    if (repage === 'false') {
      this.setState({
        selectedRowKeys: [],
        activeIndex: null,
        pickup: false
      })
    } else if (repage === 'repage') {
      this.setState({
        pageIndex: pageIndex,
        selectedRowKeys: [],
        activeIndex: null,
        pickup: false
@@ -947,7 +975,7 @@
        pageSizeOptions: pageOptions,
        showSizeChanger: true,
        total: this.props.total || 0,
        showTotal: (total, range) => `${range[0]}-${range[1]} ${this.state.dict['main.pagination.of']} ${total} ${this.state.dict['main.pagination.items']}`
        showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
      }
    }
@@ -958,9 +986,13 @@
    }
    let height = setting.height || false
    let loading = this.props.loading
    if (setting.mask === 'hidden') {
      loading = false
    }
    return (
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''}`} id={tableId}>
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''}`} id={tableId}>
        {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
          <Switch title="收起" className="main-pickup" checkedChildren="开" unCheckedChildren="关" checked={pickup} onChange={this.pickupChange} /> : null
        }
@@ -971,7 +1003,7 @@
          rowSelection={rowSelection}
          columns={this.state.columns}
          dataSource={_data}
          loading={this.props.loading}
          loading={loading}
          scroll={{ x: '100%', y: height }}
          onRow={(record, index) => {
            return {
src/tabviews/custom/components/share/normalTable/index.scss
@@ -94,7 +94,7 @@
        // vertical-align: top;
        .card-cell-list {
          color: rgba(0, 0, 0, 0.85);
          color: inherit;
        }
        .ant-mk-picture {
          position: relative;
@@ -204,12 +204,10 @@
  }
  table tr {
    th .ant-table-column-title {
      // color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
    td {
      color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
@@ -218,6 +216,14 @@
      }
    }
  }
  table tbody tr {
    color: var(--mk-table-color);
  }
  // table tbody {
  //   tr:nth-child(even) {
  //     background: #f5f5f5;
  //   }
  // }
}
.normal-custom-table:not(.fixed-height) {
  .ant-table-body::-webkit-scrollbar {
src/tabviews/custom/components/share/tabtransfer/index.jsx
@@ -124,14 +124,15 @@
   * @description 主表数据加载
   */ 
  loadmaindata = (params) => {
    const { config } = this.props
    let BID = ''
    let BData = window.GLOB.CacheData.get(this.props.config.$pageId)
    let BData = window.GLOB.CacheData.get(config.$pageId)
    if (BData) {
      BID = BData.$BID || ''
    }
    let param = getStructuredParams(params, this.props.config, BID)
    let param = getStructuredParams(params, config, BID)
    Api.genericInterface(param).then(result => {
      if (result.status) {
@@ -140,6 +141,16 @@
        delete result.ErrMesg
        delete result.ErrCode
        if (config.$cache) {
          params.forEach((item) => {
            let _data = result[item.name] || ''
            if (_data && !Array.isArray(_data)) {
              _data = [_data]
            }
            Api.writeCacheConfig(item.uuid, _data)
          })
        }
        this.setState({
          data: result
        })
src/tabviews/custom/components/table/base-table/index.jsx
@@ -70,7 +70,7 @@
    let setting = {..._config.setting, ..._config.wrap}
    if (setting.selected !== 'always' && setting.selected !== 'init') {
    if (setting.selected !== 'always' && setting.selected !== 'init' && setting.selected !== 'sign') {
      setting.selected = 'false'
    } else {
      setting.orisel = true
@@ -126,7 +126,7 @@
      })
      
      MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 广播数据切换
      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 列表重置
      reset && MKEmitter.emit('resetTable', config.uuid, 'true') // 列表重置
      if (setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
@@ -157,9 +157,26 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      if (repage === 'false' && result.data && result.data.length === 0 && result.total > 0 && pageIndex > 1) {
        let _pageIndex = Math.ceil(result.total / pageSize)
        if (_pageIndex < pageIndex) {
          MKEmitter.emit('resetTable', config.uuid, 'repage', _pageIndex)
          this.setState({
            pageIndex: _pageIndex,
            data: [],
            selectedData: [],
            total: result.total
          }, () => {
            this.loadmaindata()
          })
          return
        }
      }
      if ((setting.selected !== 'false' || (setting.orisel && id)) && result.data && result.data.length > 0) {
        setTimeout(() => {
          MKEmitter.emit('mkCheckTopLine', config.uuid, id)
          MKEmitter.emit('mkCheckTopLine', config.uuid, id, setting.selected)
        }, 200)
        if (setting.selected === 'init') {
          this.setState({setting: {...setting, selected: 'false'}})
src/tabviews/custom/components/table/base-table/index.scss
@@ -7,6 +7,7 @@
  }
  .top-search {
    border-bottom: 1px solid #efefef;
    padding-top: 10px;
  }
  >.button-list.toolbar-button {
    min-height: 60px;
src/tabviews/custom/components/table/edit-table/index.jsx
@@ -186,7 +186,7 @@
        selectedData: [],
        total: 0
      })
      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 列表重置
      reset && MKEmitter.emit('resetTable', config.uuid, 'true') // 列表重置
      return
    }
src/tabviews/custom/components/table/edit-table/index.scss
@@ -7,6 +7,7 @@
  }
  .top-search {
    border-bottom: 1px solid #efefef;
    padding-top: 10px;
  }
  >.button-list.toolbar-button {
    padding: 0;
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -14,7 +14,6 @@
import enUS from '@/locales/en-US/main.js'
import CusSwitch from './cusSwitch'
import Encrypts from '@/components/encrypts'
import '@/assets/css/table.scss'
import './index.scss'
const { Paragraph } = Typography
@@ -507,7 +506,10 @@
        <CardCellComponent data={record} cards={config} elements={col.elements}/>
      )
    } else if (col.type === 'action') {
      style.padding = '0px 5px'
      style.padding = '0px'
      if (col.style) {
        style = {...style, ...col.style}
      }
      children = (
        <CardCellComponent data={record} cards={config} elements={col.elements}/>
      )
@@ -1201,13 +1203,21 @@
      if (item.resourceType === '1' && result[item.uuid] && result[item.uuid].length > 0) {
        let options = []
        let _map = new Map()
        let all = false
        result[item.uuid].forEach(cell => {
          let _cell = {key: Utils.getuuid()}
          _cell.value = cell[item.valueField]
          _cell.label = cell[item.valueText]
          if (!_cell.label && _cell.label !== 0) return
          if (!_cell.label && _cell.label !== 0) {
            if (!all) {
              _cell.label = '全部'
              all = true
            } else {
              return
            }
          }
          if (_map.has(_cell.value)) return
          _map.set(_cell.value, 0)
@@ -1988,7 +1998,7 @@
          {!submit.hasAction && pickup ? <Button style={submit.style} onClick={() => setTimeout(() => {this.checkData()}, 10)} loading={loading} className="submit-table" type="link">提交</Button> : null}
          <Switch title="编辑" className="main-pickup" checkedChildren="开" unCheckedChildren="关" disabled={loading || this.props.loading} checked={pickup} onChange={this.pickupChange} />
        </div>
        <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${setting.operType || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''}`} id={tableId}>
        <div className={`edit-custom-table ${pickup ? 'editable' : ''} ${setting.tableHeader || ''} ${setting.operType || ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''}`} id={tableId}>
          <Table
            rowKey="$$uuid"
            components={components}
src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -72,7 +72,7 @@
        // vertical-align: top;
        .card-cell-list {
          color: rgba(0, 0, 0, 0.85);
          color: inherit;
        }
        .action-col {
          .ant-btn > .anticon + span {
@@ -292,12 +292,10 @@
  }
  table tr {
    th .ant-table-column-title, th .ant-table-column-title span:not(.anticon) {
      // color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
    }
    td {
      color: var(--mk-table-color)!important;
      font-size: var(--mk-table-font-size)!important;
      font-weight: var(--mk-table-font-weight)!important;
@@ -306,6 +304,9 @@
      }
    }
  }
  table tbody tr {
    color: var(--mk-table-color);
  }
}
.edit-custom-table.buoyMode {
  .ant-table-scroll {
src/tabviews/custom/components/table/normal-table/index.jsx
@@ -45,6 +45,8 @@
    statFValue: []        // 合计值
  }
  loaded = false
  /**
   * @description 初始化处理
   * 1、 initdata 为打印时使用的数据集
@@ -78,21 +80,22 @@
    let setting = {..._config.setting, ..._config.wrap}
    if (setting.selected !== 'always' && setting.selected !== 'init') {
    if (setting.selected !== 'always' && setting.selected !== 'init' && setting.selected !== 'sign') {
      setting.selected = 'false'
    } else {
      setting.orisel = true
    }
    if (_config.setting.sync === 'true' && data) {
    if (_sync && data) {
      _data = data[_config.dataName] || []
      _sync = false
    } else if (_config.setting.sync === 'true' && initdata) {
    } else if (_sync && initdata) {
      _data = initdata || []
      _sync = false
    }
    if (_data) {
      this.loaded = true
      _data = _data.map((item, index) => {
        item.key = index
        item.$$uuid = item[_config.setting.primaryKey] || ''
@@ -120,7 +123,7 @@
      if (setting.selected !== 'false' && _data && _data.length > 0) {
        setTimeout(() => {
          MKEmitter.emit('mkCheckTopLine', _config.uuid)
          MKEmitter.emit('mkCheckTopLine', _config.uuid, '', setting.selected)
        }, 200)
        if (setting.selected === 'init') {
          setting.selected = 'false'
@@ -201,10 +204,12 @@
      })
      
      MKEmitter.emit('resetSelectLine', config.uuid, '', '') // 广播数据切换
      reset && MKEmitter.emit('resetTable', config.uuid, repage) // 列表重置
      reset && MKEmitter.emit('resetTable', config.uuid, 'true') // 列表重置
      if (setting.$hasSyncModule) {
        MKEmitter.emit('syncBalconyData', config.uuid, [], false)
      }
      this.loaded = true
      return
    }
@@ -234,9 +239,31 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.loaded = true
      if (config.$cache && pageIndex === 1) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      if (repage === 'false' && result.data && result.data.length === 0 && result.total > 0 && pageIndex > 1) {
        let _pageIndex = Math.ceil(result.total / pageSize)
        if (_pageIndex < pageIndex) {
          MKEmitter.emit('resetTable', config.uuid, 'repage', _pageIndex)
          this.setState({
            pageIndex: _pageIndex,
            data: [],
            selectedData: [],
            total: result.total
          }, () => {
            this.loadmaindata()
          })
          return
        }
      }
      if ((setting.selected !== 'false' || (setting.orisel && id)) && result.data && result.data.length > 0) {
        setTimeout(() => {
          MKEmitter.emit('mkCheckTopLine', config.uuid, id)
          MKEmitter.emit('mkCheckTopLine', config.uuid, id, setting.selected)
        }, 200)
        if (setting.selected === 'init') {
          this.setState({setting: {...setting, selected: 'false'}})
@@ -636,13 +663,15 @@
        if (setting.selected !== 'false' && _data && _data.length > 0) {
          setTimeout(() => {
            MKEmitter.emit('mkCheckTopLine', config.uuid)
            MKEmitter.emit('mkCheckTopLine', config.uuid, '', setting.selected)
          }, 200)
          if (setting.selected === 'init') {
            this.setState({setting: {...setting, selected: 'false'}})
          }
        }
      }
      this.loaded = true
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -657,7 +686,7 @@
  }
  componentDidMount () {
    const { config } = this.state
    const { config, setting } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
@@ -675,6 +704,35 @@
        })
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        this.setState({data: res.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.setting.primaryKey] || ''
          item.$$key = '' + item.key + item.$$uuid
          item.$Index = index + 1 + ''
          if (config.absFields) {
            config.absFields.forEach(f => {
              if (!isNaN(item[f])) {
                item[f] = Math.abs(item[f])
              }
            })
          }
          if (setting.controlField) {
            if (setting.controlVal.includes(item[setting.controlField])) {
              item.$disabled = true
            }
          }
          return item
        })})
      })
    }
  }
  /**
src/tabviews/custom/components/table/normal-table/index.scss
@@ -7,10 +7,12 @@
  }
  .top-search {
    border-bottom: 1px solid #efefef;
    padding-top: 10px;
  }
  >.button-list.toolbar-button {
    min-height: 60px;
    padding-right: 60px;
    line-height: 40px;
    button {
      margin-right: 0px;
      margin-bottom: 0px;
src/tabviews/custom/components/timeline/normal-timeline/index.jsx
@@ -32,6 +32,8 @@
    description: false
  }
  loaded = false
  /**
   * @description 初始化处理
   * 1、 initdata 为打印时使用的数据集
@@ -66,6 +68,7 @@
    }
    if (_data) {
      this.loaded = true
      _data = _data.map((item, index) => {
        item.key = index
        item.$$uuid = item[_config.setting.primaryKey] || ''
@@ -123,6 +126,20 @@
        this.loadData(true)
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        this.setState({data: res.map((item, index) => {
          item.key = index
          item.$$uuid = item[config.setting.primaryKey] || ''
          item.$Index = index + 1 + ''
          return item
        })})
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -161,6 +178,8 @@
        item.$Index = index + 1 + ''
        return item
      })
      this.loaded = true
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -246,6 +265,7 @@
      this.setState({
        data: [],
      })
      this.loaded = true
      return
    }
@@ -280,6 +300,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data.map((item, index) => {
          item.key = index
src/tabviews/custom/components/timeline/normal-timeline/index.scss
@@ -80,9 +80,9 @@
  .loading-mask {
    position: absolute;
    left: 40px;
    left: 0px;
    top: 0;
    right: 40px;
    right: 0px;
    bottom: 0px;
    display: flex;
    align-items: center;
src/tabviews/custom/components/tree/antd-tree/index.jsx
@@ -34,6 +34,8 @@
    selected: false            // 选中首行
  }
  loaded = false
  UNSAFE_componentWillMount () {
    const { config, data, initdata } = this.props
    let _config = fromJS(config).toJS()
@@ -52,15 +54,17 @@
      BID = BData.$BID || ''
    }
    if (config.setting.sync === 'true' && data) {
    if (_sync && data) {
      _data = data[config.dataName] || []
      _sync = false
    } else if (config.setting.sync === 'true' && initdata) {
    } else if (_sync && initdata) {
      _data = initdata || []
      _sync = false
    }
    _config.wrap.contentHeight = config.wrap.title || config.wrap.searchable === 'true' ? 'calc(100% - 45px)' : '100%'
    this.loaded = _data !== null
    this.setState({
      selected: _config.wrap.selected === 'true',
@@ -92,6 +96,8 @@
        _data = nextProps.data[config.dataName] || []
      }
      this.loaded = true
      this.setState({sync: false, data: _data}, () => {
        this.handleData()
      })
@@ -116,6 +122,16 @@
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.timer, config.timerRepeats, () => {
        this.loadData(true)
      })
    }
    if (config.$cache && !this.loaded) {
      Api.getLCacheConfig(config.uuid).then(res => {
        if (!res || this.loaded) return
        this.setState({data: res}, () => {
          this.handleData()
        })
      })
    }
  }
@@ -165,6 +181,7 @@
      }, () => {
        this.handleData()
      })
      this.loaded = true
      return
    }
@@ -186,6 +203,11 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.loaded = true
      if (config.$cache) {
        Api.writeCacheConfig(config.uuid, result.data || '')
      }
      this.setState({
        data: result.data,
        loading: false
src/tabviews/custom/index.jsx
@@ -40,6 +40,7 @@
const TimeLine = asyncComponent(() => import('./components/timeline/normal-timeline'))
const AntvG6 = asyncComponent(() => import('./components/chart/antv-G6'))
const Voucher = asyncComponent(() => import('./components/module/voucher'))
const Account = asyncComponent(() => import('./components/module/account'))
const Iframe = asyncComponent(() => import('./components/iframe'))
const DebugTable = asyncComponent(() => import('@/tabviews/debugtable'))
const TableNodes = asyncComponent(() => import('@/tabviews/zshare/tablenodes'))
@@ -196,9 +197,10 @@
        popview = 'popview'
      }
      config.interfaces = this.formatInterSetting(config.interfaces, regs)
      config.$cache = config.cacheLocal === 'true'
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, skip, param, MenuID, config.interfaces, popview)
      config.interfaces = this.formatInterSetting(config.interfaces, regs)
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, skip, param, MenuID, config.interfaces, popview, config.$cache)
      
      // 获取主搜索条件
      let mainSearch = []
@@ -306,9 +308,10 @@
    }
  }
  filterComponent = (components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview) => {
  filterComponent = (components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview, cache) => {
    return components.filter(item => {
      item.$pageId = pageId
      item.$cache = cache
      
      if (item.style && item.style.boxShadow) {
        delete item.style.hShadow
@@ -392,7 +395,7 @@
        item.subtabs = item.subtabs.map(tab => {
          tab.$pageId = pageId
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview)
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview, cache)
          return tab
        })
@@ -405,7 +408,7 @@
          return false
        }
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview)
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview, cache)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart'].includes(item.type)) {
@@ -838,6 +841,10 @@
      component.setting.useMSearch = component.setting.useMSearch === 'true'
      if (component.wrap && component.wrap.goback === 'true') {
        component.setting.sync = 'false'
      }
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.laypage = component.setting.laypage === 'true'
@@ -983,7 +990,8 @@
   * @description 主表数据加载
   */ 
  loadmaindata = (params) => {
    let param = getStructuredParams(params, this.state.config, this.state.BID || '')
    const { config } = this.state
    let param = getStructuredParams(params, config, this.state.BID || '')
    this.setState({loading: true, loadingview: false})
@@ -993,6 +1001,16 @@
        delete result.message
        delete result.ErrMesg
        delete result.ErrCode
        if (config.$cache) {
          params.forEach((item) => {
            let _data = result[item.name] || ''
            if (_data && !Array.isArray(_data)) {
              _data = [_data]
            }
            Api.writeCacheConfig(item.uuid, _data)
          })
        }
        this.setState({
          data: result,
@@ -1272,6 +1290,12 @@
            <Voucher config={item}/>
          </Col>
        )
      } else if (item.type === 'module' && item.subtype === 'account') {
        return (
          <Col span={item.width} style={style} key={item.uuid}>
            <Account config={item}/>
          </Col>
        )
      } else if (item.type === 'iframe') {
        return (
          <Col span={item.width} style={style} key={item.uuid}>
@@ -1289,7 +1313,7 @@
    return (
      <div className={'custom-page-wrap ' + (loadingview || loading ? 'loading' : '')} id={this.state.ContainerId} style={config ? config.style : null}>
        {(loadingview || loading) ? <Spin className="view-spin" size="large" /> : null}
        {(loadingview || (loading && !config.$cache)) ? <Spin className="view-spin" size="large" /> : null}
        <Row className="component-wrap">{this.getComponents()}</Row>
        {config && config.interfaces.length > 0 ? <MkInterfaces BID={BID} interfaces={config.interfaces}/> : null}
        {config && window.GLOB.breakpoint ? <DebugTable /> : null}
src/tabviews/custom/popview/index.jsx
@@ -129,7 +129,9 @@
      })
    }
    config.components = this.filterComponent(config.components, roleId, balMap, param, Tab)
    config.$cache = config.cacheLocal === 'true'
    config.components = this.filterComponent(config.components, roleId, balMap, param, Tab, config.$cache)
    
    // 获取主搜索条件
    let mainSearch = []
@@ -175,9 +177,10 @@
    })
  }
  filterComponent = (components, roleId, balMap, urlparam, Tab) => {
  filterComponent = (components, roleId, balMap, urlparam, Tab, cache) => {
    return components.filter(item => {
      item.$pageId = Tab.uuid
      item.$cache = cache
      
      if (item.style && item.style.boxShadow) {
        delete item.style.hShadow
@@ -261,7 +264,7 @@
        item.subtabs = item.subtabs.map(tab => {
          tab.$pageId = Tab.uuid
          tab.components = this.filterComponent(tab.components, roleId, balMap, urlparam, Tab)
          tab.components = this.filterComponent(tab.components, roleId, balMap, urlparam, Tab, cache)
          return tab
        })
@@ -274,7 +277,7 @@
          return false
        }
        item.components = this.filterComponent(item.components, roleId, balMap, urlparam, Tab)
        item.components = this.filterComponent(item.components, roleId, balMap, urlparam, Tab, cache)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart'].includes(item.type)) {
@@ -754,7 +757,8 @@
   * @description 主表数据加载
   */ 
  loadmaindata = (params) => {
    let param = getStructuredParams(params, this.state.config, this.state.BID || '')
    const { config } = this.state
    let param = getStructuredParams(params, config, this.state.BID || '')
    this.setState({loading: true})
@@ -764,6 +768,16 @@
        delete result.message
        delete result.ErrMesg
        delete result.ErrCode
        if (config.$cache) {
          params.forEach((item) => {
            let _data = result[item.name] || ''
            if (_data && !Array.isArray(_data)) {
              _data = [_data]
            }
            Api.writeCacheConfig(item.uuid, _data)
          })
        }
        this.setState({
          data: result,
@@ -1011,7 +1025,7 @@
    return (
      <div className={'pop-page-wrap ' + (loading ? 'loading' : '')} style={config ? config.style : null}>
        {loading ? <Spin className="view-spin" size="large" /> : null}
        {loading && !config.$cache ? <Spin className="view-spin" size="large" /> : null}
        <Row className="component-wrap">{this.getComponents()}</Row>
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -164,7 +164,10 @@
    let _this = this
    let param = {
      func: 'webapi_ChangeUser'
      func: 'webapi_ChangeUser',
      login_city: sessionStorage.getItem('city') || '',
      login_id_address: sessionStorage.getItem('ipAddress') || '',
      domain_name: window.btoa(window.encodeURIComponent(window.GLOB.host)),
    }
    if (this.props.BID) {
src/tabviews/zshare/actionList/excelInbutton/excelin/index.jsx
@@ -1,7 +1,7 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { notification } from 'antd'
import * as XLSX from 'xlsx'
import * as XLSX from 'sheetjs-style'
import Utils from '@/utils/utils.js'
import './index.scss'
src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -303,7 +303,7 @@
      })
    }
    let result = getExcelInSql(btn, data, this.state.dict, (this.props.BID || ''))
    let result = getExcelInSql(btn, data, this.state.dict, (this.props.BID || ''), this.state.primaryId)
    if (result.errors) {
      notification.warning({
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -3,7 +3,7 @@
import moment from 'moment'
import { is, fromJS } from 'immutable'
import { Button, Modal, notification, message } from 'antd'
import * as XLSX from 'xlsx'
import * as XLSX from 'sheetjs-style'
import Utils from '@/utils/utils.js'
import options from '@/store/options.js'
@@ -195,7 +195,7 @@
        })
        viewParam.arr_field = viewParam.arr_field.join(',')
        viewParam.orderBy = btn.verify.order || viewParam.orderBy
        viewParam.orderBy = btn.verify.order || ''
      }
    }
    if (btn.intertype === 'system' && btn.verify.enable === 'true') {
@@ -602,11 +602,15 @@
        let _header = []
        let _topRow = {}
        let colwidth = []
        columns.forEach(col => {
        let requires = []
        columns.forEach((col, i) => {
          _header.push(col.Column)
          _topRow[col.Column] = col.Text
          colwidth.push({width: col.Width || 20})
          if (col.required === 'true') {
            requires.push(i)
          }
        })
  
        let table = []
@@ -638,8 +642,18 @@
        })
  
        const ws = XLSX.utils.json_to_sheet(table, {header: _header, skipHeader: true})
        ws['!cols'] = colwidth
        if (requires.length) {
          let cols = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
          requires.forEach(col => {
            if (cols[col]) {
              ws[cols[col] + '1'].s = {font: { color: { rgb: 'F5222D' } }}
            }
          })
        }
        // ws["A1"].s = {fill: { bgColor: { rgb: "FFFFAA"  }}, font: { color: { rgb: "1890FF" } }}
  
        const wb = XLSX.utils.book_new()
        XLSX.utils.book_append_sheet(wb, ws, 'Sheet1')
src/tabviews/zshare/actionList/index.jsx
@@ -1,7 +1,8 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Affix } from 'antd'
import { Affix, Dropdown } from 'antd'
import { DownOutlined } from '@ant-design/icons'
import asyncComponent from './asyncButtonComponent'
import './index.scss'
@@ -29,7 +30,25 @@
    setting: PropTypes.any,           // 页面通用设置
  }
  state = {}
  state = {
    actions: [],
    mores: null
  }
  UNSAFE_componentWillMount() {
    const { setting, actions } = this.props
    if (!setting.btnlimit || setting.btnlimit >= actions.length) {
      this.setState({actions: actions})
    } else {
      let mores = fromJS(actions).toJS()
      this.setState({
        actions: mores.splice(0, setting.btnlimit),
        mores
      })
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
@@ -139,6 +158,7 @@
              btn={item}
              BData={BData}
              setting={setting}
              columns={columns}
              selectedData={selectedData}
            />
          )
@@ -173,7 +193,8 @@
  }
  render() {
    const { setting, MenuID, actions } = this.props
    const { setting, MenuID } = this.props
    const { actions, mores } = this.state
    let fixed = setting.actionfixed && setting.tabType === 'main' // 按钮是否固定在头部
    if (fixed && MenuID) {
@@ -181,6 +202,9 @@
        <Affix offsetTop={48}>
          <div className="button-list toolbar-button" id={fixed ? MenuID + 'mainaction' : ''}>
            {this.getButtonList(actions)}
            {mores ? <Dropdown overlay={<div className="mk-button-dropdown-wrap">{this.getButtonList(mores)}</div>} trigger={['hover']}>
              <div className="mk-button-more">更多<DownOutlined/></div>
            </Dropdown> : null}
          </div>
        </Affix>
      )
@@ -188,6 +212,9 @@
      return (
        <div className="button-list toolbar-button" id={fixed ? MenuID + 'mainaction' : ''}>
          {this.getButtonList(actions)}
          {mores ? <Dropdown overlay={<div className="mk-button-dropdown-wrap">{this.getButtonList(mores)}</div>} trigger={['hover']}>
            <div className="mk-button-more">更多<DownOutlined/></div>
          </Dropdown> : null}
        </div>
      )
    }
src/tabviews/zshare/actionList/index.scss
@@ -26,3 +26,34 @@
    display: none;
  }
}
.mk-button-more {
  display: inline-block;
  height: 28px;
  border: 1px solid #d8d8d8;
  line-height: 28px;
  padding: 0 10px 0px 20px;
  border-radius: 4px;
  cursor: pointer;
  .anticon-down {
    margin-left: 3px;
  }
}
.mk-button-dropdown-wrap {
  box-shadow: 0 0 2px #bcbcbc;
  background: #ffffff;
  min-width: 85px;
  button {
    display: block;
    margin: 0!important;
    width: 100%;
    height: 34px;
    border-radius: 0px;
    padding-left: 15px!important;
    .anticon {
      display: none;
    }
    .anticon + span {
      margin-left: 0px;
    }
  }
}
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -867,7 +867,7 @@
    }
  
    // 添加数据中字段,表单值优先(按钮不选行或多行拼接时跳过)
    if (data && btn.Ot !== 'notRequired' && btn.Ot !== 'requiredOnce' && columns && columns.length > 0) {
    if (data && btn.Ot !== 'notRequired' && columns && columns.length > 0) {
      datavars = {...data, ...datavars}
  
      const setField = (col) => {
@@ -2680,7 +2680,7 @@
      if (btn.formType === 'switch') { 
        return <Switch loading={loading} checked={check} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} onChange={(val,e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style} className={btn.size === 'large' ? 'ant-switch-large' : ''} size={btn.size} checkedChildren={btn.openText || ''} unCheckedChildren={btn.closeText || ''}/>
      } else if (btn.formType === 'radio') {
        return <Checkbox disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} checked={check} onChange={(e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style}></Checkbox>
        return <Checkbox className={btn.checkType || ''} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} checked={check} onChange={(e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style}></Checkbox>
      } else {
        return <Button type="link" icon="scan" disabled={true} style={btn.style} onClick={(e) => {e.stopPropagation()}}></Button>
      }
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -27,6 +27,7 @@
    MenuID: PropTypes.string,         // 菜单ID
    btn: PropTypes.object,            // 按钮
    setting: PropTypes.any,           // 页面通用设置
    columns: PropTypes.array,
    disabled: PropTypes.any,          // 行按钮禁用
  }
@@ -190,6 +191,13 @@
        duration: 5
      })
      return
    } else if (btn.intertype === 'system' && btn.verify.dataType === 'custom' && (!btn.verify.setting || btn.verify.columns.length === 0)) {
      notification.warning({
        top: 92,
        message: '自定义打印数据请设置数据源!',
        duration: 5
      })
      return
    }
    this.setState({
@@ -244,70 +252,52 @@
  triggerNormalPrint = (data, formlist) => {
    const { btn } = this.props
    let formdata = {}
    let baseCount = 1
    let baseType = ''
    let baseTemp = btn.verify.Template || ''
    
    formlist.forEach(_data => {
      formdata[_data.key] = _data.value
      if (!_data.value) return
      if (_data.key.toLowerCase() === 'printcount') {
        baseCount = +_data.value
      } else if (_data.key.toLowerCase() === 'printtype') {
        baseType = _data.value
      } else if (_data.key.toLowerCase() === 'templateid') {
        baseTemp = _data.value
      }
      let _key = _data.key.toLowerCase()
      formdata[_key] = _data.value
    })
    let printlist = []
    let templates = []
    if (isNaN(baseCount) || baseCount < 1) {
      baseCount = 1
    }
    new Promise(resolve => {
      if (btn.intertype === 'system') { // 使用系统时,直接从表格或表单中选取数据
      if (btn.intertype === 'system' && btn.verify.dataType !== 'custom') { // 使用系统时,直接从表格或表单中选取数据
        if (btn.Ot === 'notRequired') {
          let printcell = {}
  
          printcell.printType = baseType
          printcell.printCount = baseCount
          printcell.templateID = baseTemp
          printcell.printType = formdata.printtype || ''
          printcell.printCount = +(formdata.printcount || 1)
          printcell.templateID = formdata.templateid || btn.verify.Template || ''
          printcell.data = [formdata]
          if (isNaN(printcell.printCount) || printcell.printCount < 1) {
            printcell.printCount = 1
          }
          templates.push(printcell.templateID)
          printlist.push(printcell)
        } else {
          data.forEach(cell => {
            let _cell = {...cell, ...formdata}
            let _cell = {}
            Object.keys(cell).forEach(key => {
              let _key = key.toLowerCase()
              _cell[_key] = cell[key]
            })
            _cell = {..._cell, ...formdata}
            
            let printcell = {data: [_cell]}
  
            printcell.templateID = baseTemp
            printcell.printType = baseType
            printcell.printCount = 0
            Object.keys(_cell).forEach(key => {
              if (!_cell[key]) return
              let _key = key.toLowerCase()
              if (_key === 'templateid') {
                printcell.templateID = _cell[key]
              } else if (_key === 'printtype') {
                printcell.printType = _cell[key]
              } else if (_key === 'printcount') {
                printcell.printCount = +_cell[key]
              }
            })
            printcell.printType = _cell.printtype || ''
            printcell.printCount = +(_cell.printcount || 1)
            printcell.templateID = _cell.templateid || btn.verify.Template || ''
            if (isNaN(printcell.printCount) || printcell.printCount < 1) {
              printcell.printCount = baseCount
              printcell.printCount = 1
            }
            templates.push(printcell.templateID)
@@ -316,58 +306,71 @@
          })
        }
        resolve(true)
        if (btn.verify.printMode === 'custom') {
          this.execCustomPrint(printlist, formdata)
          resolve(false)
        } else {
          resolve(true)
        }
      } else {
        this.getprintdata(btn, data, formdata, formlist).then(result => {
          if (result.next) {
            result.list.forEach(cell => {
              // 系统打印数据,校验data字段
              if (btn.verify.printMode !== 'custom' && (!cell.data || cell.data.length === 0)) return
          if (!result.next) {
            resolve(false)
            return
          }
              let templateID = baseTemp
              let printType = baseType
              let printCount = 0
          // 自定义打印
          if (btn.verify.printMode === 'custom') {
            this.execCustomPrint(result.list, formdata)
            resolve(false)
            return
          }
              Object.keys(cell).forEach(key => {
                if (!cell[key]) return
          result.list.forEach(cell => {
            // 系统打印数据,校验data字段
            if (!cell.data || cell.data.length === 0) return
            Object.keys(cell).forEach(key => {
              let _key = key.toLowerCase()
              if (['templateid', 'printtype', 'printcount'].includes(_key)) {
                cell[_key] = cell[key]
              }
            })
            cell.data.forEach(item => {
              let _item = {...formdata}
              _item.printtype = cell.printtype || ''
              _item.printcount = cell.printcount || 1
              _item.templateid = cell.templateid || ''
              Object.keys(item).forEach(key => {
                let _key = key.toLowerCase()
                if (_key === 'templateid') {
                  templateID = cell[key]
                } else if (_key === 'printtype') {
                  printType = cell[key]
                } else if (_key === 'printcount') {
                  printCount = +cell[key]
                }
                _item[_key] = item[key]
              })
              cell.templateID = templateID
              cell.printType = printType
              cell.printCount = printCount
              let printcell = {data: [_item]}
              printcell.printType = _item.printtype || ''
              printcell.printCount = +(_item.printcount || 1)
              printcell.templateID = _item.templateid || btn.verify.Template || ''
              if (isNaN(cell.printCount) || cell.printCount < 1) {
                cell.printCount = baseCount
              if (isNaN(printcell.printCount) || printcell.printCount < 1) {
                printcell.printCount = 1
              }
              templates.push(cell.templateID)
              templates.push(printcell.templateID)
              printlist.push(cell)
              printlist.push(printcell)
            })
          }
          })
          
          resolve(result.next)
          resolve(true)
        })
      }
    }).then(res => {
      // 获取打印模板 getTemp
      if (!res) return false
      if (btn.verify.printMode === 'custom') {
        this.execCustomPrint(printlist, formdata)
        return false
      }
      templates = Array.from(new Set(templates)) // 去重
@@ -447,10 +450,10 @@
              })
            }
            this.execPrint(printlist, _temps, formdata)
            this.execPrint(printlist, _temps)
          }, 500)
        } else {
          this.execPrint(printlist, _temps, formdata)
          this.execPrint(printlist, _temps)
        }
      } else {
        this.execError(errorMsg)
@@ -471,7 +474,7 @@
    })
    new Promise(resolve => {
      if (btn.intertype === 'system') { // 使用系统时,直接从表格或表单中选取数据
      if (btn.intertype === 'system' && btn.verify.dataType !== 'custom') { // 使用系统时,直接从表格或表单中选取数据
        if (btn.Ot === 'notRequired') {
          if (formlist.length > 0) {
            list = [formdata]
@@ -792,72 +795,124 @@
   * @description 获取打印数据
   */
  getprintdata = (btn, data, formdata, formlist) => {
    const { setting } = this.props
    const { setting, BID } = this.props
    let _list = []
    return new Promise(resolve => {
      let params = []
      let param = {}
      if (this.props.BID) {
        param.BID = this.props.BID
      }
      if (btn.Ot === 'notRequired') {
        let _param = { ...param, ...formdata }
        params.push(_param)
      } else if (btn.Ot === 'requiredSgl') {
        if (setting.primaryKey) {
          param[setting.primaryKey] = data[0][setting.primaryKey]
        }
        let _param = { ...param, ...formdata }
        params.push(_param)
      } else if (btn.Ot === 'requiredOnce') {
        if (setting.primaryKey) {
          let ids = data.map(d => { return d[setting.primaryKey]})
          ids = ids.filter(Boolean)
          ids = ids.join(',')
      if (btn.intertype === 'system' && btn.verify.dataType === 'custom') {
        if (btn.Ot === 'notRequired') {
          let _param = this.getDefaultSql(formlist, null, '')
  
          param[setting.primaryKey] = ids
        }
        let _param = { ...param, ...formdata }
        params.push(_param)
      } else if (btn.Ot === 'required') {
        params = data.map((cell, index) => {
          let _param = { ...param }
          params.push(_param)
        } else if (btn.Ot === 'requiredSgl') {
          let ID = ''
          if (setting.primaryKey) {
            _param[setting.primaryKey] = cell[setting.primaryKey]
            ID = data[0][setting.primaryKey] || ''
          }
          let _cell = {}
          if (index !== 0) {
            Object.keys(cell).forEach(key => {
              _cell[key.toLowerCase()] = cell[key]
            })
          let _param = this.getDefaultSql(formlist, data[0], ID)
          params.push(_param)
        } else if (btn.Ot === 'requiredOnce') {
          let ID = ''
          if (setting.primaryKey) {
            let ids = data.map(d => { return d[setting.primaryKey]})
            ids = ids.filter(Boolean)
            ID = ids.join(',')
          }
          formlist.forEach(_data => {
            if (index !== 0 && _data.readin && _cell.hasOwnProperty(_data.key.toLowerCase())) {
              _param[_data.key] = _cell[_data.key.toLowerCase()]
            } else {
              _param[_data.key] = _data.value
          let _param = this.getDefaultSql(formlist, data[0], ID)
          params.push(_param)
        } else if (btn.Ot === 'required') {
          params = data.map(cell => {
            let ID = ''
            if (setting.primaryKey) {
              ID = cell[setting.primaryKey] || ''
            }
            return this.getDefaultSql(formlist, cell, ID)
          })
          return _param
        })
        }
      } else {
        if (btn.Ot === 'notRequired') {
          let _param = { ...formdata }
          if (BID) {
            _param.BID = BID
          }
          params.push(_param)
        } else if (btn.Ot === 'requiredSgl') {
          let _param = { ...formdata }
          if (setting.primaryKey) {
            _param[setting.primaryKey] = data[0][setting.primaryKey]
          }
          if (BID) {
            _param.BID = BID
          }
          params.push(_param)
        } else if (btn.Ot === 'requiredOnce') {
          let _param = { ...formdata }
          if (setting.primaryKey) {
            let ids = data.map(d => { return d[setting.primaryKey]})
            ids = ids.filter(Boolean)
            ids = ids.join(',')
            _param[setting.primaryKey] = ids
          }
          if (BID) {
            _param.BID = BID
          }
          params.push(_param)
        } else if (btn.Ot === 'required') {
          params = data.map((cell, index) => {
            let _param = {}
            if (setting.primaryKey) {
              _param[setting.primaryKey] = cell[setting.primaryKey]
            }
            if (BID) {
              _param.BID = BID
            }
            let _cell = {}
            if (index !== 0) {
              Object.keys(cell).forEach(key => {
                _cell[key.toLowerCase()] = cell[key]
              })
            }
            formlist.forEach(_data => {
              if (index !== 0 && _data.readin && _cell.hasOwnProperty(_data.key.toLowerCase())) {
                _param[_data.key] = _cell[_data.key.toLowerCase()]
              } else {
                _param[_data.key] = _data.value
              }
            })
            return _param
          })
        }
      }
      if (btn.intertype === 'inner') {
        params = params.map(_param => {
          _param.func = btn.innerFunc
          return _param
        })
      if (btn.intertype === 'inner' || btn.intertype === 'system') {
        if (btn.intertype === 'inner') {
          params = params.map(_param => {
            _param.func = btn.innerFunc
            return _param
          })
        }
        if (params.length <= 20) {
          let deffers = params.map(par => {
@@ -888,6 +943,233 @@
        this.printOuterLoopRequest(params, btn, _list, resolve)
      }
    })
  }
  /**
   * @description 获取默认存储过程请求参数
   */
  getDefaultSql = (formlist, data, ID) => {
    const { BID, btn, columns } = this.props
    let arrFields = btn.verify.columns.map(col => col.field).join(',')
    let param = {
      func: 'sPC_Get_TableData',
      obj_name: 'data',
      exec_type: 'y',
      arr_field: arrFields,
      default_sql: btn.verify.setting.defaultSql
    }
    if (BID) {
      param.BID = BID
    }
    if (ID) {
      param.ID = ID
    }
    let userName = sessionStorage.getItem('User_Name') || ''
    let fullName = sessionStorage.getItem('Full_Name') || ''
    let RoleID = sessionStorage.getItem('role_id') || ''
    let departmentcode = sessionStorage.getItem('departmentcode') || ''
    let organization = sessionStorage.getItem('organization') || ''
    let mk_user_type = sessionStorage.getItem('mk_user_type') || ''
    let nation = sessionStorage.getItem('nation') || ''
    let province = sessionStorage.getItem('province') || ''
    let city = sessionStorage.getItem('city') || ''
    let district = sessionStorage.getItem('district') || ''
    let address = sessionStorage.getItem('address') || ''
    let _dataresource = btn.verify.setting.dataresource
    let _customScript = ''
    btn.verify.scripts && btn.verify.scripts.forEach(script => {
      if (script.status !== 'false') {
        _customScript += `
        ${script.sql}
        `
      }
    })
    if (btn.verify.setting.defaultSql === 'false') {
      _dataresource = ''
    }
    if (/\s/.test(_dataresource)) {
      _dataresource = '(' + _dataresource + ') tb'
    }
    if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
      _dataresource = _dataresource.replace(/\$@/ig, '/*').replace(/@datam@/ig, '\'Y\'')
      _dataresource = _dataresource.replace(/@\$/ig, '*/')
      _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@datam@/ig, '\'Y\'')
      _customScript = _customScript.replace(/@\$/ig, '*/')
    } else {
      _dataresource = _dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
      _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
    }
    let initsql = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100)
      Select @ErrorCode='',@retmsg ='',@UserName='${userName}', @FullName='${fullName}', @RoleID='${RoleID}', @mk_departmentcode='${departmentcode}', @mk_organization='${organization}', @mk_user_type='${mk_user_type}', @mk_nation='${nation}', @mk_province='${province}', @mk_city='${city}', @mk_district='${district}', @mk_address='${address}'
    `
    let _vars = []
    let _initvars = []
    let _declare = []
    // 获取字段键值对
    formlist.forEach(form => {
      let _key = form.key.toLowerCase()
      if (_vars.includes(_key)) return
      _vars.push(_key)
      if (form.type === 'number' || form.type === 'rate') {
        let val = form.value
        if (isNaN(val)) {
          val = 0
        }
        _initvars.push(`@${_key}=${val}`)
      } else if (['date', 'datemonth'].includes(form.type)) {
        _initvars.push(`@${_key}='${form.value || '1949-10-01'}'`)
      } else {
        _initvars.push(`@${_key}='${form.value}'`)
      }
      if (form.fieldlen && form.fieldlen > 2048) {
        form.fieldlen = 'max'
      }
      let _type = `nvarchar(${form.fieldlen})`
      if (form.type.match(/date/ig)) {
        _type = 'datetime'
      } else if (form.type === 'number') {
        _type = `decimal(18,${form.fieldlen})`
      } else if (form.type === 'rate') {
        _type = `decimal(18,2)`
      }
      _declare.push(`@${_key} ${_type}`)
    })
    if (_declare.length > 0) {
      initsql += `/* 表单变量 */
        Declare ${_declare.join(',')}
        select ${_initvars.join(',')}
      `
      _declare = []
      _initvars = []
    }
    if (data && columns && columns.length > 0) {
      let datavars = {}
      Object.keys(data).forEach(key => {
        datavars[key.toLowerCase()] = data[key]
      })
      columns.forEach(col => {
        if (!col.field || !col.datatype) return
        let _key = col.field.toLowerCase()
        if (_vars.includes(_key)) return
        let _val = datavars.hasOwnProperty(_key) ? datavars[_key] : ''
        if (/^date/ig.test(col.datatype) && !_val) {
          _val = '1949-10-01'
        }
        _initvars.push(`@${_key}='${_val}'`)
        _declare.push(`@${_key} ${col.datatype}`)
      })
    }
    if (_declare.length > 0) {
      initsql += `/* 显示列变量 */
        Declare ${_declare.join(',')}
        select ${_initvars.join(',')}
      `
    }
    if (_customScript) {
      _customScript = `${initsql}
        ${_customScript}
      `
    }
    _dataresource = _dataresource.replace(/@select\$|\$select@/ig, '')
    _customScript = _customScript.replace(/@select\$|\$select@/ig, '')
    _dataresource = _dataresource.replace(/\$sum@/ig, '/*')
    _dataresource = _dataresource.replace(/@sum\$/ig, '*/')
    _customScript = _customScript.replace(/\$sum@/ig, '/*')
    _customScript = _customScript.replace(/@sum\$/ig, '*/')
    _dataresource = _dataresource.replace(/@ID@/ig, `'${ID}'`)
    _customScript = _customScript.replace(/@ID@/ig, `'${ID}'`)
    _dataresource = _dataresource.replace(/@BID@/ig, `'${BID || ''}'`)
    _customScript = _customScript.replace(/@BID@/ig, `'${BID || ''}'`)
    _dataresource = _dataresource.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
    _customScript = _customScript.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
    _dataresource = _dataresource.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    _customScript = _customScript.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    _dataresource = _dataresource.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    _customScript = _customScript.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    _dataresource = _dataresource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    _customScript = _customScript.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    let LText = ''
    if (_dataresource) {
      LText = `/*system_query*/select ${arrFields} from (select ${arrFields} ,ROW_NUMBER() over(order by ${btn.verify.setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows `
    }
    if (_customScript) {
      if (LText) {
        LText = `${LText}
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      } else {
        _customScript = `${_customScript}
          aaa:
          if @ErrorCode!=''
            insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
        `
      }
    } else {
      LText = `${initsql}
        ${LText}
      `
    }
    // 测试系统打印查询语句
    if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
      _customScript && console.info(`${btn.logLabel ? `/*${btn.logLabel} 自定义脚本*/\n` : ''}${LText ? '' : '/*不执行默认sql*/\n'}${_customScript}`)
      LText && console.info(`${btn.logLabel ? `/*${btn.logLabel} 数据源*/\n` : ''}` + LText.replace(/\n\s{8}/ig, '\n'))
    }
    if (btn.logLabel) {
      param.menuname = btn.logLabel
    }
    param.custom_script = Utils.formatOptions(_customScript)
    param.LText = Utils.formatOptions(LText)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    if (window.GLOB.probation) {
      param.s_debug_type = 'Y'
    }
    return param
  }
  /**
@@ -986,7 +1268,6 @@
        return Api.genericInterface(_callbackparam)
      } else if (response.status) {
        _list.push(response)
        // 一次请求成功,进行下一项请求
@@ -1072,7 +1353,7 @@
        }
        configParam.elements.forEach(element => {
          let _field = element.field
          let _field = element.field || ''
          if (_field === 'other_field') {
            _field = element.cusfield || ''
@@ -1082,7 +1363,7 @@
            Name: element.name || '',
            Type: element.type,
            Value: element.value || '',
            Field: _field,
            Field: _field.toLowerCase(),
            Left: element.left + offsetLeft,
            Top: element.top + offsetTop,
            Width: element.width,
@@ -1119,11 +1400,13 @@
            item.ImageWidth = element.imgWidth
            item.ImageHeight = element.imgHeight
            item.Trimming = ''
            if (element.productValue && window.GLOB.systemType === 'production') {
              item.Value = element.productValue
              imgs.push(item.Value)
            } else if (item.Value) {
              imgs.push(item.Value)
            if (!item.Field) {
              if (element.productValue && window.GLOB.systemType === 'production') {
                item.Value = element.productValue
                imgs.push(item.Value)
              } else if (item.Value) {
                imgs.push(item.Value)
              }
            }
          } else if (item.Type === 'text') {
            item.FontFamily = element.fontFamily
@@ -1190,8 +1473,8 @@
    return {
      error: error,
      config: _configparam,
      fields: fields,
      nonEFields: nonEFields,
      fields: Array.from(new Set(fields)),
      nonEFields: Array.from(new Set(nonEFields)),
      imgs: imgs
    }
  }
@@ -1339,7 +1622,7 @@
    })
  }
  execPrint = (list, template, formdata) => {
  execPrint = (list, template) => {
    const { btn } = this.props
    let _errors = []
@@ -1379,30 +1662,25 @@
        _datalist.forEach(res => {
          res.data.forEach(_cell => {
            for (let i = 0; i < res.printCount; i++) {
              _data.push({...formdata, ..._cell})
              _data.push(_cell)
            }
          })
        })
        let _fields = Array.from(new Set(template[key].fields))
        let _nonEFields = Array.from(new Set(template[key].nonEFields))
        let lacks = []
        let emptys = []
        _data.forEach(d => {
          _fields.forEach(f => {
          template[key].fields.forEach(f => {
            if (!d.hasOwnProperty(f)) {
              lacks.push(f)
            } else if (_nonEFields.includes(f) && !d[f] && d[f] !== 0) {
            } else if (template[key].nonEFields.includes(f) && !d[f] && d[f] !== 0) {
              emptys.push(f)
            }
          })
        })
        if (lacks.length > 0 || emptys.length > 0) {
          lacks = Array.from(new Set(lacks))
          emptys = Array.from(new Set(emptys))
          _errors.push({
            title: template[key].config.Title,
            lacks: lacks,
@@ -1490,49 +1768,29 @@
      return
    }
    // let lackItems = printerList.filter(cell => cell.task.printer === 'lackprinter')[0]
    if (!socket || socket.readyState !== 1 || socket.url !== 'ws://' + btn.verify.linkUrl) {
      socket = new WebSocket('ws://' + btn.verify.linkUrl)
    } else {
      // if (lackItems) {
      //   let request  = {
      //     requestID: '',
      //     version: '',
      //     cmd: 'getPrinters'
      //   }
      //   socket.send(JSON.stringify(request))
      // } else {
        this.syncMessageSend(printerList)
      this.syncMessageSend(printerList)
        this.execSuccess({
          ErrCode: 'S',
          message: '',
          ErrMesg: '打印请求已发出。',
          status: true
        })
      // }
      this.execSuccess({
        ErrCode: 'S',
        message: '',
        ErrMesg: '打印请求已发出。',
        status: true
      })
    }
    // 打开Socket
    socket.onopen = () =>{
      // if (lackItems) {
      //   let request  = {
      //     requestID: '',
      //     version: '',
      //     cmd: 'getPrinters'
      //   }
      //   socket.send(JSON.stringify(request))
      // } else {
        this.syncMessageSend(printerList)
      this.syncMessageSend(printerList)
        this.execSuccess({
          ErrCode: 'S',
          message: '',
          ErrMesg: '打印请求已发出。',
          status: true
        })
      // }
      this.execSuccess({
        ErrCode: 'S',
        message: '',
        ErrMesg: '打印请求已发出。',
        status: true
      })
    }
    // 监听消息
    socket.onmessage = (event) => {
src/tabviews/zshare/cardcomponent/index.jsx
@@ -208,6 +208,7 @@
              btn={item}
              BData={BData}
              setting={setting}
              columns={columns}
              selectedData={[data]}
            />
          )
src/tabviews/zshare/mutilform/index.jsx
@@ -301,7 +301,7 @@
            })
          } else if (item.regular === 'email') {
            _rules.push({
              pattern: /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/,
              pattern: /^([a-zA-Z0-9._-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/,
              message: item.regularText || '请正确输入邮箱地址'
            })
          }
@@ -715,6 +715,7 @@
      if (['select', 'link', 'radio', 'checkbox', 'checkcard', 'multiselect', 'cascader'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
        let options = []
        let map = new Map()
        let all = false
        result[item.field].forEach(cell => {
          let _cell = { key: Utils.getuuid() , ParentID: ''}
@@ -725,13 +726,27 @@
          if (item.type !== 'checkcard') {
            _cell.value = cell[item.valueField]
            _cell.label = cell[item.valueText] + ''
            if (!_cell.label || map.has(_cell.ParentID + _cell.value)) return
            if (map.has(_cell.ParentID + _cell.value)) return
            if (!_cell.label) {
              if (!all) {
                _cell.label = '全部'
                all = true
              } else {
                return
              }
            }
            
            map.set(_cell.ParentID + _cell.value, 0)
          } else {
            _cell.$value = cell[item.cardValField]
            _cell = {..._cell, ...cell}
            if (item.urlField) {
              _cell.$url = cell[item.urlField] || ''
            } else if (item.colorField) {
              _cell.$color = cell[item.colorField] || ''
            }
            if (map.has(_cell.ParentID + _cell.$value)) return
            
            map.set(_cell.ParentID + _cell.$value, 0)
src/tabviews/zshare/mutilform/mkCheckCard/index.jsx
@@ -191,7 +191,7 @@
        }
        return <Col span={width} key={item.key}>
          <div className={'card-color-cell' + (_active ? ' active' : '') + (item.$disabled ? ' disabled' : '')} style={{background: item.$value}} onClick={() => this.changeCard(item)}>
          <div className={'card-color-cell' + (_active ? ' active' : '') + (item.$disabled ? ' disabled' : '')} style={{background: item.$color}} onClick={() => this.changeCard(item)}>
            {fields.map(col => {
              return <span className="content-line" key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{item[col.field]}</span>
            })}
src/tabviews/zshare/mutilform/mkColor/index.jsx
@@ -29,7 +29,7 @@
  handleChange = (color) => {
    let _color = `rgba(${ color.rgb.r }, ${ color.rgb.g }, ${ color.rgb.b }, ${ color.rgb.a })`
    if (!this.props.config.isHex) {
    if (this.props.config.colorType !== 'hex') {
      this.setState({ color: _color }, () => {
        this.props.onChange(_color)
      })
src/tabviews/zshare/normalTable/index.scss
@@ -232,6 +232,11 @@
      display: block;
    }
  }
  // table tbody {
  //   tr:nth-child(even) {
  //     background: #f9f9f9;
  //   }
  // }
}
.image-scale-modal {
  width: 70vw;
src/tabviews/zshare/tablenodes/index.jsx
@@ -155,11 +155,8 @@
        let { tbs, ptbs } = this.getTbs(config)
        ptbs = Array.from(new Set(ptbs))
        ptbs = ptbs.filter(tb => tb.length > 1 && tb !== 'dbo')
        ptbs.sort()
        if (ptbs.length && sessionStorage.getItem('mk_tb_names')) {
          let names = sessionStorage.getItem('mk_tb_names')
          ptbs = ptbs.filter(tb => names.indexOf(',' + tb.toLowerCase() + ',') > -1)
        }
        if (ptbs.length) {
          ptbs.forEach((item, i) => {
@@ -184,6 +181,7 @@
        if (result.tb_list) {
          result.tb_list.sort((a, b) => a.tbname > b.tbname ? 1 : -1)
          let length = result.tb_list.length
          result.tb_list.forEach((item, i) => {
            let cell = {
              label: item.tbname,
@@ -191,6 +189,8 @@
              id: 'table' + i,
              direction: 'right',
              color: '#1890ff',
              collapsed: false,
              collable: true,
              children: []
            }
@@ -209,10 +209,17 @@
                    id: item.tbname + 'menu' + i,
                    direction: 'right',
                    color: '#1890ff',
                    type: 'dice-mind-map-leaf',
                    param: _param
                  })
                }
              })
            }
            if (cell.children.length > 5 && length > 1) {
              cell.collapsed = true
            } else if (cell.children.length === 0) {
              cell.collable = false
            }
            data.children.push(cell)
@@ -261,12 +268,12 @@
          const stroke = cfg.style.stroke || '#096dd9';
    
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
              <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${cfg.label}</text>
            </rect>
          </group>
        `;
            <group>
              <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
                <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${cfg.label}</text>
              </rect>
            </group>
          `;
        },
        getAnchorPoints() {
          return [
@@ -285,13 +292,13 @@
          const color = cfg.color;
    
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 26, fill: 'transparent' }}>
              <text style={{ fontSize: 12, fill: ${cfg.fontcolor ? cfg.fontcolor : 'black'}, marginLeft: 12, marginTop: 6 }}>${cfg.label}</text>
            </rect>
            <rect style={{ fill: ${color}, width: ${width}, height: 2, x: 0, y: 32 }} />
          </group>
        `;
            <group>
              <rect draggable="true" style={{width: ${width}, cursor: ${cfg.collable ? 'pointer' : 'default'}, height: 26, fill: 'transparent' }}>
                <text style={{ fontSize: 12, fill: ${cfg.fontcolor ? cfg.fontcolor : 'black'}, cursor: ${cfg.collable ? 'pointer' : 'default'}, marginLeft: 12, marginTop: 6 }}>${cfg.label} ${cfg.collable ? '+' : ''}</text>
              </rect>
              <rect style={{ fill: ${color}, width: ${width}, cursor: ${cfg.collable ? 'pointer' : 'default'}, height: 2, x: 0, y: 32 }} />
            </group>
          `;
        },
        getAnchorPoints() {
          return [
@@ -302,6 +309,7 @@
      },
      'single-node',
    );
    G6.registerBehavior('scroll-canvas', {
      getEvents: function getEvents() {
        return {
@@ -358,9 +366,10 @@
          data.color = color;
        }
    
        if (d.children) {
        if (d.children && !d.collapsed) {
          data.children = d.children.map((child) => changeData(child, level + 1, data.color));
        }
        return data;
      };
      return changeData(data);
@@ -399,9 +408,20 @@
          lineWidth: 2,
        },
      },
      minZoom: 0.5,
      minZoom: 0.3,
      modes: {
        default: ['drag-canvas', 'zoom-canvas'],
        default: [
          {
            type: 'collapse-expand',
            trigger: 'click',
            shouldBegin: (e, self) => {
              if (e.item && e.item.getModel().collable) return true;
              return false;
            },
          },
          'drag-canvas',
          'zoom-canvas'
        ],
      },
    });
    
@@ -441,6 +461,7 @@
          </div>
          <div className="footer">
            <Button key="cancel" onClick={() => { this.setState({ visible: false })}}>关闭</Button>
            <span className="tip">注:点击表名可展开/收起菜单</span>
          </div>
        </Modal>
      </div>
src/tabviews/zshare/tablenodes/index.scss
@@ -62,7 +62,16 @@
  }
  .footer {
    position: relative;
    text-align: center;
    .tip {
      position: absolute;
      font-size: 12px;
      color: var(--mk-sys-color);
      right: 10px;
      top: 20px;
    }
  }
  .tb-search {
    position: absolute;
src/tabviews/zshare/topSearch/index.jsx
@@ -4,6 +4,7 @@
import { Form, Row, Col, Button, notification, Modal, Drawer } from 'antd'
import { CloseOutlined, DownOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import options from '@/store/options.js'
@@ -37,6 +38,7 @@
  }
  record = {}
  sign = ''
  UNSAFE_componentWillMount () {
    const { config, searchlist, setting } = this.props
@@ -402,6 +404,7 @@
      if (['select', 'link', 'multiselect', 'checkcard'].includes(item.type) && result[item.field] && result[item.field].length > 0) {
        let options = []
        let map = new Map()
        let all = false
        result[item.field].forEach(cell => {
          let _item = {
            key: Utils.getuuid(),
@@ -416,12 +419,26 @@
            _item.Value = cell[item.valueField]
            _item.Text = cell[item.valueText] + ''
            
            if (!_item.Text || map.has(_item.ParentID + _item.Value)) return
            if (map.has(_item.ParentID + _item.Value)) return
            if (!_item.Text) {
              if (!all) {
                _item.Text = '全部'
                all = true
              } else {
                return
              }
            }
            
            map.set(_item.ParentID + _item.Value, 0)
          } else {
            _item.$value = cell[item.cardValField]
            _item = {..._item, ...cell}
            if (item.urlField) {
              _item.$url = cell[item.urlField] || ''
            } else if (item.colorField) {
              _item.$color = cell[item.colorField] || ''
            }
            if (map.has(_item.ParentID + _item.$value)) return
            
@@ -630,6 +647,15 @@
          }
        }
        let sign = md5(JSON.stringify(searches))
        if (sign === this.sign) return
        this.sign = sign
        setTimeout(() => {
          this.sign = ''
        }, 2000)
        this.props.refreshdata(searches)
      })
    })
src/templates/comtableconfig/updatetable/index.jsx
@@ -897,10 +897,12 @@
                datatype: 'dynamic',
                eleType: _cols[sub].type !== 'number' ? 'text' : 'number',
                field: sub,
                height: 1,
                innerHeight: 21,
                height: '',
                innerHeight: 'auto',
                marks: _cols[sub].marks || null,
                noValue: 'show',
                prefix: _cols[sub].prefix || '',
                postfix: _cols[sub].postfix || '',
                style: {},
                width: 24,
                uuid: Utils.getuuid()
src/templates/modalconfig/checkCard/index.jsx
@@ -66,7 +66,7 @@
      }
      return _options.map(item => {
        return <Col span={width} key={item.key}>
          <div className={'card-color-cell ' + cls} style={{background: item.$value}}>
          <div className={'card-color-cell ' + cls} style={{background: item.$color}}>
            {_fields.map(col => {
              return <span className="content-line" key={col.key} style={{color: col.color, fontSize: col.fontSize + 'px', height: col.fontSize * 1.5 + 'px', textAlign: col.align}}>{item[col.field]}</span>
            })}
src/templates/modalconfig/dragelement/index.scss
@@ -124,6 +124,9 @@
      width: 89.5%;
    }
  }
  .ant-form-item label > .anticon {
    vertical-align: middle;
  }
}
.modal-fields-row.up_down {
  .ant-form-item {
src/templates/modalconfig/index.jsx
@@ -783,7 +783,7 @@
                <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']} config={this.state.config} plusFields={this.plusFields}/>
                <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>
src/templates/modalconfig/settingform/index.jsx
@@ -256,7 +256,7 @@
            </Form.Item>
          </Col> : null}
          {display === 'drawer' ? <Col span={12}>
            <Form.Item label="抽屉方向">
            <Form.Item label="弹出方向">
              {getFieldDecorator('placement', {
                initialValue: placement
              })(
src/templates/sharecomponent/actioncomponent/actionform/index.jsx
@@ -383,9 +383,11 @@
        
        _fieldval.label = '导入Excel'
        _fieldval.class = 'dgreen'
        _fieldval.execSuccess = 'grid'
        this.record.Ot = 'notRequired'
        this.record.label = '导入Excel'
        this.record.class = 'dgreen'
        this.record.execSuccess = 'grid'
      } else if (value === 'excelOut') {
        _fieldval.intertype = 'system'
        _fieldval.label = '导出Excel'
src/templates/sharecomponent/actioncomponent/index.jsx
@@ -878,7 +878,8 @@
    } else if (card.OpenType === 'funcbutton' && card.funcType === 'print') {
      return <VerifyPrint
        card={card}
        columns={config.columns}
        columns={[]}
        // columns={config.columns}
        wrappedComponentRef={(inst) => this.verifyRef = inst}
      />
    } else if (card.OpenType === 'funcbutton' && card.funcType === 'megvii') {
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -49,7 +49,7 @@
      _dec += ','
    }
    let _sql = `Declare @${btn.sheet} table (${_dec}jskey nvarchar(50) )
    let _sql = `Declare @${btn.sheet.replace(/@db@/ig, '')} table (${_dec}jskey nvarchar(50) )
      Declare @UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100),@ErrorCode nvarchar(50), @retmsg nvarchar(4000),@tbid Nvarchar(512)
      Select @ErrorCode='', @retmsg=''
    `
@@ -183,7 +183,7 @@
        }
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.LText = param.LText.replace(/@\$|\$@/ig, '').replace(/\$check@|@check\$/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${param.timestamp}'`)
        param.LText = param.LText.replace(/@\$|\$@/ig, '').replace(/\$check@|@check\$/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${param.timestamp}'`)
        param.LText = param.LText.replace(/\n/g, ' ')
        
        // 外联数据库替换
@@ -298,7 +298,7 @@
          </Col>
          <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              {usefulfields}
            </Form.Item>
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -239,8 +239,10 @@
  UNSAFE_componentWillMount() {
    const { card } = this.props
    let _verify = fromJS(card.verify || {range: 1}).toJS()
    let _verify = fromJS(card.verify || {}).toJS()
    let _columns = _verify.columns || []
    delete _verify.dataresource
    // 旧数据兼容
    _columns = _columns.map(col => {
@@ -248,6 +250,12 @@
      col.type = col.type || 'Nvarchar(50)'
      col.import = col.import || 'true'
      col.required = col.required || 'true'
      if (col.type === 'text' || col.type === 'image') {
        col.type = 'Nvarchar(50)'
      } else if (col.type === 'number') {
        col.type = 'Decimal(18,2)'
      }
      
      if (/^Nvarchar/ig.test(col.type)) {
        col.limit = col.type.match(/\d+/)[0]
@@ -260,6 +268,10 @@
      return col
    })
    if (!_verify.hasOwnProperty('range')) {
      _verify.range = 1
    }
    this.setState({
      verify: {
        ..._verify,
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -1,8 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Button, notification, Modal, Tooltip, Radio, Select } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { Form, Row, Col, Button, notification, Tooltip, Select } from 'antd'
import moment from 'moment'
import Api from '@/api'
@@ -12,39 +11,100 @@
class CustomForm extends Component {
  static propTpyes = {
    scripts: PropTypes.array,       // 自定义脚本列表
    usefulfields: PropTypes.any,    // 可用字段
    systemScripts: PropTypes.array, // 系统脚本
    scriptsChange: PropTypes.func   // 表单
    searches: PropTypes.any,        // 搜索条件
    linefields: PropTypes.any,
    scriptsChange: PropTypes.func
  }
  state = {
    editItem: null,
    systemScripts: [],
    usefulfields: null,
    loading: false,
    verifySql: ''
  }
  UNSAFE_componentWillMount () {
    this.resetfield(this.props.usefulfields)
    this.resetfield(this.props.searches)
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (nextProps.usefulfields && !is(fromJS(this.props.usefulfields), fromJS(nextProps.usefulfields))) {
      this.resetfield(nextProps.usefulfields)
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (!is(fromJS(this.props.searches), fromJS(nextProps.searches))) {
      this.resetfield(nextProps.searches)
    }
  }
  resetfield = (columns) => {
    columns = columns.filter(item => item.Column !== '$Index')
    let fields = columns.map(item => item.Column)
  componentDidMount () {
    this.getsysScript()
  }
    let _sql = `Declare @UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100),@ErrorCode nvarchar(50), @retmsg nvarchar(4000)
    `
  getsysScript = () => {
    if (sessionStorage.getItem('mk_sys_scripts')) {
      this.setState({
        systemScripts: JSON.parse(sessionStorage.getItem('mk_sys_scripts'))
      })
      return
    }
    
    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from  s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
    _scriptSql = Utils.formatOptions(_scriptSql)
    let _sParam = {
      func: 'sPC_Get_SelectedList',
      LText: _scriptSql,
      obj_name: 'data',
      arr_field: 'funcname,longparam'
    }
    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
    _sParam.open_key = Utils.encryptOpenKey(_sParam.secretkey, _sParam.timestamp) // 云端数据验证
    Api.getSystemConfig(_sParam).then(res => {
      if (res.status) {
        let _scripts = res.data.map(item => {
          return {
            name: item.funcname,
            value: window.decodeURIComponent(window.atob(item.longparam))
          }
        })
        sessionStorage.setItem('mk_sys_scripts', JSON.stringify(_scripts))
        this.setState({
          systemScripts: _scripts
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  resetfield = (searches) => {
    let _usefulFields = []
    searches.forEach(item => {
      if (!item.field) return
      if (item.type === 'group') {
        _usefulFields.push(item.field)
        _usefulFields.push(item.datefield)
        _usefulFields.push(item.datefield + '1')
      } else if (['dateweek', 'datemonth', 'daterange'].includes(item.type)) {
        _usefulFields.push(item.field)
        _usefulFields.push(item.field + '1')
      } else if (item.type === 'date' && _usefulFields.includes(item.field)) {
        _usefulFields.push(item.field + '1')
      } else {
        _usefulFields.push(item.field)
      }
    })
    this.setState({
      verifySql: _sql,
      usefulfields: fields.join(', ')
      usefulfields: _usefulFields.join(', ')
    })
  }
@@ -116,89 +176,22 @@
          return
        }
        let tail = `
          aaa:
        `
        let _initCustomScript = '' // 初始化脚本
        let _prevCustomScript = '' // 默认sql前执行脚本
        let _backCustomScript = '' // 默认sql后执行脚本
        this.props.scripts.forEach(item => {
          if (item.status === 'false') return
          if (item.position === 'init') {
            _initCustomScript += `
            /* 初始化脚本 */
            ${values.uuid === item.uuid ? values.sql : item.sql}
            `
          } else if (item.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${values.uuid === item.uuid ? values.sql : item.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${values.uuid === item.uuid ? values.sql : item.sql}
            `
          }
        this.setState({
          loading: true
        })
        if (!values.uuid) {
          if (values.position === 'init') {
            _initCustomScript += `
            /* 初始化脚本 */
            ${values.sql}
            `
          } else if (values.position === 'front') {
            _prevCustomScript += `
            /* 默认sql前脚本 */
            ${values.sql}
            `
          } else {
            _backCustomScript += `
            /* 默认sql后脚本 */
            ${values.sql}
            `
          }
        }
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: this.state.verifySql + _initCustomScript + _prevCustomScript + _backCustomScript + tail
        }
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.LText = param.LText.replace(/@\$|\$@/ig, '').replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${param.timestamp}'`)
        param.LText = param.LText.replace(/\n/g, ' ')
        // 外联数据库替换
        if (window.GLOB.externalDatabase !== null) {
          param.LText = param.LText.replace(/@db@/ig, window.GLOB.externalDatabase)
        }
        param.LText = Utils.formatOptions(param.LText)
        param.secretkey = Utils.encrypt('', param.timestamp)
        this.setState({loading: true})
        Api.genericInterface(param).then(res => {
          if (res.status) {
        this.props.scriptsChange(values, (status) => {
          if (status) {
            this.setState({
              loading: false,
              editItem: null
            }, () => {
              this.props.scriptsChange(values)
            })
            this.props.form.setFieldsValue({
              sql: ''
            })
          } else {
            this.setState({loading: false})
            Modal.error({
              title: res.message
            this.setState({
              loading: false
            })
          }
        })
@@ -250,8 +243,8 @@
  }
  render() {
    const { systemScripts, sheet } = this.props
    const { usefulfields } = this.state
    const { sheet, linefields } = this.props
    const { usefulfields, systemScripts } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
@@ -280,11 +273,12 @@
          <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              {usefulfields}
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>
              {usefulfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'搜索条件,请按照@xxx@格式使用。'}>,&nbsp;{usefulfields}</Tooltip> : null}
              {linefields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'表单及行变量,系统会定义变量并赋值。'}>,&nbsp;{linefields}</Tooltip> : null}
            </Form.Item>
          </Col>
          <Col span={8} style={{whiteSpace: 'nowrap'}}>
          {/* <Col span={8} style={{whiteSpace: 'nowrap'}}>
            <Form.Item style={{marginBottom: 0}} label={
              <Tooltip placement="bottomLeft" title={'自定义脚本与默认sql位置关系。'}>
                <QuestionCircleOutlined className="mk-form-tip" />
@@ -301,8 +295,8 @@
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={10}>
          </Col> */}
          <Col span={8}>
            <Form.Item style={{marginBottom: 0}} label={'快捷添加'}>
              <Select
                showSearch
src/templates/sharecomponent/actioncomponent/verifyexcelout/datasource/index.jsx
@@ -11,6 +11,7 @@
class SettingForm extends Component {
  static propTpyes = {
    btnType: PropTypes.any,
    setting: PropTypes.object,    // 数据源配置
  }
@@ -20,10 +21,10 @@
  }
  UNSAFE_componentWillMount () {
    const { setting } = this.props
    const { setting, btnType } = this.props
    this.setState({
      dataType: setting.dataType,
      dataType: btnType === 'print' ? 'custom' : setting.dataType,
      defaultSql: setting.defaultSql || 'true'
    })
  }
@@ -104,7 +105,7 @@
  }
  render() {
    const { setting } = this.props
    const { setting, btnType } = this.props
    const { getFieldDecorator } = this.props.form
    const { dataType, defaultSql } = this.state
@@ -123,7 +124,7 @@
      <div className="excelout-datasource-wrap">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            <Col span={8}>
            {btnType !== 'print' ? <Col span={8}>
              <Form.Item label="导出数据">
                {getFieldDecorator('dataType', {
                  initialValue: setting.dataType
@@ -134,7 +135,7 @@
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
            </Col> : null}
            {dataType === 'custom' ? <Col className="short-label" span={8}>
              <Form.Item label="表名">
                {getFieldDecorator('tableName', {
@@ -198,12 +199,7 @@
              </Form.Item>
            </Col> : null}
            {dataType === 'custom' && defaultSql === 'true' ? <Col className="short-label" span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="排序方式为空时,使用表格或组件中的排序方式。">
                  <QuestionCircleOutlined className="mk-form-tip" />
                  排序方式
                </Tooltip>
              }>
              <Form.Item label="排序方式">
                {getFieldDecorator('order', {
                  initialValue: setting.order || '',
                  rules: [
@@ -215,9 +211,9 @@
                })(<Input placeholder={'ID asc, UID desc'} autoComplete="off" />)}
              </Form.Item>
            </Col> : null}
            {dataType === 'custom' ? <Col span={8}>
            {dataType === 'custom' && btnType !== 'print' ? <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="不使用搜索条件时,不会进行搜索条件的拼接与相关统计字段的替换。注:自定义数据来源时,只使用内部搜索。">
                <Tooltip placement="topLeft" title="不使用搜索条件时,不会进行搜索条件的拼接与相关统计字段的替换。">
                  <QuestionCircleOutlined className="mk-form-tip" />
                  搜索条件
                </Tooltip>
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -29,7 +29,6 @@
  state = {
    verify: {},
    activeKey: 'setting',
    systemScripts: [],
    defaultscript: '', // 自定义脚本
    excelColumns: [
      {
@@ -38,7 +37,7 @@
        inputType: 'input',
        editable: true,
        unique: true,
        width: '17%'
        width: '16%'
      },
      {
        title: '名称',
@@ -46,7 +45,7 @@
        inputType: 'input',
        editable: true,
        unique: true,
        width: '17%'
        width: '16%'
      },
      {
        title: '列宽',
@@ -55,7 +54,7 @@
        min: 5,
        max: 200,
        editable: true,
        width: '12%',
        width: '10%',
        render: (text) => text || 20
      },
      {
@@ -64,7 +63,7 @@
        inputType: 'select',
        editable: true,
        required: false,
        width: '14%',
        width: '12%',
        render: (text) => {
          if (text === 'image') {
            return '图片'
@@ -86,7 +85,7 @@
        inputType: 'radio',
        editable: true,
        required: false,
        width: '14%',
        width: '12%',
        render: (text) => {
          if (text === 'true') {
            return '是'
@@ -115,7 +114,7 @@
        inputType: 'radio',
        editable: true,
        required: false,
        width: '14%',
        width: '12%',
        render: (text) => {
          if (text !== 'false') {
            return '是'
@@ -127,7 +126,19 @@
          {value: 'true', text: '是'},
          {value: 'false', text: '否'}
        ]
      }
      },
      {
        title: '红色标题',
        dataIndex: 'required',
        width: '10%',
        editable: true,
        inputType: 'radio',
        render: (text, record) => record.required === 'true' ? '是' : '否',
        options: [
          {value: 'true', text: '是'},
          {value: 'false', text: '否'}
        ]
      },
    ],
    scriptsColumns: [
      {
@@ -216,13 +227,21 @@
    if (card.intertype !== 'system') {
      _verify.enable = 'false'
    }
    if (_verify.columns[0] && (!_verify.columns[0].type || !_verify.columns[0].output)) {
      _verify.columns = _verify.columns.map(col => {
        col.type = col.type || 'text'
        col.output = col.output || 'true'
        return col
      })
    }
    _verify.columns = _verify.columns.map(col => {
      col.type = col.type || 'text'
      col.output = col.output || 'true'
      col.required = col.required || 'false'
      if (!['text', 'image', 'number'].includes(col.type)) {
        if (/^Decimal/ig.test(col.type)) {
          col.type = 'number'
        } else {
          col.type = 'text'
        }
      }
      return col
    })
    let defaultscript = ''
    if (!_verify.script && card.intertype === 'system') {
@@ -356,57 +375,6 @@
    })
  }
  componentDidMount () {
    this.getsysScript()
  }
  getsysScript = () => {
    if (sessionStorage.getItem('mk_sys_scripts')) {
      this.setState({
        systemScripts: JSON.parse(sessionStorage.getItem('mk_sys_scripts'))
      })
      return
    }
    let _scriptSql = `Select distinct func+Remark as funcname,longparam, s.Sort from  s_custom_script s inner join (select OpenID from sapp where ID=@Appkey@) p on s.openid = case when s.appkey='' then s.openid else p.OpenID end order by s.Sort`
    _scriptSql = Utils.formatOptions(_scriptSql)
    let _sParam = {
      func: 'sPC_Get_SelectedList',
      LText: _scriptSql,
      obj_name: 'data',
      arr_field: 'funcname,longparam'
    }
    _sParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    _sParam.secretkey = Utils.encrypt(_sParam.LText, _sParam.timestamp)
    _sParam.open_key = Utils.encryptOpenKey(_sParam.secretkey, _sParam.timestamp) // 云端数据验证
    Api.getSystemConfig(_sParam).then(res => {
      if (res.status) {
        let _scripts = res.data.map(item => {
          return {
            name: item.funcname,
            value: window.decodeURIComponent(window.atob(item.longparam))
          }
        })
        sessionStorage.setItem('mk_sys_scripts', JSON.stringify(_scripts))
        this.setState({
          systemScripts: _scripts
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  handleEdit = (record, type) => {
    let node = null
@@ -511,6 +479,7 @@
    values.uuid = Utils.getuuid()
    values.abs = 'false'
    values.output = 'true'
    values.required = 'false'
    verify.columns.push(values)
    this.setState({
@@ -803,6 +772,7 @@
        Width: 20,
        abs: 'false',
        output: 'true',
        required: 'false',
        type: 'text',
        uuid: Utils.getuuid()
      }
@@ -850,6 +820,7 @@
          Width: 20,
          abs: 'false',
          output: col.output || 'true',
          required: col.required || 'false',
          type: 'text',
        }
@@ -920,10 +891,9 @@
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
          message: '存在未保存脚本!',
          duration: 5
        })
        return
      }
      this.setState({loading: true})
@@ -945,7 +915,7 @@
    }
  }
  scriptsChange = (values) => {
  scriptsChange = (values, callback) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
@@ -968,10 +938,12 @@
        loading: false,
        verify: verify
      })
      callback(true)
    }, () => {             // 验证失败
      this.setState({
        loading: false
      })
      callback(false)
    }, verify.scripts)
  }
@@ -984,7 +956,7 @@
    }
    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    let sql = SettingUtils.getDebugSql(verify, scripts, searches, Utils, timestamp)
    let sql = SettingUtils.getDebugSql(verify, scripts, (verify.useSearch === 'true' ? searches : []), Utils, timestamp)
    let param = {
      func: 's_debug_sql',
      exec_type: 'y',
@@ -1012,7 +984,7 @@
  render() {
    const { card } = this.props
    const { verify, excelColumns, defaultscript, scriptsColumns, activeKey, loading } = this.state
    const { verify, excelColumns, defaultscript, scriptsColumns, activeKey, loading, searches } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
@@ -1046,7 +1018,7 @@
            <Button className="excel-col-add mk-red" title="清空Excel列" onClick={this.clearField}>
              清空Excel列
            </Button>
            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>如需导出序号,请使用字段 $Index;数值类型导出时可进行数据处理(取绝对值、保留小数位)。</div>
            <div style={{color: '#959595', fontSize: '13px', paddingLeft: '10px'}}>如需导出序号,请使用字段 $Index;数值类型导出时可进行数据处理(取绝对值、保留小数位);红色标题导出时列头文字为红色。</div>
            <EditTable actions={['edit', 'move', 'copy', 'del']} type="excelcolumn" wrappedComponentRef={(inst) => this.columnRef = inst} data={verify.columns} columns={excelColumns} onChange={this.changeColumns}/>
          </TabPane>
          {card.intertype === 'system' ? <TabPane tab={
@@ -1058,9 +1030,7 @@
            <CustomScript
              btn={card}
              sheet={verify.tableName}
              usefulfields={verify.columns}
              scripts={verify.scripts}
              systemScripts={this.state.systemScripts}
              searches={verify.useSearch === 'true' ? searches : []}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -23,6 +23,10 @@
    })
    arr_field = arr_field.join(',')
    if (!arr_field) {
      arr_field = '*'
    }
    let _customScript = ''
    scripts && scripts.forEach(script => {
      if (script.status === 'false') return
@@ -39,14 +43,6 @@
    if (verify.defaultSql === 'false') {
      _dataresource = ''
    }
    if (window.GLOB.funcs && window.GLOB.funcs.length > 0) {
      window.GLOB.funcs.forEach(item => {
        let reg = new RegExp('\\$ex@' + item.func_code + '@ex\\$', 'ig')
        _dataresource = _dataresource.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
        _customScript = _customScript.replace(reg, `/*$ex@${item.func_code}-begin*/\n${item.key_sql}\n/*@ex$-end*/`)
      })
    }
    
    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
@@ -105,15 +101,15 @@
    }
    // 数据源处理, 存在显示列时 
    if (arr_field && _dataresource) {
    if (_dataresource) {
      if (/\s/.test(_dataresource)) {
        _dataresource = '(' + _dataresource + ') tb'
      }
      if (verify.order) {
        _dataresource = `select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${verify.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows`
        _dataresource = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${verify.order}) as rows from ${_dataresource} ${_search}) tmptable order by tmptable.rows`
      } else {
        _dataresource = `select ${arr_field} from ${_dataresource} ${_search}`
        _dataresource = `/*system_query*/select ${arr_field} from ${_dataresource} ${_search}`
      }
    }
src/templates/sharecomponent/actioncomponent/verifyprint/editable/index.jsx
@@ -1,4 +1,5 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
import { Table, Input, Popconfirm, Form } from 'antd'
import { ArrowUpOutlined, ArrowDownOutlined, PlusOutlined, DeleteOutlined } from '@ant-design/icons'
import Utils from '@/utils/utils.js'
@@ -160,11 +161,14 @@
    this.setState({
      dataSource: _data
    })
    this.props.onChange(fromJS(_data).toJS())
  }
  handleDelete = key => {
    const dataSource = [...this.state.dataSource]
    this.setState({ dataSource: dataSource.filter(item => item.key !== key) })
    const dataSource = [...this.state.dataSource].filter(item => item.key !== key)
    this.setState({ dataSource: dataSource })
    this.props.onChange(fromJS(dataSource).toJS())
  }
  handleAdd = () => {
@@ -174,11 +178,13 @@
      Value: `${count}`,
      Text: `${count}`
    }
    let list = [...dataSource, newData]
    this.setState({
      dataSource: [...dataSource, newData],
      dataSource: list,
      count: count + 1
    })
    this.props.onChange(fromJS(list).toJS())
  }
  handleSave = row => {
@@ -190,10 +196,7 @@
      ...row
    })
    this.setState({ dataSource: newData })
  }
  UNSAFE_componentWillReceiveProps () {
    this.props.onChange(fromJS(newData).toJS())
  }
  render() {
src/templates/sharecomponent/actioncomponent/verifyprint/index.jsx
@@ -1,16 +1,25 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio, Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { fromJS } from 'immutable'
import { Form, Tabs, Row, Col, Button, notification, Modal, message, InputNumber, Input, Select, Radio, Tooltip, Typography, Popconfirm, Spin } from 'antd'
import { QuestionCircleOutlined, EditOutlined, StopOutlined, CheckCircleOutlined, SwapOutlined, DeleteOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import SettingUtils from './utils.jsx'
import CodeMirror from '@/templates/zshare/codemirror'
import DataSource from '../verifyexcelout/datasource'
import CustomScript from '../verifyexcelout/customscript'
import asyncComponent from '@/utils/asyncComponent'
import ColForm from '@/menu/datasource/verifycard/columnform'
import EditTable from './editable'
import './index.scss'
const EditMTable = asyncComponent(() => import('@/templates/zshare/editTable'))
const FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
const { Paragraph } = Typography
const { TabPane } = Tabs
class VerifyCard extends Component {
@@ -25,20 +34,239 @@
  state = {
    verify: {},
    templates: [],
    loading: false,
    activeKey: 'base',
    selectimg: '',
    printMode: 'normal'
    dataType: 'line',
    printMode: 'normal',
    usefulfields: '',
    declareSql: '',
    scriptsColumns: [
      {
        title: 'SQL',
        dataIndex: 'sql',
        width: '60%',
        render: (text) => {
          let title = text.match(/^\s*\/\*.+\*\//)
          title = title && title[0] ? title[0] : ''
          let _text = title ? text.replace(title, '') : text
          return (
            <div>
              {title ? <span style={{color: '#a50'}}>{title}<span style={{fontSize: '12px', marginLeft: '5px'}}>{_text.length}</span></span> : null}
              <Paragraph copyable={{ text: text }} ellipsis={{ rows: 4, expandable: true }}>{_text}</Paragraph>
            </div>
          )
        }
      },
      {
        title: '执行位置',
        dataIndex: 'position',
        width: '10%',
        render: (text, record) => {
          if (record.position === 'init') {
            return <span style={{color: 'orange'}}>初始化</span>
          } else if (record.position === 'front') {
            return <span style={{color: '#26C281'}}>sql前</span>
          } else {
            return <span style={{color: '#1890ff'}}>sql后</span>
          }
        }
      },
      {
        title: '状态',
        dataIndex: 'status',
        width: '10%',
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
          (
            <div style={{color: '#26C281'}}>
              启用
              <CheckCircleOutlined style={{marginLeft: '5px'}}/>
            </div>
          )
      },
      {
        title: '操作',
        align: 'center',
        width: '140px',
        dataIndex: 'operation',
        render: (text, record) =>
          (<div style={{textAlign: 'center'}}>
            <span className="operation-btn" title="编辑" onClick={() => this.handleEdit(record, 'scripts')} style={{color: '#1890ff'}}><EditOutlined /></span>
            <span className="operation-btn" title="状态切换" onClick={() => this.handleStatus(record, 'scripts')} style={{color: '#8E44AD'}}><SwapOutlined /></span>
            <Popconfirm
              overlayClassName="popover-confirm"
              title="确定删除吗?"
              onConfirm={() => this.handleDelete(record, 'scripts')
            }>
              <span className="operation-btn" style={{color: '#ff4d4f'}}><DeleteOutlined /></span>
            </Popconfirm>
          </div>)
      }
    ],
    colColumns: [
      {
        title: '名称',
        dataIndex: 'label',
        inputType: 'input',
        editable: true,
        width: '28%'
      },
      {
        title: '字段',
        dataIndex: 'field',
        inputType: 'input',
        editable: true,
        unique: true,
        copy: true,
        rules: [{
          pattern: /^[\u4E00-\u9FA50-9a-zA-Z_]*$/ig,
          message: '字段名只允许包含数字、字母、汉字以及_'
        }],
        width: '28%'
      },
      {
        title: '数据类型',
        dataIndex: 'datatype',
        inputType: 'select',
        options: [
          { value: 'Nvarchar(10)', text: 'Nvarchar(10)' },
          { value: 'Nvarchar(20)', text: 'Nvarchar(20)' },
          { value: 'Nvarchar(50)', text: 'Nvarchar(50)' },
          { value: 'Nvarchar(100)', text: 'Nvarchar(100)' },
          { value: 'Nvarchar(256)', text: 'Nvarchar(256)' },
          { value: 'Nvarchar(512)', text: 'Nvarchar(512)' },
          { value: 'Nvarchar(1024)', text: 'Nvarchar(1024)' },
          { value: 'Nvarchar(2048)', text: 'Nvarchar(2048)' },
          { value: 'Nvarchar(max)', text: 'Nvarchar(max)' },
          { value: 'Int', text: 'Int' },
          { value: 'Decimal(18,0)', text: 'Decimal(18,0)' },
          { value: 'Decimal(18,1)', text: 'Decimal(18,1)' },
          { value: 'Decimal(18,2)', text: 'Decimal(18,2)' },
          { value: 'Decimal(18,3)', text: 'Decimal(18,3)' },
          { value: 'Decimal(18,4)', text: 'Decimal(18,4)' },
          { value: 'Decimal(18,5)', text: 'Decimal(18,5)' },
          { value: 'Decimal(18,6)', text: 'Decimal(18,6)' },
          { value: 'Decimal(18,7)', text: 'Decimal(18,7)' },
          { value: 'Decimal(18,8)', text: 'Decimal(18,8)' },
          { value: 'Decimal(18,9)', text: 'Decimal(18,9)' },
          { value: 'Decimal(18,10)', text: 'Decimal(18,10)' },
          { value: 'Decimal(18,11)', text: 'Decimal(18,11)' },
          { value: 'Decimal(18,12)', text: 'Decimal(18,12)' },
          { value: 'Decimal(18,13)', text: 'Decimal(18,13)' },
          { value: 'Decimal(18,14)', text: 'Decimal(18,14)' },
          { value: 'Decimal(18,15)', text: 'Decimal(18,15)' },
          { value: 'Decimal(18,16)', text: 'Decimal(18,16)' },
          { value: 'Decimal(18,17)', text: 'Decimal(18,17)' },
          { value: 'Decimal(18,18)', text: 'Decimal(18,18)' },
          { value: 'date', text: 'date' },
          { value: 'datetime', text: 'datetime' },
        ],
        editable: true,
        width: '25%',
      }
    ]
  }
  UNSAFE_componentWillMount() {
    let _verify = this.props.card.verify || {}
    const { columns, card } = this.props
    let _verify = fromJS(card.verify || {}).toJS()
    _verify.Template = _verify.Template || ''
    _verify.printerTypeList = _verify.printerTypeList || []
    _verify.linkType = _verify.linkType || 'system'
    _verify.printMode = _verify.printMode || 'normal'
    _verify.scripts = _verify.scripts || []
    _verify.columns = _verify.columns || []
    let _usefulfields = []
    let _declare = []
    let _select = []
    let fieldArr = []
    let _sql = ''
    if (card.execMode === 'pop' && card.modal && card.modal.fields) {
      card.modal.fields.forEach(_f => {
        if (!_f.field || fieldArr.includes(_f.field.toLowerCase())) return
        fieldArr.push(_f.field.toLowerCase())
        _usefulfields.push(_f.field)
        let _fieldlen = _f.fieldlength || 50
        if (_f.type === 'number') {
          _fieldlen = _f.decimal ? _f.decimal : 0
        }
        if (_fieldlen > 2048) {
          _fieldlen = 'max'
        }
        let _type = `nvarchar(${_fieldlen})`
        if (_f.type.match(/date/ig)) {
          _type = 'datetime'
          _select.push(`@${_f.field}='1949-10-01'`)
        } else if (_f.type === 'number') {
          _type = `decimal(18,${_fieldlen})`
          _select.push(`@${_f.field}=0`)
        } else if (_f.type === 'rate') {
          _type = `decimal(18,2)`
          _select.push(`@${_f.field}=0`)
        } else {
          _select.push(`@${_f.field}=''`)
        }
        _declare.push(`@${_f.field} ${_type}`)
      })
      if (_declare.length > 0) {
        _sql = `/* 表单变量 */
          Declare ${_declare.join(', ')}
          Select ${_select.join(', ')}
        `
      }
      _declare = []
      _select = []
    }
    if (columns && columns.length > 0 && card.Ot !== 'notRequired') {
      columns.forEach(_f => {
        if (!_f.field || fieldArr.includes(_f.field.toLowerCase()) || !_f.datatype) return
        fieldArr.push(_f.field.toLowerCase())
        _usefulfields.push(_f.field)
        if (/decimal/ig.test(_f.datatype)) {
          _select.push(`@${_f.field}=0`)
        } else {
          _select.push(`@${_f.field}=''`)
        }
        _declare.push(`@${_f.field} ${_f.datatype}`)
      })
      if (_declare.length > 0) {
        _sql += `/* 显示列变量 */
          Declare ${_declare.join(', ')}
          Select ${_select.join(', ')}
        `
      }
    }
    this.setState({
      verify: _verify,
      declareSql: _sql,
      usefulfields: _usefulfields.join(', '),
      dataType: _verify.dataType || 'line',
      linkType: _verify.linkType,
      printMode: _verify.printMode,
      printFunc: _verify.printFunc || '// Function(data, form, printer, notification) data-打印数据列表,form-表单信息(不存在时为{}),printer-打印设置,notification-信息提示控件'
@@ -157,56 +385,67 @@
  }
  handleConfirm = () => {
    const { verify } = this.state
    const { verify, activeKey } = this.state
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          let _verify = {...verify, ...values}
          if (this.refs.editTable && this.refs.editTable.state) {
            let printTypes = this.refs.editTable.state.dataSource
      if (activeKey === 'base') {
        this.props.form.validateFieldsAndScroll((err, values) => {
          if (err) return
  
            let emptys = printTypes.filter(item => !item.Value || !item.Text)
            let valMap = new Map()
            let isvalid = true
          resolve({...verify, ...values})
        })
      } else if (activeKey === 'print') {
        if (verify.printerTypeList.length > 0) {
          let printTypes = verify.printerTypeList.map(item => item.Value)
          printTypes = Array.from(new Set(printTypes))
  
            printTypes.forEach(item => {
              if (valMap.has(item.Value)) {
                isvalid = false
              } else {
                valMap.set(item.Value, item.Text)
              }
          if (verify.printerTypeList.length > printTypes.length) {
            notification.warning({
              top: 92,
              message: '打印类型中Value字段不可重复!',
              duration: 5
            })
            if (emptys.length > 0) {
              notification.warning({
                top: 92,
                message: '打印类型表格中Value、Text字段不可为空!',
                duration: 5
              })
              return
            } else if (!isvalid) {
              notification.warning({
                top: 92,
                message: '打印类型表格中Value字段不可重复!',
                duration: 5
              })
              return
            }
            _verify.printerTypeList = printTypes
            return
          }
          resolve(_verify)
        } else {
        }
        resolve(verify)
      } else if (activeKey === 'setting') {
        this.settingForm.handleConfirm().then(res => {
          let _verify = {...verify, setting: res}
          this.setState({
            verify: _verify
          }, () => {
            this.setState({loading: true})
            this.sqlverify(() => { // 验证成功
              resolve(_verify)
            }, () => {             // 验证失败
              this.setState({
                loading: false
              })
            }, _verify.scripts)
          })
        })
      } else if (activeKey === 'scripts') {
        if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
          notification.warning({
            top: 92,
            message: '链接地址与打印模板不可为空!',
            message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
            duration: 5
          })
          return
        }
      })
        this.setState({loading: true})
        this.sqlverify(() => { // 验证成功
          resolve(verify)
        }, () => {             // 验证失败
          this.setState({
            loading: false
          })
        }, verify.scripts)
      } else {
        resolve(verify)
      }
    })
  }
@@ -254,10 +493,181 @@
    })
  }
  changeDataType = (e) => {
    let value = e.target.value
    this.setState({
      dataType: value
    })
  }
  // 标签切换
  tabchange = (val) => {
    const { activeKey, verify } = this.state
    if (activeKey === 'base') {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (err) return
        this.setState({
          verify: {...verify, ...values},
          activeKey: val
        })
      })
    } else if (activeKey === 'print') {
      if (verify.printerTypeList.length > 0) {
        let printTypes = verify.printerTypeList.map(item => item.Value)
        printTypes = Array.from(new Set(printTypes))
        if (verify.printerTypeList.length > printTypes.length) {
          notification.warning({
            top: 92,
            message: '打印类型中Value字段不可重复!',
            duration: 5
          })
          return
        }
      }
      this.setState({
        activeKey: val
      })
    } else if (activeKey === 'setting') {
      this.settingForm.handleConfirm().then(res => {
        this.setState({
          verify: {...verify, setting: res}
        }, () => {
          this.setState({loading: true})
          this.sqlverify(() => { // 验证成功
            this.setState({
              activeKey: val,
              loading: false
            })
          }, () => {             // 验证失败
            this.setState({
              activeKey: val,
              loading: false
            })
          }, verify.scripts)
        })
      })
    } else if (activeKey === 'scripts') {
      if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本!',
          duration: 5
        })
      }
      this.setState({loading: true})
      this.sqlverify(() => { // 验证成功
        this.setState({
          activeKey: val,
          loading: false
        })
      }, () => {             // 验证失败
        this.setState({
          activeKey: val,
          loading: false
        })
      }, verify.scripts)
    } else {
      this.setState({
        activeKey: val
      })
    }
  }
  scriptsChange = (values, callback) => {
    let verify = JSON.parse(JSON.stringify(this.state.verify))
    if (values.uuid) {
      verify.scripts = verify.scripts.map(item => {
        if (item.uuid === values.uuid) {
          return values
        } else {
          return item
        }
      })
    } else {
      values.uuid = Utils.getuuid()
      verify.scripts.push(values)
    }
    this.setState({loading: true})
    this.sqlverify(() => { // 验证成功
      this.setState({
        loading: false,
        verify: verify
      })
      callback(true)
    }, () => {             // 验证失败
      this.setState({
        loading: false
      })
      callback(false)
    }, verify.scripts)
  }
  sqlverify = (_resolve, _reject, scripts) => {
    const { verify, declareSql } = this.state
    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    let sql = SettingUtils.getDebugSql(verify.setting || {}, verify.columns, scripts, declareSql, timestamp)
    let param = {
      func: 's_debug_sql',
      exec_type: 'y',
      LText: sql
    }
    param.LText = Utils.formatOptions(param.LText)
    param.timestamp = timestamp
    param.secretkey = Utils.encrypt('', timestamp)
    Api.genericInterface(param).then(result => {
      if (result.status) {
        _resolve()
      } else {
        _reject()
        Modal.error({
          title: result.message
        })
      }
    })
  }
  columnChange = (values, resolve) => {
    let verify = fromJS(this.state.verify).toJS()
    let fields = verify.columns.map(item => item.field.toLowerCase())
    if (fields.includes(values.field.toLowerCase())) {
      notification.warning({
        top: 92,
        message: '字段已存在!',
        duration: 5
      })
      return
    }
    resolve()
    values.uuid = Utils.getuuid()
    verify.columns.push(values)
    this.setState({verify})
  }
  updatefields = (columns) => {
    let verify = fromJS(this.state.verify).toJS()
    verify.columns = columns
    this.setState({verify})
  }
  render() {
    const { card } = this.props
    const { getFieldDecorator } = this.props.form
    const { verify, linkType, printMode, printFunc } = this.state
    const { verify, linkType, printMode, printFunc, scriptsColumns, dataType, loading, activeKey, usefulfields, colColumns } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -270,10 +680,11 @@
    }
    return (
      <div>
      <div className="verify-card-print-box">
        {card.label ? <div className="mk-com-name">{card.label} - 验证信息</div> : null}
        <Tabs defaultActiveKey="1" className="verify-card-print-box" onChange={this.tabchange}>
          <TabPane tab="打印验证" key="1">
        {loading && <Spin size="large" />}
        <Tabs activeKey={activeKey} onChange={this.tabchange}>
          <TabPane tab="打印验证" key="base">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col span={8}>
@@ -339,6 +750,18 @@
                    })(<Input placeholder="" autoComplete="off" />)}
                  </Form.Item>
                </Col>}
                {card.intertype === 'system' ? <Col span={8}>
                  <Form.Item label="数据类型">
                    {getFieldDecorator('dataType', {
                      initialValue: dataType || 'line'
                    })(
                      <Radio.Group onChange={this.changeDataType}>
                        <Radio value="line">行数据</Radio>
                        <Radio value="custom">自定义</Radio>
                      </Radio.Group>
                    )}
                  </Form.Item>
                </Col> : null}
                {printMode === 'custom' ? <Col span={24}>
                  <Form.Item label={'处理函数'} className="printFunc">
                    {getFieldDecorator('printFunc', {
@@ -433,7 +856,7 @@
                    )}
                  </Form.Item>
                </Col> : null}
                {printMode !== 'custom' ? <Col span={8} offset={printMode === 'RFID' ? 16 : 0}>
                {printMode !== 'custom' ? <Col span={8} offset={16}>
                  <img className="legend" src={this.state.selectimg} alt=""/>
                </Col> : null }
              </Row>
@@ -444,7 +867,7 @@
              打印类型
              {verify.printerTypeList.length ? <span className="count-tip">{verify.printerTypeList.length}</span> : null}
            </span>
          } disabled={printMode === 'RFID'} key="2">
          } disabled={printMode === 'RFID'} key="print">
            <Form {...formItemLayout}>
              <Row gutter={24}>
                <Col span={24} className="print-tip">
@@ -455,12 +878,45 @@
                  </Form.Item>
                </Col>
                <Col span={24}>
                  <EditTable data={verify.printerTypeList} ref="editTable"/>
                  <EditTable data={verify.printerTypeList} onChange={(list) => this.setState({verify: {...verify, printerTypeList: list}})}/>
                </Col>
              </Row>
            </Form>
          </TabPane>
          <TabPane tab="信息提示" key="7">
          {card.intertype === 'system' ? <TabPane tab="数据源" disabled={dataType !== 'custom'} key="setting">
            <DataSource setting={verify.setting || {}} btnType="print" wrappedComponentRef={(inst) => this.settingForm = inst}/>
          </TabPane> : null}
          {card.intertype === 'system' ? <TabPane tab={
            <span>
              字段集
              {verify.columns.length ? <span className="count-tip">{verify.columns.length}</span> : null}
            </span>
          } disabled={dataType !== 'custom'} key="columns">
            <ColForm columnChange={this.columnChange}/>
            <FieldsComponent
              config={verify}
              type="fields"
              updatefield={this.updatefields}
            />
            <EditMTable actions={['edit', 'move', 'copy', 'del', 'clear']} type="datasourcefield" data={verify.columns} columns={colColumns} onChange={(columns) => this.setState({verify: {...verify, columns}})}/>
          </TabPane> : null}
          {card.intertype === 'system' ? <TabPane tab={
            <span>
              自定义脚本
              {verify.scripts.length ? <span className="count-tip">{verify.scripts.length}</span> : null}
            </span>
          } key="scripts" disabled={dataType !== 'custom'} id="mk-exout-script">
            <CustomScript
              btn={card}
              sheet={verify.setting ? verify.setting.tableName : ''}
              searches={[]}
              linefields={usefulfields}
              scriptsChange={this.scriptsChange}
              wrappedComponentRef={(inst) => this.scriptsForm = inst}
            />
            <EditMTable actions={['move']} data={verify.scripts} columns={scriptsColumns} onChange={(scripts) => {this.setState({verify: {...verify, scripts}})}}/>
          </TabPane> : null}
          <TabPane tab="信息提示" key="message">
            <div style={{textAlign: 'center', fontSize: '13px', marginBottom: '10px'}}>打印信息中如果存在网络资源(图片),请确保资源可以正常访问,资源不存在时会报数据异常。</div>
            <Form {...formItemLayout}>
              <Row gutter={24}>
src/templates/sharecomponent/actioncomponent/verifyprint/index.scss
@@ -1,4 +1,5 @@
.verify-card-print-box {
  position: relative;
  .ant-tabs-nav-scroll {
    text-align: center;
  }
@@ -60,6 +61,56 @@
    color: #1890ff;
    font-size: 12px;
  }
  .verify-form {
    .sql {
      .ant-col-sm-8 {
        width: 10.5%;
      }
      .ant-col-sm-16 {
        width: 89.5%;
        padding-top: 4px;
      }
      .CodeMirror {
        height: 350px;
      }
    }
    .sqlfield {
      .ant-form-item {
        margin-bottom: 5px;
      }
      .ant-form-item-control {
        line-height: 24px;
      }
      .ant-form-item-label {
        line-height: 25px;
      }
      .ant-form-item-children {
        line-height: 22px;
      }
      .ant-col-sm-8 {
        width: 10.5%;
      }
      .ant-col-sm-16 {
        width: 89.5%;
      }
    }
    .add {
      padding-top: 4px;
    }
  }
  .ant-spin {
    position: absolute;
    top: calc(50% - 16px);
    left: calc(50% - 16px);
    z-index: 1;
  }
  .quickly-add {
    position: absolute;
    width: 100px;
    right: 24px;
    top: 5px;
    z-index: 2;
  }
}
.print-template-setting {
  .ant-select-dropdown-menu-item {
src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
New file
@@ -0,0 +1,77 @@
export default class SettingUtils {
  static getDebugSql (setting, columns, scripts, declareSql, timestamp) {
    let sql = ''
    let _dataresource = setting.dataresource || ''
    let _customScript = ''
    scripts && scripts.forEach(script => {
      if (script.status === 'false') return
      _customScript += `
      ${script.sql}
      `
    })
    if (_customScript) {
      _customScript = `declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100) select @ErrorCode='',@retmsg =''
        ${declareSql}
        ${_customScript}
      `
    }
    if (setting.defaultSql === 'false') {
      _dataresource = ''
    }
    _dataresource = _dataresource.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
    _customScript = _customScript.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${timestamp}'`)
    _dataresource = _dataresource.replace(/@\$|\$@/ig, '')
    _customScript = _customScript.replace(/@\$|\$@/ig, '')
    // 外联数据库替换
    if (window.GLOB.externalDatabase !== null) {
      _dataresource = _dataresource.replace(/@db@/ig, window.GLOB.externalDatabase)
      _customScript = _customScript.replace(/@db@/ig, window.GLOB.externalDatabase)
    }
    let arr_field = columns.map(col => col.field)
    arr_field = arr_field.join(',')
    if (!arr_field) {
      arr_field = '*'
    }
    // 数据源处理, 存在显示列时
    if (_dataresource) {
      if (/\s/.test(_dataresource)) {
        _dataresource = '(' + _dataresource + ') tb'
      }
      if (setting.order) {
        _dataresource = `/*system_query*/select ${arr_field} from (select ${arr_field} ,ROW_NUMBER() over(order by ${setting.order}) as rows from ${_dataresource}) tmptable order by tmptable.rows`
      } else {
        _dataresource = `/*system_query*/select ${arr_field} from ${_dataresource}`
      }
    }
    if (_customScript) {
      sql = `/* sql 验证 */
        ${_customScript}
        ${_dataresource}
        aaa:
        if @ErrorCode!=''
          insert into tmp_err_retmsg (ID, ErrorCode, retmsg, CreateUserID) select @time_id@,@ErrorCode, @retmsg,@UserID@
      `
    } else {
      sql = `/* sql 验证 */
        declare @ErrorCode nvarchar(50),@retmsg nvarchar(4000),@UserName nvarchar(50),@FullName nvarchar(50),@RoleID nvarchar(512),@mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20),@mk_nation nvarchar(50),@mk_province nvarchar(50),@mk_city nvarchar(50),@mk_district nvarchar(50),@mk_address nvarchar(100) select @ErrorCode='',@retmsg =''
        ${declareSql}
        ${_dataresource}`
    }
    sql = sql.replace(/\n\s{8}/ig, '\n')
    console.info(sql)
    sql = sql.replace(/\n/g, ' ')
    return sql
  }
}
src/templates/sharecomponent/searchcomponent/index.jsx
@@ -160,7 +160,6 @@
    this.searchFormRef.handleConfirm().then(res => {
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      _searchlist = _searchlist.filter(item => !item.origin || item.uuid === res.uuid) // 去除系统项
@@ -188,8 +187,6 @@
          if (setFields.length < itemFields.length + resFields.length && (res.type !== 'date' || item.type !== 'date')) {
            fieldrepet = true
          } else if (item.label === res.label) {
            labelrepet = true
          }
        }
@@ -204,13 +201,6 @@
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 5
        })
        return
      } else if (labelrepet) {
        notification.warning({
          top: 92,
          message: '名称已存在!',
          duration: 5
        })
        return
src/templates/sharecomponent/searchcomponent/index.scss
@@ -26,6 +26,9 @@
    vertical-align: top;
  }
  .mk-search-item-wrap.action {
    .ant-form-item {
      white-space: nowrap;
    }
    .ant-form-item-label, .ant-form-item-control-wrapper {
      display: inline-block;
    }
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -198,7 +198,7 @@
        if (this.record.resourceType === '0') {        // 自定义资源
          shows.push('options', 'fields')
        } else if (this.record.resourceType === '1') { // 数据源
          shows.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database')
          shows.push('dataSource', 'cardValField', 'colorField', 'fields', 'orderBy', 'orderType', 'database')
        }
      } else {
        reRequired.fields = true
@@ -419,7 +419,11 @@
    let resource = this.props.form.getFieldValue('dataSource') || ''
    resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    if (field === text) {
      resource = `select '' as ${field} union all \n${resource}`
    } else {
      resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    }
    this.props.form.setFieldsValue({dataSource: resource})
  }
src/templates/sharecomponent/searchcomponent/settingform/index.jsx
@@ -89,7 +89,7 @@
            <Form.Item label={
              <Tooltip placement="topLeft" title="抽屉展开的方向。">
                <QuestionCircleOutlined className="mk-form-tip" />
                抽屉方向
                弹出方向
              </Tooltip>
            }>
              {getFieldDecorator('drawerPlacement', {
src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
@@ -182,10 +182,9 @@
      if (_loading) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
          message: '存在未保存脚本!',
          duration: 5
        })
        return
      }
      this.setState({loading: true})
src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -363,10 +363,9 @@
    if (this.scriptsForm && this.scriptsForm.props.form.getFieldValue('sql') && !/^\s+$/.test(this.scriptsForm.props.form.getFieldValue('sql'))) {
      notification.warning({
        top: 92,
        message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
        message: '存在未保存的脚本!',
        duration: 5
      })
      return
    }
    if (activeKey === 'setting') {
src/templates/sharecomponent/treesettingcomponent/settingform/index.jsx
@@ -212,10 +212,9 @@
      if (_loading) {
        notification.warning({
          top: 92,
          message: '存在未保存脚本,请点击确定保存,或点击取消放弃修改!',
          message: '存在未保存脚本!',
          duration: 5
        })
        return
      }
      this.setState({loading: true})
      this.sqlverify(() => { // 验证成功
src/templates/zshare/createinterface/index.jsx
@@ -1064,7 +1064,7 @@
    } else if (_actionType === 'LogicDelete') { // 逻辑删除
      _sql += `
        /* 默认sql */
        update ${btn.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifyuserid=@userid@ where ${primaryKey}=@${primaryKey}@;`
        update ${btn.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifystaff=@fullname,modifyuserid=@userid@ where ${primaryKey}=@${primaryKey}@;`
      
    } else if (_actionType === 'delete') {      // 物理删除
      let _msg = ''
src/templates/zshare/editTable/index.scss
@@ -13,6 +13,9 @@
    .ant-select {
      width: 100%;
    }
    span.ant-radio + * {
      padding-left: 2px;
    }
    > td {
      padding: 14px 10px;
    }
src/templates/zshare/editcomponent/index.jsx
@@ -119,6 +119,9 @@
    let _config = fromJS(this.props.config).toJS()
    this.pasteFormRef.handleConfirm().then(res => {
      if (type === 'formboard' && res.copyType === 'search' && ['text', 'select', 'multiselect', 'link', 'checkcard', 'date', 'datemonth'].includes(res.type)) {
        res.copyType = 'form'
      }
      if (!options.includes(res.copyType)) {
        notification.warning({
          top: 92,
src/templates/zshare/formconfig.jsx
@@ -489,6 +489,13 @@
      required: true
    },
    {
      type: 'text',
      key: 'colorField',
      label: '色值字段',
      initVal: card.colorField || '',
      required: true
    },
    {
      type: 'radio',
      key: 'picratio',
      label: '图片比例',
@@ -1440,7 +1447,7 @@
    {
      type: 'radio',
      key: 'placement',
      label: '抽屉方向',
      label: '弹出方向',
      initVal: card.placement || 'right',
      required: false,
      options: [{
@@ -2693,6 +2700,13 @@
      readonly: false
    },
    {
      type: 'text',
      key: 'colorField',
      label: '色值字段',
      initVal: card.colorField || '',
      required: true
    },
    {
      type: 'radio',
      key: 'picratio',
      label: '图片比例',
@@ -3203,6 +3217,19 @@
    },
    {
      type: 'radio',
      key: 'colorType',
      label: '颜色类型',
      initVal: card.colorType || 'hex',
      options: [{
        value: 'hex',
        text: '16进制'
      }, {
        value: 'rgba',
        text: 'RGBA'
      }]
    },
    {
      type: 'radio',
      key: 'allowHalf',
      label: '半选',
      initVal: card.allowHalf || 'false',
@@ -3671,7 +3698,7 @@
      key: 'regularExtra',
      label: '正则扩展符',
      initVal: card.regularExtra || '',
      tooltip: '正则验证时的自定义字符,包括~!@#$%^&*()_+:;{}<>,.-',
      tooltip: '正则验证时允许添加的自定义字符,包括~!@#$%^&*()_+:;{}<>,.-',
      required: false,
      readonly: false
    },
src/templates/zshare/modalform/datatable/index.jsx
@@ -201,6 +201,17 @@
          return <span style={{display: 'block', width: '70px', height: '70px'}}><img style={{width: '100%', height: '100%'}} src={text} alt="" /></span>
        }
      })
    } else if (display === 'color') {
      columns.push({
        title: 'Color',
        dataIndex: '$color',
        inputType: 'text',
        editable: true,
        render: (text) => {
          if (!text) return ''
          return <div style={{height: '20px', background: text}}></div>
        }
      })
    }
    fields.forEach(item => {
@@ -371,6 +382,8 @@
    if (display === 'picture') {
      item.$url = ''
    } else if (display === 'color') {
      item.$color = ''
    }
    fields.forEach(f => {
src/templates/zshare/modalform/index.jsx
@@ -34,7 +34,7 @@
  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'marginTop', 'marginBottom', 'minDate', 'maxDate'],
  textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra', 'count', 'placeholder', 'marginTop', 'marginBottom'],
  cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom', 'separator'],
  color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'marginTop', 'marginBottom'],
  color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'colorType', 'extra', 'marginTop', 'marginBottom'],
  rate: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'splitline', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'allowHalf', 'color', 'rateCount', 'character', 'place'],
  hint: ['label', 'field', 'type', 'blacklist', 'message', 'span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
  split: ['label', 'type', 'marginTop', 'marginBottom', 'splitline'],
@@ -193,7 +193,7 @@
        if (this.record.resourceType === '0') {        // 自定义资源
          shows.push('options', 'fields')
        } else if (this.record.resourceType === '1') { // 数据源
          shows.push('dataSource', 'cardValField', 'fields', 'orderBy', 'orderType', 'database')
          shows.push('dataSource', 'cardValField', 'colorField', 'fields', 'orderBy', 'orderType', 'database')
        }
      } else {
        reRequired.fields = true
@@ -560,7 +560,11 @@
    let resource = this.props.form.getFieldValue('dataSource') || ''
    resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    if (field === text) {
      resource = `select '' as ${field} union all \n${resource}`
    } else {
      resource = `select '' as ${field},'全部' as ${text} union all \n${resource}`
    }
    this.props.form.setFieldsValue({dataSource: resource})
  }
src/templates/zshare/verifycard/index.jsx
@@ -626,7 +626,7 @@
          _fields.push(...group.sublist)
        })
        resolve(_fields)
      } else if (card.modal) {
      } else if (card.modal && (card.OpenType === 'pop' || !card.OpenType)) {
        _fields = card.modal.fields || []
        resolve(_fields)
      } else if (card.OpenType === 'pop') {
@@ -840,10 +840,10 @@
        let _arr = []
        _fields.forEach(item => {
          if (!item.field || item.writein === 'false') return
          if (!item.field || item.writein === 'false' || item.uuid === 'BID') return
          _arr.push(item.field.toLowerCase())
          if (item.field.toLowerCase() === 'bid' && item.uuid === 'BID') {
          if (item.field.toLowerCase() === 'bid') {
            _form.push(item.field + '=@BID@')
          } else {
            _form.push(item.field + '=@' + item.field)
@@ -921,10 +921,10 @@
        if (_verify.voucher && _verify.voucher.enabled) {
          _voucher = ',BVoucher=@BVoucher,FIBVoucherDate=@FIBVoucherDate,FiYear=@FiYear'
        }
        _defaultsql = `update ${card.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifyuserid=@userid@${_voucher} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
        _defaultsql = `update ${card.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifystaff=@fullname,modifyuserid=@userid@${_voucher} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
      } else if (card.sqlType === 'delete') {
        let _msg = ''
        if (columns && columns.length > 0 && card.Ot !== 'notRequired' && card.Ot !== 'requiredOnce') {
        if (columns && columns.length > 0 && card.Ot !== 'notRequired') {
          let _index = 0
          columns.forEach(col => {
            if (!col.field || col.Hide === 'true' || _index >= 4) return
src/utils/utils-custom.js
@@ -896,7 +896,7 @@
export function getTables (config, pops) {
  let tables = []
  let cuts = []
  let cutreg = /(from|update|insert\s+into)\s+(@db@)?[a-z_]+/ig
  let cutreg = /(from|update|insert\s+into)\s+(@db@)?[a-z0-9_]+/ig
  let trimreg = /(from|update|insert\s+into)\s+(@db@)?/ig
  if (config.setting && (!config.wrap || !config.wrap.datatype || config.wrap.datatype === 'dynamic')) {
@@ -943,6 +943,8 @@
        if (cell.eleType !== 'button') return
        if (['form', 'pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(cell.OpenType)) {
          action.push(cell)
        } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) {
          action.push(cell)
        } else if (cell.OpenType === 'popview') {
          if (pops) {
            pops.push({...cell, parentId: config.uuid})
@@ -956,6 +958,8 @@
        item.backElements.forEach(cell => {
          if (cell.eleType !== 'button') return
          if (['form', 'pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(cell.OpenType)) {
            action.push(cell)
          } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) {
            action.push(cell)
          } else if (cell.OpenType === 'popview') {
            if (pops) {
@@ -974,6 +978,8 @@
      col.elements.forEach(cell => {
        if (['form', 'pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(cell.OpenType)) {
          action.push(cell)
        } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) {
          action.push(cell)
        } else if (cell.OpenType === 'popview') {
          if (pops) {
            pops.push({...cell, parentId: config.uuid})
@@ -989,6 +995,8 @@
    if (cell.eleType !== 'button') return
    if (['form', 'pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(cell.OpenType)) {
      action.push(cell)
    } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) {
      action.push(cell)
    } else if (cell.OpenType === 'popview') {
      if (pops) {
        pops.push({...cell, parentId: config.uuid})
@@ -1000,6 +1008,8 @@
  config.action && config.action.forEach(cell => {
    if (['pop', 'prompt', 'exec', 'excelIn', 'excelOut'].includes(cell.OpenType)) {
      action.push(cell)
    } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print' && cell.verify) {
      action.push(cell)
    } else if (cell.OpenType === 'popview') {
      if (pops) {
@@ -1021,6 +1031,19 @@
      }
      if (btn.intertype === 'system' && btn.verify.scripts) {
        btn.verify.scripts.forEach(script => {
          if (script.status === 'false') return
          let tbs = script.sql.match(cutreg)
          tbs && cuts.push(...tbs)
        })
      }
    } else if (btn.OpenType === 'funcbutton') {
      if (btn.intertype !== 'system' || !btn.verify || !btn.verify.setting) return
      if (btn.verify.dataType === 'custom') {
        if (btn.verify.setting.defaultSql !== 'false') {
          let tbs = btn.verify.setting.dataresource.match(cutreg)
          tbs && cuts.push(...tbs)
        }
        btn.verify.scripts && btn.verify.scripts.forEach(script => {
          if (script.status === 'false') return
          let tbs = script.sql.match(cutreg)
          tbs && cuts.push(...tbs)
@@ -1102,7 +1125,7 @@
  cuts = cuts.map(item => item.replace(trimreg, ''))
  tables.push(...cuts)
  tables = tables.filter(Boolean)
  tables = tables.filter(tb => tb && tb !== 'dbo' && tb.length > 1)
  tables = Array.from(new Set(tables))
  return tables
src/utils/utils-datamanage.js
@@ -733,7 +733,7 @@
 * @description 生成单个组件sPC_Get_structured_data请求参数
 */
export function getStructDefaultParam (component, searchlist, first) {
  const { columns, setting, dataName, format } = component
  const { columns, setting, dataName, format, uuid } = component
  let arr_field = columns.map(col => col.field)
  let _dataresource = setting.dataresource
@@ -799,6 +799,7 @@
  }
  return {
    uuid: uuid,
    name: dataName,
    $name: setting.$name,
    columns: columns,
src/utils/utils.js
@@ -783,6 +783,8 @@
      arrfield.push(item.cardValField)
      if (item.urlField) {
        arrfield.push(item.urlField)
      } else if (item.colorField) {
        arrfield.push(item.colorField)
      }
    }
@@ -842,7 +844,7 @@
 * @return {Object} dict   字典项
 * @return {String} BID    上级Id
 */
export function getExcelInSql (item, data, dict, BID) {
export function getExcelInSql (item, data, dict, BID, primaryId) {
  let btn = item.verify
  let keys = ['delete', 'drop', 'insert', 'truncate', 'update']
  let userName = sessionStorage.getItem('User_Name') || ''
@@ -895,20 +897,30 @@
    btn.scripts.forEach(script => {
      if (script.status === 'false') return
      let _sql = script.sql
      _sql = _sql.replace(/@ID@/ig, `'${primaryId || ''}'`)
      _sql = _sql.replace(/@BID@/ig, `'${BID}'`)
      _sql = _sql.replace(/@LoginUID@/ig, `'${sessionStorage.getItem('LoginUID') || ''}'`)
      _sql = _sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
      _sql = _sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
      _sql = _sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
      _sql = _sql.replace(/@typename@/ig, `'admin'`)
      if (script.position === 'init') {
        _initCustomScript += `
      /* 自定义脚本 */
      ${script.sql}
      ${_sql}
      `
      } else if (script.position === 'front') {
        _prevCustomScript += `
      /* 自定义脚本 */
      ${script.sql}
      ${_sql}
      `
      } else {
        _backCustomScript += `
      /* 自定义脚本 */
      ${script.sql}
      ${_sql}
      `
      }
    })
@@ -1485,7 +1497,7 @@
  }
  // 添加数据中字段,表单值优先(按钮不选行或多行拼接时跳过)
  if (data && btn.Ot !== 'notRequired' && btn.Ot !== 'requiredOnce' && columns && columns.length > 0) {
  if (data && btn.Ot !== 'notRequired' && columns && columns.length > 0) {
    datavars = {...data, ...datavars}
    const setField = (col) => {
@@ -2040,17 +2052,16 @@
    _sql += `
      /* 默认sql */
      update ${btn.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifyuserid=@userid@ where ${primaryKey}${_ID};`
      update ${btn.sql} set deleted=1,modifydate=getdate(),modifyuser=@username,modifystaff=@fullname,modifyuserid=@userid@ where ${primaryKey}${_ID};`
  
  } else if (_actionType === 'delete') {      // 物理删除
    let _msg = ''
    if (data && columns && columns.length > 0) {
    if (data && columns && columns.length > 0 && btn.Ot !== 'notRequired') {
      let _index = 0
      columns.forEach(col => {
        if (col.Hide !== 'true' && col.type !== 'colspan' && col.type !== 'old_colspan' && _index < 4) {
          _msg += col.label + '=' + data[col.field] + ','
          _index++
        }
        if (!col.field || col.Hide === 'true' || _index >= 4) return
        _msg += col.label + '=' + data[col.field] + ','
        _index++
      })
    }
@@ -2147,6 +2158,7 @@
  let icon = null
  let innerStyle = null
  let position = null
  let signType = ''
  style = JSON.parse(JSON.stringify(style))
  marks.some(mark => {
@@ -2184,6 +2196,7 @@
    if (type === 'font') {
      style.color = mark.color
      innerStyle = {color: mark.color}
      signType = ' sign-font'
    } else if (type === 'background') {
      style.backgroundColor = mark.color
      if (mark.fontColor) {
@@ -2215,7 +2228,8 @@
    style,
    icon,
    innerStyle,
    position
    position,
    signType
  }
}
@@ -2566,9 +2580,9 @@
        @ErrorSeverity=ERROR_SEVERITY(),
        @ErrorState=ERROR_STATE();
        
      RAISERROR(@ErrorMessage, /*-- Message text.*/
        @ErrorSeverity, /*-- Severity.*/
        @ErrorState  /*-- State.*/
      RAISERROR(@ErrorMessage, /* Message text.*/
        @ErrorSeverity, /* Severity.*/
        @ErrorState  /* State.*/
      );
    END CATCH
    
@@ -2707,9 +2721,9 @@
        @ErrorSeverity=ERROR_SEVERITY(),
        @ErrorState=ERROR_STATE();
        
      RAISERROR(@ErrorMessage, /*-- Message text.*/
        @ErrorSeverity, /*-- Severity.*/
        @ErrorState  /*-- State.*/
      RAISERROR(@ErrorMessage, /* Message text.*/
        @ErrorSeverity, /* Severity.*/
        @ErrorState  /* State.*/
      );
    END CATCH
    
src/views/appcheck/index.jsx
@@ -27,7 +27,8 @@
  bg_black_style_purple: {name: '紫色', color: '#722ed1'},
  bg_black_style_magenta: {name: '洋红色', color: '#eb2f96'},
  bg_black_style_grass_green: {name: '草绿色', color: '#aeb303'},
  bg_black_style_deep_red: {name: '深红色', color: '#c32539'}
  bg_black_style_deep_red: {name: '深红色', color: '#c32539'},
  bg_black_style_deep_blue: {name: '深红色', color: '#1d3661'}
}
class AppCheck extends Component {
src/views/appmanage/index.jsx
@@ -39,7 +39,8 @@
  bg_black_style_purple: {name: '紫色', color: '#722ed1'},
  bg_black_style_magenta: {name: '洋红色', color: '#eb2f96'},
  bg_black_style_grass_green: {name: '草绿色', color: '#aeb303'},
  bg_black_style_deep_red: {name: '深红色', color: '#c32539'}
  bg_black_style_deep_red: {name: '深红色', color: '#c32539'},
  bg_black_style_deep_blue: {name: '深红色', color: '#1d3661'}
}
class AppManage extends Component {
@@ -466,6 +467,7 @@
              cell.delay = _param.delay || 0
              cell.statusBarColor = _param.statusBarColor || 'black'
              cell.sysBgColor = _param.sysBgColor || '#ffffff'
              cell.direction = _param.direction || 'vertical'
              cell.adapter = _param.adapter || ''
              cell.share = _param.share || 'false' // 分享
              cell.share_des = _param.share_des || '' // 分享描述
@@ -650,7 +652,7 @@
    })
    // 子应用ID、typename、应用ID、CloudUserID、appkey、login_types(是否需要登录,已弃用)、link_type(是否使用短连接,已弃用)、role_type(是否使用角色管理)、lang、css(皮肤)、title(标题)、favicon(图标)、user_binding(用户绑定)、sms_id(短信模板ID)、自定义
    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
    param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
    param.LText = param.LText.join(' union all ')
    param.LText = Utils.formatOptions(param.LText)
    
@@ -896,7 +898,7 @@
          return item
        })
        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
        param.LText = selectApp.sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
        param.LText = param.LText.join(' union all ')
        param.LText = Utils.formatOptions(param.LText)
      }
@@ -989,7 +991,7 @@
        return item
      })
      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
      param.LText = sublist.map(item => `select '${item.ID}','${item.typename}','${selectApp.ID}','${sessionStorage.getItem('CloudUserID') || ''}','${window.GLOB.appkey || ''}','false','false','${item.role_type || 'true'}','${item.lang || 'zh-CN'}','${item.css || ''}','${item.title || ''}','${item.favicon || ''}','${item.user_binding || 'false'}','','${window.btoa(window.encodeURIComponent(JSON.stringify({userbind: item.userbind || '', instantMessage: item.instantMessage || '', apptype: item.apptype || '', delay: item.delay || 0, statusBarColor: item.statusBarColor || 'black', sysBgColor: item.sysBgColor || '#ffffff', direction: item.direction || 'vertical', adapter: item.adapter || '', share: item.share || '', share_des: item.share_des || '', share_url: item.share_url || '', share_link: item.share_link || ''})))}'`)
      param.LText = param.LText.join(' union all ')
      param.LText = Utils.formatOptions(param.LText)
src/views/appmanage/submutilform/index.jsx
@@ -152,6 +152,7 @@
                  <Select.Option value="bg_black_style_magenta"><span className="color-block" style={{background: '#eb2f96'}}></span>洋红色(#eb2f96)</Select.Option>
                  <Select.Option value="bg_black_style_grass_green"><span className="color-block" style={{background: '#aeb303'}}></span>草绿色(#aeb303)</Select.Option>
                  <Select.Option value="bg_black_style_deep_red"><span className="color-block" style={{background: '#c32539'}}></span>深红色(#c32539)</Select.Option>
                  <Select.Option value="bg_black_style_deep_blue"><span className="color-block" style={{background: '#1d3661'}}></span>深蓝色(#1d3661)</Select.Option>
                </Select>
              )}
            </Form.Item>
@@ -295,7 +296,7 @@
            <Form.Item label={
              <Tooltip placement="topLeft" title="在使用明科云APP时,状态栏的字体颜色。">
                <QuestionCircleOutlined className="mk-form-tip" />
                状态栏
                状态栏文字
              </Tooltip>
            }>
              {getFieldDecorator('statusBarColor', {
@@ -322,6 +323,23 @@
              )}
            </Form.Item>
          </Col>
          {typename === 'pad' ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="系统默认屏幕方向,单个页面方向请在页面中配置。">
                <QuestionCircleOutlined className="mk-form-tip" />
                屏幕方向
              </Tooltip>
            }>
              {getFieldDecorator('direction', {
                initialValue: card ? card.direction || 'vertical' : 'vertical'
              })(
                <Radio.Group>
                  <Radio value="vertical">竖屏</Radio>
                  <Radio value="horizontal">横屏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
        </Row>
      </Form>
    )
src/views/design/index.jsx
@@ -23,7 +23,7 @@
  
  render () {
    return (
      <div className="mk-main-view mk-design-view">
      <div className="mk-main-view">
        <ConfigProvider locale={_locale}>
          <Sidemenu key="sidemenu"/>
          <Header key="header"/>
src/views/design/index.scss
@@ -1,24 +1,6 @@
.mk-main-view {
  display: flex;
  flex: auto;
  min-height: 100%;
  .mk-save-menu[disabled] {
    background: #ffffff!important;
  }
}
.mk-design-view {
  #mk-tabview-wrap {
    z-index: unset;
    >.content-header {
      >.ant-tabs {
        z-index: 21;
        background: #ffffff;
      }
    }
  }
  #mk-tabview-wrap.hastab + .sys-header-container .app-prod-entrance {
    display: none;
  }
}
.mk-popover-control-wrap {
src/views/design/sidemenu/index.scss
@@ -1,4 +1,4 @@
@import '../../../assets/css/iconfont.css';
// @import '../../../assets/css/iconfont.css';
.mk-sys-side-menu {
  flex: 0 0 235px;
src/views/login/index.jsx
@@ -84,11 +84,8 @@
   * @param {Object} param 用户名密码等信息
   */
  async loginsubmit (param) {
    let city = sessionStorage.getItem('city') || ''
    let ipAddress = sessionStorage.getItem('ipAddress') || ''
    // 登录提交
    let res = await Api.getusermsg(param.username, param.password, false, ipAddress, city)
    let res = await Api.getusermsg(param.username, param.password, false)
    if (res.status) {
      if (res.check_mob) {
        let loginWays = this.state.loginWays.filter(item => item.type === 'sms_vcode')
@@ -201,11 +198,8 @@
  }
  async phoneloginsubmit (param) {
    let city = sessionStorage.getItem('city') || ''
    let ipAddress = sessionStorage.getItem('ipAddress') || ''
    // 登录提交
    let res = await Api.getphoneusermsg(param.phone, param.vercode, false, ipAddress, city)
    let res = await Api.getphoneusermsg(param.phone, param.vercode, false)
    if (res.status) {
      sessionStorage.setItem('UserID', res.UserID)
      sessionStorage.setItem('LoginUID', res.LoginUID)
@@ -332,6 +326,10 @@
    //   if (!res || !res.ip) return
    //   sessionStorage.setItem('ipAddress', res.ip)
    // })
    setTimeout(() => {
      Api.delCacheConfig()
    }, 50)
    if (window.GLOB.filter) {
      let view = document.getElementById('mk-login-view')
      
@@ -605,7 +603,7 @@
            let level = res.pwd_level || ''
            if (level && !['letter_num', 'char_num', 'char_num_90'].includes(level)) {
            if (level && !['letter_num', 'char_num', 'char_num_90', 'char_num_90_sms'].includes(level)) {
              level = ''
            }
src/views/login/index.scss
@@ -2,6 +2,7 @@
  position: relative;
  height: 100vh;
  min-height: 600px;
  background-color: var(--mk-sys-background);
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center center;
@@ -9,13 +10,14 @@
    position: relative;
    height: 100px;
    padding-top: 30px;
    border-bottom: 3px solid #aeb303;
    line-height: 80px;
    border-bottom: 2px solid var(--mk-sys-color);
    img {
      height: 50px;
    }
    .plat-name {
      position: absolute;
      color: #ffffff;
      color: var(--mk-sys-font-color);
      line-height: 30px;
      font-size: 30px;
      font-weight: 600;
@@ -33,6 +35,22 @@
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center center;
    border-bottom: 2px solid var(--mk-sys-color);
    .login-form-button {
      background-color: var(--mk-sys-color);
      border-color: var(--mk-sys-color);
    }
    .login-form-button[disabled] {
      background-color: var(--mk-sys-color5);
      border-color: var(--mk-sys-color5);
    }
    .login-way-wrap {
      .login-way.active, .login-way:hover {
        color: var(--mk-sys-color);
      }
    }
    .login-form {
      position: relative;
@@ -173,6 +191,7 @@
      }
      button.vercode {
        border: 0;
        color: var(--mk-sys-color);
      }
      button:not(.vercode) {
        width: 100%;
@@ -205,7 +224,7 @@
        font-size: 18px;
      }
      .anticon-eye {
        color: #aeb303;
        color: var(--mk-sys-color);
      }
    }
    .login-sync-button {
@@ -220,6 +239,7 @@
    left: 0;
    width: 100%;
    text-align: center;
    color: var(--mk-sys-font-color);
    padding-top: 20px;
    font: 12px/150% Arial,Verdana,"\5b8b\4f53";
    p span.split {
@@ -228,7 +248,7 @@
    a {
      display: inline-block;
      margin-bottom: 5px;
      font: 12px/150% Arial,Verdana,"\5b8b\4f53";
      color: var(--mk-sys-font-color);
    }
  }
  .ant-btn-primary[disabled] {
src/views/main/index.jsx
@@ -10,7 +10,7 @@
import QueryLog from '@/components/querylog'
import ImgScale from '@/components/imgScale'
import './index.scss'
// import './index.scss'
const Tabview = asyncComponent(() => import('@/components/tabview'))
const Breadview = asyncComponent(() => import('@/components/breadview'))
src/views/main/index.scss
@@ -1,5 +0,0 @@
.mk-main-view {
  display: flex;
  flex: auto;
  min-height: 100%;
}
src/views/menudesign/homeform/index.jsx
@@ -103,6 +103,8 @@
      this.props.updateConfig({...config, cacheUseful: value})
    } else if (key === 'timeUnit') {
      this.props.updateConfig({...config, timeUnit: value})
    } else if (key === 'cacheLocal') {
      this.props.updateConfig({...config, cacheLocal: value})
    }
  }
@@ -132,9 +134,26 @@
        <Row>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                缓存数据
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
src/views/menudesign/index.jsx
@@ -1043,7 +1043,8 @@
      }
      let subforbid = {
        editable: '可编辑表格',
        voucher: '凭证'
        voucher: '凭证',
        account: '账套'
      }
      config.components.forEach(item => {
src/views/menudesign/menuform/index.jsx
@@ -205,6 +205,8 @@
      this.props.updateConfig({...config, hidden: value})
    } else if (key === 'permission') {
      this.props.updateConfig({...config, permission: value})
    } else if (key === 'cacheLocal') {
      this.props.updateConfig({...config, cacheLocal: value})
    }
  }
@@ -340,9 +342,26 @@
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                缓存数据
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
src/views/menudesign/popview/menuform/index.jsx
@@ -25,6 +25,8 @@
      this.props.updateConfig({...config, cacheUseful: value})
    } else if (key === 'timeUnit') {
      this.props.updateConfig({...config, timeUnit: value})
    } else if (key === 'cacheLocal') {
      this.props.updateConfig({...config, cacheLocal: value})
    }
  }
@@ -47,9 +49,26 @@
        <Row>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                缓存数据
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
src/views/mobdesign/index.jsx
@@ -45,6 +45,7 @@
const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller'))
const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
const PopView = asyncComponent(() => import('./popview'))
sessionStorage.setItem('isEditState', 'true')
sessionStorage.setItem('editMenuType', 'menu') // 编辑菜单类型
@@ -68,12 +69,12 @@
    menuloading: false,
    oriConfig: null,
    config: null,
    direction: 'vertical',
    settingshow: true,
    controlshow: true,
    comloading: false,
    adapters: [],
    viewType: 'menu',
    view: '',
    eyeopen: false,
    needUpdate: false
  }
@@ -91,6 +92,7 @@
        sessionStorage.setItem('typename', param.typename || 'mob')
        sessionStorage.setItem('adapter', param.adapter || '')
        sessionStorage.setItem('sysBgColor', param.sysBgColor || '#ffffff')
        sessionStorage.setItem('direction', param.direction || 'vertical')
        sessionStorage.setItem('userbind', param.userbind || '')
        sessionStorage.setItem('instantMessage', param.instantMessage || '')
@@ -100,13 +102,6 @@
        window.GLOB.winHeight = 738
        window.GLOB.shellWidth = 376
        window.GLOB.shellHeight = 680
        if (sessionStorage.getItem('typename') === 'pad') {
          window.GLOB.winWidth = 736
          window.GLOB.winHeight = 945
          window.GLOB.shellWidth = 640
          window.GLOB.shellHeight = 853
        }
        let adapters = sessionStorage.getItem('adapter')
        if (adapters) {
@@ -147,6 +142,7 @@
      document.getElementById('mk-mob-design-view').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh; height: 100vh; background: #fff;">本应用没有PC端页面的编辑权限,请联系管理员!</div>'
      return
    }
    MKEmitter.addListener('changePopview', this.initPopview)
    MKEmitter.addListener('triggerMenuSave', this.submitConfig)
    MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
    setTimeout(() => {
@@ -217,8 +213,129 @@
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('changePopview', this.initPopview)
    MKEmitter.removeListener('triggerMenuSave', this.submitConfig)
    MKEmitter.removeListener('changeEditMenu', this.changeEditMenu)
  }
  initPopview = (card, btn) => {
    const { config } = this.state
    if (!this.checkBase()) {
      return
    }
    let _btn = fromJS(btn).toJS()
    if (_btn.config) {
      _btn.config.uuid = _btn.uuid
      _btn.config.MenuID = _btn.uuid
      _btn.config.ParentId = card.uuid
      _btn.config.MenuName = _btn.label
    } else {
      _btn.config = {
        uuid: _btn.uuid,
        MenuID: _btn.uuid,
        ParentId: card.uuid,
        enabled: false,
        MenuName: _btn.label,
        tables: config.tables || [],
        Template: 'CustomPage',
        components: [],
        viewType: 'popview',
        style: { backgroundColor: '#ffffff', backgroundImage: '', paddingTop: '16px', paddingBottom: '40px', paddingLeft: '16px', paddingRight: '16px' }
      }
    }
    this.setState({view: 'popview', popConfig: _btn})
  }
  closePop = () => {
    const {config} = this.state
    sessionStorage.setItem('editMenuType', 'menu')
    window.GLOB.urlFields = config.urlFields || []
    window.GLOB.customMenu = config
    this.setState({view: '', popConfig: null})
  }
  submitPopConfig = (btnconfig) => {
    let parents = {[btnconfig.ParentId]: true}
    let popbtns = {[btnconfig.uuid]: fromJS(btnconfig).toJS()}
    let config = fromJS(this.state.config).toJS()
    config.components = this.setPopView(config.components, parents, popbtns)
    this.setState({ config }, () => {
      this.submitConfig()
    })
  }
  setPopView = (components, parents, popbtns) => {
    return components.map(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          tab.components = this.setPopView(tab.components, parents, popbtns)
        })
      } else if (item.type === 'group') {
        item.components = this.setPopView(item.components, parents, popbtns)
      } else if (parents[item.uuid]) {
        this.setpopConfig(item, popbtns)
      }
      return item
    })
  }
  setpopConfig = (config, popbtns) => {
    config.subcards && config.subcards.forEach(item => {
      item.elements.forEach(cell => {
        if (cell.eleType !== 'button') return
        if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
          cell.config = popbtns[cell.uuid]
        }
      })
    })
    config.cols && config.cols.forEach(col => {
      if (col.type === 'action') {
        col.elements.forEach(cell => {
          if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
            cell.config = popbtns[cell.uuid]
          }
        })
      }
    })
    config.elements && config.elements.forEach(cell => {
      if (cell.eleType !== 'button') return
      if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
        cell.config = popbtns[cell.uuid]
      }
    })
    config.action && config.action.forEach(cell => {
      if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
        cell.config = popbtns[cell.uuid]
      }
    })
    config.$tables = getTables(config)
  }
  checkBase = () => {
    const { config } = this.state
    if (!config.MenuName || !config.MenuNo) {
      notification.warning({
        top: 92,
        message: '请完善菜单基本信息!',
        duration: 5
      })
      return false
    }
    return true
  }
  getSmStemp = () => {
@@ -498,7 +615,22 @@
        config.uuid = MenuId
        config.MenuID = MenuId
        config.open_edition = result.open_edition || ''
        config.direction = config.direction || sessionStorage.getItem('direction') || 'vertical'
        window.GLOB.urlFields = config.urlFields || []
        if (sessionStorage.getItem('typename') === 'pad') {
          if (config.direction !== 'vertical') {
            window.GLOB.winWidth = 992
            window.GLOB.winHeight = 690
            window.GLOB.shellWidth = 853
            window.GLOB.shellHeight = 640
          } else {
            window.GLOB.winWidth = 736
            window.GLOB.winHeight = 945
            window.GLOB.shellWidth = 640
            window.GLOB.shellHeight = 853
          }
        }
        if (config.version !== 2.0) {
          config.components = this.collectTB(config.components)
@@ -739,6 +871,21 @@
      config.MenuName = urlParam.MenuName || ''
      // config.MenuNo = urlParam.MenuNo || ''
      config.MenuNo = ''
      config.direction = config.direction || sessionStorage.getItem('direction') || 'vertical'
      if (sessionStorage.getItem('typename') === 'pad') {
        if (config.direction !== 'vertical') {
          window.GLOB.winWidth = 992
          window.GLOB.winHeight = 690
          window.GLOB.shellWidth = 853
          window.GLOB.shellHeight = 640
        } else {
          window.GLOB.winWidth = 736
          window.GLOB.winHeight = 945
          window.GLOB.shellWidth = 640
          window.GLOB.shellHeight = 853
        }
      }
      let navItem = null
      config.components.forEach(item => {
@@ -1809,6 +1956,8 @@
  }
  changeView = (val) => {
    if (sessionStorage.getItem('typename') !== 'pad') return
    if (val !== 'vertical') {
      window.GLOB.winWidth = 992
      window.GLOB.winHeight = 690
@@ -1822,7 +1971,6 @@
    }
    this.setState({
      direction: val,
      comloading: true
    }, () => {
      this.setState({ comloading: false })
@@ -1844,15 +1992,15 @@
  render () {
    const { viewType, comloading, loading, settingshow, controlshow, activeKey, MenuId, config, menuloading, adapters, eyeopen, needUpdate } = this.state
    const { view, viewType, comloading, loading, settingshow, controlshow, activeKey, MenuId, config, menuloading, adapters, eyeopen, needUpdate } = this.state
    return (
      <ConfigProvider locale={antdZhCN}>
        <div className={'mk-mob-view ' + viewType} id="mk-mob-design-view">
          <Header changeView={this.changeView}/>
          <Header/>
          {loading ? <Spin className="view-spin" size="large" /> : null}
          <DndProvider backend={HTML5Backend}>
            <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
            {view !== 'popview' ? <><div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
              <div className="draw">
                {settingshow ? <DoubleLeftOutlined onClick={() => {this.setState({settingshow: false})}} /> : null}
                {!settingshow ? <DoubleRightOutlined onClick={() => {this.setState({settingshow: true})}} /> : null}
@@ -1866,12 +2014,18 @@
                      config={config}
                      MenuId={MenuId}
                      adapters={adapters}
                      updateConfig={this.updateConfig}
                      updateConfig={(con) => {
                        this.updateConfig(con)
                        if (con.direction !== config.direction) {
                          this.changeView(con.direction)
                        }
                      }}
                    /> : null}
                    {config ? <UrlFieldComponent config={config} updateConfig={this.updateConfig}/> : null}
                    {/* 表名添加 */}
                    {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null}
                    {config ? <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>菜单ID</Paragraph> : null}
                    {config ? <Paragraph style={{padding: '10px 0px 0px 18px'}} copyable={{ text:  `${window.GLOB.baseurl}mob/index.html#/index/${sessionStorage.getItem('kei_no')}/${sessionStorage.getItem('typename')}/${sessionStorage.getItem('lang')}/${MenuId}/@BID@` }}>菜单链接</Paragraph> : null}
                  </Panel>
                  {/* 组件添加 */}
                  <Panel header="组件" className="component" key="component">
@@ -1917,7 +2071,7 @@
              {config && !comloading ? <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
                <MobShell menu={config} handleList={this.updateConfig} />
              </div> : null}
            </div>
            </div></> : <PopView btn={this.state.popConfig} save={this.submitPopConfig} cancel={this.closePop}/>}
          </DndProvider>
          <StyleController />
          <StyleCombController />
src/views/mobdesign/index.scss
@@ -276,6 +276,12 @@
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .card-button-cell {
    .ant-checkbox-inner {
      width: 20px;
      height: 20px;
    }
  }
}
.mk-mob-view.userbind {
src/views/mobdesign/menuform/index.jsx
@@ -97,9 +97,26 @@
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                缓存数据
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
@@ -185,6 +202,18 @@
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label="屏幕方向">
              {getFieldDecorator('direction', {
                initialValue: config.direction || 'vertical'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('direction', e.target.value)}}>
                  <Radio value="vertical">竖屏</Radio>
                  <Radio value="horizontal">横屏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          {adapters.includes('app') || adapters.includes('wxmini') ? <Col span={24}>
            <Form.Item className="status-bar" label={
              <Tooltip placement="topLeft" title="在明科云APP或小程序中,状态栏的背景色。">
src/views/mobdesign/popview/index.jsx
New file
@@ -0,0 +1,306 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import PropTypes from 'prop-types'
import { notification, Modal, Collapse, Switch, Button } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'
import MKEmitter from '@/utils/events.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
const MenuForm = asyncComponent(() => import('./menuform'))
const MobShell = asyncComponent(() => import('@/mob/mobshell'))
const SourceWrap = asyncComponent(() => import('@/mob/modulesource'))
const Modulecell = asyncComponent(() => import('@/menu/modulecell'))
const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
class PopViewDesign extends Component {
  static propTpyes = {
    btn: PropTypes.object,
    save: PropTypes.func,
    cancel: PropTypes.func
  }
  state = {
    menuloading: false,
    oriConfig: null,
    config: null,
    comloading: false,
    settingshow: true,
    controlshow: true,
    eyeopen: false
  }
  UNSAFE_componentWillMount() {
    const { btn } = this.props
    sessionStorage.setItem('editMenuType', 'popview')
    let config = fromJS(btn.config).toJS()
    window.GLOB.urlFields = []               // url变量
    window.GLOB.customMenu = config          // 保存菜单信息
    this.setState({config: config, oriConfig: fromJS(config).toJS()})
  }
  componentDidMount () {
    MKEmitter.addListener('completeSave', this.completeSave)
    MKEmitter.addListener('triggerMenuSave', this.submitConfig)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('completeSave', this.completeSave)
    MKEmitter.removeListener('triggerMenuSave', this.submitConfig)
  }
  closeView = () => {
    const { oriConfig, config } = this.state
    if (!is(fromJS(oriConfig), fromJS(config))) {
      const _this = this
      confirm({
        title: '配置已修改,放弃保存吗?',
        content: '',
        onOk() {
          _this.props.cancel()
        },
        onCancel() {}
      })
    } else {
      this.props.cancel()
    }
  }
  getMenuMessage = (config) => {
    let tbs = []
    let traversal = (components) => {
      components.forEach(item => {
        if (item.$tables) {
          tbs.push(...item.$tables)
        }
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            traversal(tab.components)
          })
        } else if (item.type === 'group') {
          traversal(item.components)
        }
      })
    }
    traversal(config.components)
    config.$tables = Array.from(new Set(tbs))
  }
  completeSave = () => {
    this.setState({
      oriConfig: fromJS(this.state.config).toJS(),
      menuloading: false
    })
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
    if (config.cacheUseful === 'true' && !config.cacheTime) {
      notification.warning({
        top: 92,
        message: '请完善缓存设置!',
        duration: 5
      })
      return
    }
    if (config.enabled && this.verifyConfig()) {
      config.enabled = false
    }
    this.getMenuMessage(config)
    this.setState({
      config: config,
      menuloading: true
    })
    window.GLOB.customMenu = config
    this.props.save(fromJS(config).toJS())
  }
  onEnabledChange = () => {
    const { config } = this.state
    if (!config.enabled && this.verifyConfig(true)) {
      return
    }
    this.setState({
      config: {...config, enabled: !config.enabled}
    })
  }
  verifyConfig = (show) => {
    const { config } = this.state
    let error = ''
    let check = (components) => {
      components.forEach(item => {
        if (error) return
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            check(tab.components)
          })
          return
        } else if (item.type === 'group') {
          check(item.components)
          return
        } else if (!item.errors || item.errors.length === 0) {
          return
        }
        item.errors.forEach(err => {
          if (err.level !== 0 || error) return
          error = `组件《${item.name}》${err.detail}`
        })
      })
    }
    check(config.components)
    if (show && error) {
      notification.warning({
        top: 92,
        message: error,
        duration: 5
      })
    }
    return error
  }
  // 更新配置信息
  updateConfig = (config) => {
    this.setState({
      config: config
    })
    window.GLOB.customMenu = config
  }
  resetConfig = (config) => {
    this.setState({
      config,
      comloading: true
    }, () => {
      this.setState({
        comloading: false
      })
    })
    window.GLOB.customMenu = config
  }
  /**
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
  updatetable = (config) => {
    this.setState({ config })
    window.GLOB.customMenu = config
  }
  insert = (item) => {
    let config = fromJS(this.state.config).toJS()
    config.components.push(item)
    this.setState({config})
    window.GLOB.customMenu = config
    notification.success({
      top: 92,
      message: '粘贴成功!',
      duration: 2
    })
  }
  render () {
    const { settingshow, controlshow, comloading, config, menuloading, eyeopen } = this.state
    return (
      <div className="mob-poper-view">
        <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
          <div className="draw">
            {settingshow ? <DoubleLeftOutlined onClick={() => {this.setState({settingshow: false})}} /> : null}
            {!settingshow ? <DoubleRightOutlined onClick={() => {this.setState({settingshow: true})}} /> : null}
          </div>
          <div className="pc-setting-tools">
            <Collapse accordion defaultActiveKey="component" bordered={false}>
              {/* 基本信息 */}
              <Panel header="基本信息" forceRender className="basedata" key="basedata">
                {/* 菜单信息 */}
                <MenuForm config={config} updateConfig={this.updateConfig}/>
                {/* 表名添加 */}
                <TableComponent config={config} updatetable={this.updateConfig}/>
              </Panel>
              {/* 组件添加 */}
              <Panel header="组件" className="component" key="component">
                <SourceWrap viewType="popview"/>
              </Panel>
              <Panel header="元素" key="element">
                <Modulecell />
              </Panel>
              <Panel header={'页面样式'} key="background">
                <BgController config={config} updateConfig={this.updateConfig} />
              </Panel>
            </Collapse>
          </div>
        </div>
        <div className={'menu-control' + (!controlshow ? ' hidden' : '')}>
          <div className="draw">
            {controlshow ? <DoubleRightOutlined onClick={() => {this.setState({controlshow: false})}}/> : null}
            {!controlshow ? <DoubleLeftOutlined onClick={() => {this.setState({controlshow: true})}}/> : null}
          </div>
          <div className="wrap">
            <Button type="primary" onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
            <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config && config.enabled} onChange={this.onEnabledChange} />
            <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
            <PasteController insert={this.insert} />
            <StyleCombControlButton menu={config} />
            <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
            <Button type="default" onClick={this.closeView}>返回</Button>
          </div>
        </div>
        <div className={'menu-body menu-view' + (menuloading ? ' saving' : '') + (eyeopen ? ' eye-open' : '')}>
          {config && !comloading ? <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
            <MobShell menu={config} handleList={this.updateConfig} />
          </div> : null}
        </div>
      </div>
    )
  }
}
export default PopViewDesign
src/views/mobdesign/popview/index.scss
New file
@@ -0,0 +1,4 @@
.mob-poper-view {
  background: #000;
  min-height: 100vh;
}
src/views/mobdesign/popview/menuform/index.jsx
New file
@@ -0,0 +1,117 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Radio, Tooltip, InputNumber } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
// import './index.scss'
class CustomMenuForm extends Component {
  static propTpyes = {
    config: PropTypes.object,
    updateConfig: PropTypes.func
  }
  changeCacheDay = (val) => {
    if (typeof(val) !== 'number') {
      val = ''
    }
    this.props.updateConfig({...this.props.config, cacheTime: val})
  }
  selectChange = (key, value) => {
    const { config } = this.props
    if (key === 'cacheUseful') {
      this.props.updateConfig({...config, cacheUseful: value})
    } else if (key === 'timeUnit') {
      this.props.updateConfig({...config, timeUnit: value})
    } else if (key === 'cacheLocal') {
      this.props.updateConfig({...config, cacheLocal: value})
    }
  }
  render() {
    const { config } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout}>
        <Row>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
                initialValue: config.cacheUseful || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheUseful', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          {config.cacheUseful === 'true' ? <Col span={24}>
            <Form.Item label="单位">
              {getFieldDecorator('timeUnit', {
                initialValue: config.timeUnit || 'day'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}>
                  <Radio value="day">天</Radio>
                  <Radio value="hour">小时</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          {config.cacheUseful === 'true' ? <Col span={24}>
            <Form.Item label="时长">
              {getFieldDecorator('cacheTime', {
                initialValue: config.cacheTime,
                rules: [
                  {
                    required: true,
                    message: '请输入时长!'
                  }
                ]
              })(
                <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/>
              )}
            </Form.Item>
          </Col> : null}
        </Row>
      </Form>
    )
  }
}
export default Form.create()(CustomMenuForm)
src/views/mobdesign/popview/menuform/index.scss
src/views/pcdesign/index.jsx
@@ -1686,7 +1686,7 @@
    return (
      <ConfigProvider locale={antdZhCN}>
        <DndProvider backend={HTML5Backend}>
          {view !== 'popview' ?<div className={'mk-pc-view '} id="mk-pc-design-view">
          {view !== 'popview' ? <div className={'mk-pc-view '} id="mk-pc-design-view">
            {loading ? <Spin className="view-spin" size="large" /> : null}
            <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
              <div className="draw">
src/views/pcdesign/menuform/index.jsx
@@ -26,6 +26,8 @@
      this.props.updateConfig({...config, timeUnit: value})
    } else if (key === 'mask') {
      this.props.updateConfig({...config, mask: value})
    } else if (key === 'cacheLocal') {
      this.props.updateConfig({...config, cacheLocal: value})
    // } else if (key === 'permission') {
    //   this.props.updateConfig({...config, permission: value})
    }
@@ -97,9 +99,26 @@
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="数据会缓存到用户本地,方便页面快速呈现。">
                <QuestionCircleOutlined className="mk-form-tip" />
                本地缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheLocal', {
                initialValue: config.cacheLocal || 'false'
              })(
                <Radio.Group onChange={(e) => {this.selectChange('cacheLocal', e.target.value)}}>
                  <Radio value="true">使用</Radio>
                  <Radio value="false">不使用</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。">
                <QuestionCircleOutlined className="mk-form-tip" />
                缓存数据
                后端缓存
              </Tooltip>
            }>
              {getFieldDecorator('cacheUseful', {
src/views/sso/index.jsx
@@ -95,7 +95,7 @@
        let level = res.pwd_level || ''
        if (level && !['letter_num', 'char_num', 'char_num_90'].includes(level)) {
        if (level && !['letter_num', 'char_num', 'char_num_90', 'char_num_90_sms'].includes(level)) {
          level = ''
        }
src/views/systemfunc/index.jsx
@@ -6,12 +6,13 @@
import Header from './header'
import Sidemenu from './sidemenu'
import './index.scss'
// import './index.scss'
const Tabview = asyncComponent(() => import('@/components/tabview'))
class Design extends Component {
  UNSAFE_componentWillMount() {
    document.body.className = 'mk-blue-black'
    sessionStorage.setItem('isEditState', 'true')
    window.GLOB.mkHS = true
@@ -27,7 +28,7 @@
  
  render () {
    return (
      <div className="mk-hs-view">
      <div className="mk-main-view">
        <ConfigProvider locale={zhCN}>
          <Sidemenu key="sidemenu"/>
          <Tabview key="tabview"/>
src/views/systemfunc/index.scss
@@ -1,5 +1 @@
.mk-hs-view {
  display: flex;
  flex: auto;
  min-height: 100%;
}
src/views/systemfunc/sidemenu/config.jsx
@@ -32,13 +32,13 @@
    MenuID: '1583979633842550imkchl4qt4qppsiv',
    MenuNo: 'sVersionMUpgrade',
    MenuName: '版本升级',
  }, {
    src: '',
    PageParam: {OpenType: 'newtab', Template: 'TabManage'},
    type: 'TabManage',
    MenuID: 'TabManageView',
    MenuNo: 'TabManage',
    MenuName: '标签页管理',
  // }, {
  //   src: '',
  //   PageParam: {OpenType: 'newtab', Template: 'TabManage'},
  //   type: 'TabManage',
  //   MenuID: 'TabManageView',
  //   MenuNo: 'TabManage',
  //   MenuName: '标签页管理',
  }, {
    src: '',
    PageParam: {OpenType: 'newtab', Template: 'BaseTable'},
src/views/systemproc/proc/index.jsx
@@ -1,5 +1,6 @@
import React, {Component} from 'react'
import { Input, notification } from 'antd'
import { Input, notification, Button, Form, Modal, Empty } from 'antd'
import { MenuUnfoldOutlined, MenuFoldOutlined } from '@ant-design/icons'
import moment from 'moment'
import Utils from '@/utils/utils.js'
@@ -7,17 +8,52 @@
import CodeMirror from '@/templates/zshare/codemirror'
import './index.scss'
const { confirm } = Modal
const { Search } = Input
class ProcControl extends Component {
  state = {
    procName: '',
    content: null,
    loading: false
    content: '',
    loading: false,
    visible: false,
    searchable: false,
    inputing: false,
    procList: [],
    permFuncs: []
  }
  componentDidMount () {
    if (sessionStorage.getItem('permFuncField')) {
      this.setState({permFuncs: JSON.parse(sessionStorage.getItem('permFuncField'))})
    } else {
      Api.getCloudConfig({func: 'sPC_Get_Roles_sModular'}).then(res => {
        if (res.status) {
          let _permFuncs = []
          if (res.sModular && res.sModular.length > 0) {
            res.sModular.forEach(field => {
              if (field.ModularNo) {
                _permFuncs.push(field.ModularNo)
              }
            })
            _permFuncs = _permFuncs.sort()
          }
          if (_permFuncs.length) {
            this.setState({permFuncs: _permFuncs})
    
            sessionStorage.setItem('permFuncField', JSON.stringify(_permFuncs))
          }
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    }
  }
  search = (value) => {
@@ -47,31 +83,330 @@
        })
        this.setState({content: '', procName: '', loading: false})
        return
      } else if (!res.Ltext) {
        this.setState({content: '', procName: '', loading: false})
      } else {
        this.setState({content: res.Ltext.replace(/mchr13k/ig, '\n'), procName: proc, loading: false})
      }
    })
  }
  save = (type) => {
    const { content, procName, permFuncs } = this.state
    let value = content.replace(/^(\s*)|(\s*)$/ig, '')
    if (!value) {
      notification.warning({
        top: 92,
        message: '存储过程不可为空',
        duration: 5
      })
      return
    } else {
      let chars = [
        {key: 'drop', reg: /(^|\s)drop\s/ig},
        {key: 'alter', reg: /(^|\s)alter\s/ig},
        {key: 'object', reg: /(^|\s)object(\s|\()/ig},
        {key: 'kill', reg: /(^|\s)kill\s/ig},
        {key: '--', reg: /--/ig}
      ]
      let error = ''
      if (!/create(\s+)proc/ig.test(value)) {
        error = '脚本中必须使用create proc'
      }
      chars.forEach(char => {
        if (!error && char.reg.test(value)) {
          error = '不可使用' + char.key
        }
      })
      if (error) {
        notification.warning({
          top: 92,
          message: error,
          duration: 5
        })
        return
      }
    }
    if (!procName) {
      if (permFuncs.length > 0) {
        this.setState({visible: true})
      } else {
        notification.warning({
          top: 92,
          message: '未获取到授权编码不可新建!',
          duration: 5
        })
      }
      return
    }
    let dropfunc = `IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID('${procName}') AND type in (N'P', N'PC'))  mdrpk PROCEDURE ${procName}`
    let createfunc = value.replace(/\n/ig, 'mchr13k')
    let dropParam = {
      func: 'sPC_TableData_InUpDe',
      LText: Utils.formatOptions(dropfunc),
      TypeCharOne: 'proc' // 删除存储过程
    }
    dropParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    dropParam.secretkey = Utils.encrypt(dropParam.LText, dropParam.timestamp)
    dropParam.open_key = Utils.encryptOpenKey(dropParam.secretkey, dropParam.timestamp)
    let createParam = {
      func: 'sPC_TableData_InUpDe',
      LText: Utils.formatOptions(createfunc),
      TypeCharOne: 'proc' // 创建存储过程
    }
    createParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    createParam.secretkey = Utils.encrypt(createParam.LText, createParam.timestamp)
    createParam.open_key = Utils.encryptOpenKey(createParam.secretkey, createParam.timestamp)
    let saveParam = {
      func: 's_proc_save',
      sql_script: window.btoa(window.encodeURIComponent(createfunc)),
      proc_name: procName,
      save_type: type !== 'prev' ? 'auto' : '' // 'auto' 时 会清y的数据
    }
    this.setState({loading: true})
    Api.genericInterface(dropParam).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({loading: false})
        return
      }
      this.setState({content: res.Ltext.replace(/mchr13k/ig, '\n'), procName: proc, loading: false})
      Api.genericInterface(createParam).then(result => {
        if (!result.status) {
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
          this.setState({loading: false})
          return
        }
        Api.genericInterface(saveParam).then(response => {
          this.setState({loading: false})
          if (!response.status) {
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          } else {
            notification.success({
              top: 92,
              message: '保存成功。',
              duration: 5
            })
          }
        })
      })
    })
  }
  prev = () => {
    const { procName } = this.state
    const that = this
    let saveParam = {
      func: 's_proc_ctrl_z',
      proc_name: procName
    }
    confirm({
      title: '确定切换上一版本吗?',
      content: '',
      onOk() {
        that.setState({loading: true})
        Api.genericInterface(saveParam).then(res => {
          that.setState({loading: false})
          if (!res.status || !res.Ltext) {
            notification.warning({
              top: 92,
              message: !res.status ? res.message : '没有可以后退的版本',
              duration: 5
            })
            return
          }
          let value = window.decodeURIComponent(window.atob(res.Ltext))
          value  = value.replace(/mchr13k/ig, '\n')
          that.setState({content: value}, () => {
            that.save('prev')
          })
        })
      },
      onCancel() {}
    })
  }
  next = () => {
    const { procName } = this.state
    const that = this
    let saveParam = {
      func: 's_proc_ctrl_y',
      proc_name: procName
    }
    confirm({
      title: '确定切换下一版本吗?',
      content: '',
      onOk() {
        that.setState({loading: true})
        Api.genericInterface(saveParam).then(res => {
          that.setState({loading: false})
          if (!res.status || !res.Ltext) {
            notification.warning({
              top: 92,
              message: !res.status ? res.message : '没有可以撤销后退的版本',
              duration: 5
            })
            return
          }
          let value = window.decodeURIComponent(window.atob(res.Ltext))
          value  = value.replace(/mchr13k/ig, '\n')
          that.setState({content: value}, () => {
            that.save()
          })
        })
      },
      onCancel() {}
    })
  }
  handleConfirm = () => {
    this.props.form.validateFieldsAndScroll((err, values) => {
      if (err) return
      this.setState({procName: values.name}, () => {
        this.save()
      })
    })
  }
  searchAll = (value) => {
    let param = {
      func: 's_proc_search',
      proc_name: value || ''
    }
    this.setState({loading: true})
    Api.genericInterface(param).then(res => {
      this.setState({loading: false})
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      this.setState({procList: res.data || []})
    })
  }
  changeProc = (name) => {
    const { loading } = this.state
    if (loading) {
      notification.warning({
        top: 92,
        message: '查询中请稍后。',
        duration: 5
      })
      return
    }
    this.setState({inputing: true, procName: name}, () => {
      this.setState({inputing: false})
      this.search(name)
    })
  }
  render () {
    const { loading, content } = this.state
    const { getFieldDecorator } = this.props.form
    const { loading, content, procName, visible, permFuncs, searchable, procList, inputing } = this.state
    let _patten = permFuncs.length ? new RegExp('^(' + permFuncs.join('|') + ')[0-9a-zA-Z_]*$', 'g') : ''
    return (
      <div className="mk-proc-wrap">
        <div className="control-wrap">
          <div className="search-wrap">
            <Search placeholder="请输入存储过程名称" disabled={loading} enterButton="确定" onSearch={this.search}/>
          </div>
          <div className="action-wrap">
        <div className={'searh-list' + (searchable ? ' open' : '')}>
          <Search placeholder="存储过程名称查询" disabled={loading} onSearch={this.searchAll}/>
          <div className="proc-list">
            {procList.map((item, index) => (<div className="proc-item" onClick={() => this.changeProc(item.proc_name)} key={index}>{item.proc_name}</div>))}
            {procList.length === 0 ? <Empty /> : null}
          </div>
        </div>
        <div className="edit-wrap">
          <CodeMirror value={content} onChange={(val) => this.setState({content: val})}/>
        <div className="proc-wrap">
          <div className="control-wrap">
            <div className="search-wrap">
              {searchable ? <MenuUnfoldOutlined onClick={() => this.setState({searchable: !searchable})}/> : <MenuFoldOutlined onClick={() => this.setState({searchable: !searchable})}/>}
              {!inputing ? <Search placeholder="请输入存储过程名称" defaultValue={procName} disabled={loading} enterButton="确定" onSearch={this.search}/> : null}
            </div>
            <div className="action-wrap">
              <Button key="save" className="mk-btn mk-green" disabled={loading} onClick={() => this.save()}>保存</Button>
              <Button key="prev" className="mk-btn mk-primary" disabled={!procName || loading} onClick={this.prev}>上一版本</Button>
              <Button key="next" className="mk-btn mk-primary" disabled={!procName || loading} onClick={this.next}>下一版本</Button>
            </div>
          </div>
          <div className="edit-wrap">
            <CodeMirror value={content} onChange={(val) => this.setState({content: val})}/>
          </div>
        </div>
        <Modal
          title="新建"
          wrapClassName="mk-create-func"
          visible={visible}
          onOk={this.handleConfirm}
          width={540}
          onCancel={() => {this.setState({ visible: false })}}
          destroyOnClose
        >
          <Form.Item label="存储过程名称">
            {getFieldDecorator('name', {
              initialValue: '',
              rules: [
                {
                  required: true,
                  message: '请输入存储过程名称!'
                },
                {
                  pattern: _patten,
                  message: `只允许包含数字、字母和下划线,且以${permFuncs.join(', ')}等字符开始。`
                }
              ]
            })(<Input placeholder="" autoComplete="off" />)}
          </Form.Item>
        </Modal>
      </div>
    )
  }
}
export default ProcControl
export default Form.create()(ProcControl)
src/views/systemproc/proc/index.scss
@@ -1,12 +1,89 @@
.mk-proc-wrap {
  position: relative;
  padding: 65px 20px 0px;
  display: flex;
  
  .searh-list {
    width: 0px;
    margin-right: 15px;
    overflow: hidden;
    transition: width 0.2s;
    .ant-input-search {
      width: 300px;
    }
    .proc-list {
      width: 300px;
      height: calc(100vh - 128px);
      overflow-y: auto;
      overflow-x: hidden;
      margin-top: 10px;
      border: 1px solid #e8e8e8;
      .proc-item {
        padding: 5px;
        margin: 5px;
        word-break: break-all;
        cursor: pointer;
      }
      .ant-empty {
        margin-top: 50px;
      }
    }
    .proc-list::-webkit-scrollbar {
      width: 7px;
      height: 7px;
    }
    .proc-list::-webkit-scrollbar-thumb {
      border-radius: 5px;
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
      background: rgba(0, 0, 0, 0.13);
    }
    .proc-list::-webkit-scrollbar-track {
      box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
      border-radius: 3px;
      border: 1px solid rgba(0, 0, 0, 0.07);
      background: rgba(0, 0, 0, 0);
    }
  }
  .searh-list.open {
    width: 300px;
  }
  .proc-wrap {
    flex: 1;
  }
  .control-wrap {
    display: flex;
    .search-wrap {
      width: 300px;
      width: 360px;
      display: flex;
      .ant-btn[disabled] {
        background-color: #1890ff!important;
        border-color: #1890ff!important;
        color: #ffffff!important;
        opacity: 0.5;
      }
      .ant-input {
        border-radius: 0;
      }
      >.anticon {
        line-height: 30px;
        width: 35px;
        border: 1px solid #e8e8e8;
        cursor: pointer;
        border-top-left-radius: 4px;
        border-bottom-left-radius: 4px;
      }
    }
    .action-wrap {
      text-align: right;
      flex: 1;
      .ant-btn {
        margin-left: 20px;
      }
      .ant-btn[disabled] {
        background-color: #1890ff!important;
@@ -33,3 +110,15 @@
    }
  }
}
.mk-create-func {
  .ant-modal-body {
    min-height: 180px;
  }
  .ant-form-item {
    display: flex;
    .ant-form-item-control-wrapper {
      flex: 1;
    }
  }
}