king
2024-06-21 b91c28df2f734b680198e755b7828666e238cea0
Merge branch 'develop'
156个文件已修改
2个文件已删除
4个文件已添加
6391 ■■■■ 已修改文件
public/manifest.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/breadview/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/loginform.jsx 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkSelect/index.jsx 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/pasteboard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/resetPassword/index.jsx 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/resetPassword/resetpwd/index.jsx 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/login.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/login.js 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/elementform/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/options.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/double-data-card/options.jsx 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/actionform/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/formconfig.jsx 33 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/options.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/dragsearch/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/search/main-search/options.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/dragaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/copycomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/searchcomponent/dragsearch/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/searchcomponent/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/editColumn/formconfig.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/editColumn/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/columns/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/options.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/index.jsx 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/editColumn/index.scss 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/options.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/index.jsx 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/options.jsx 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/customscript/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/utils.jsx 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/debug/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/sysinterface/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/tablenodes/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/colorsketch/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/menubar/normal-menubar/menucomponent/options.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/menus/menuform/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/searchdragelement/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/createview/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/createview/settingform/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/setupProxy.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/store/options.js 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/calendar/board/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.jsx 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.scss 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/table-card/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/module/invoice/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.scss 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/table/edit-table/normalTable/index.scss 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 15 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtabtable/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/changeuserbutton/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/excelInbutton/index.jsx 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/funcbutton/index.jsx 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/funczip/index.jsx 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/newpagebutton/index.jsx 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 181 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/tabbutton/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.scss 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/index.jsx 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/topSearch/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/dragaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/columncomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.jsx 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/searchcomponent/searchform/index.scss 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/codemirror/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.scss 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/pasteform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/callbackcustomscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 793 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-datamanage.js 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appcheck/index.jsx 220 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/index.jsx 481 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/submutilform/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/transmenu/index.jsx 519 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/appmanage/transmenu/index.scss 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/basedesign/index.jsx 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/billprint/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/transmenu/index.jsx 885 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/transmenu/index.scss 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editthdmenu/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuplus/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/imdesign/index.jsx 173 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/interface/index.jsx 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/logincloudform.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/loginform.jsx 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/main/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mkiframe/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 52 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/printTemplate/index.jsx 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rolemanage/index.jsx 107 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/sso/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/sidemenu/config.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemproc/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/index.jsx 42 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/manifest.json
@@ -6,5 +6,5 @@
  "display": "standalone",
  "theme_color": "#000000",
  "background_color": "#ffffff",
  "mk_version": "20240501"
  "mk_version": "20240601"
}
src/api/index.js
@@ -15,7 +15,8 @@
window.GLOB.$error = false
let service = window.GLOB.service ? '-' + window.GLOB.service.replace('/', '') : ''
let db = `mkdb${service}`
let lang = sessionStorage.getItem('lang') !== 'zh-CN' ? sessionStorage.getItem('lang') : ''
let db = `mkdb${service + lang}`
if (window.indexedDB) {
  CacheUtils.openIndexDB(db)
@@ -97,13 +98,16 @@
  }
  /**
   * @description 微信业务请求
   * @description 微信业务请求 原接口 'wxpay/getaccesstoken'
   */
  wxAccessToken (domain = '') {
    let _url = window.GLOB.baseurl + 'wxpay/getaccesstoken'
    let _url = domain || window.GLOB.baseurl
    if (domain) {
      _url = domain + 'wxpay/getaccesstoken'
    if (/qingqiumarket.cn|cloud.mk9h.cn/.test(_url)) {
      _url = _url.replace('http://qingqiumarket.cn', 'http://qingqiumarket.cn:8080')
      _url = _url.replace('http://cloud.mk9h.cn', 'http://cloud.mk9h.cn:8080')
      _url = _url.replace('https://qingqiumarket.cn', 'https://qingqiumarket.cn:8443')
      _url = _url.replace('https://cloud.mk9h.cn', 'https://cloud.mk9h.cn:8443')
    }
    return new Promise(resolve => {
@@ -112,13 +116,15 @@
      } else {
        window.GLOB.accessToken = {domain}
        axios({
          url: _url,
          method: 'get'
          url: _url + 'wechat/jsapi/getaccesstoken',
          method: 'post',
          headers: { 'Content-Type': 'application/json' },
          data: JSON.stringify({appId: 'wx4d8a34c8d4494872'})
        }).then(res => {
          if (res.oa_access_token || res.mini_access_token) {
          if (res.oa_access_token) {
            window.GLOB.accessToken.accessTime = parseInt(new Date().getTime() / 1000)
            window.GLOB.accessToken.oa_access_token = res.oa_access_token
            window.GLOB.accessToken.mini_access_token = res.mini_access_token
            // window.GLOB.accessToken.mini_access_token = res.mini_access_token
          }
          resolve(res)
        })
@@ -128,6 +134,7 @@
  /**
   * @description 微信业务请求
   * 39上 qingqiumarket.cn|cloud.mk9h.cn|sso.mk9h.cn
   */
  wxNginxRequest (url, method, param) {
    let _url = url
@@ -137,16 +144,11 @@
      if (process.env.NODE_ENV === 'production') {
        _url = document.location.origin + '/' + url
      }
      if (/^http:\/\/(qingqiumarket.cn|cloud.mk9h.cn|sso.mk9h.cn)/.test(_url)) {
        _url = window.GLOB.location + ':8080/' + url
        if (process.env.NODE_ENV === 'production') {
          _url = document.location.origin + ':8080/' + url
        }
      } else if (/^https:\/\/(qingqiumarket.cn|cloud.mk9h.cn|sso.mk9h.cn)/.test(_url)) {
        _url = window.GLOB.location + ':8443/' + url
        if (process.env.NODE_ENV === 'production') {
          _url = document.location.origin + ':8443/' + url
        }
      if (/qingqiumarket.cn|cloud.mk9h.cn/.test(_url)) {
        _url = _url.replace('http://qingqiumarket.cn', 'http://qingqiumarket.cn:8080')
        _url = _url.replace('http://cloud.mk9h.cn', 'http://cloud.mk9h.cn:8080')
        _url = _url.replace('https://qingqiumarket.cn', 'https://qingqiumarket.cn:8443')
        _url = _url.replace('https://cloud.mk9h.cn', 'https://cloud.mk9h.cn:8443')
      }
    }
    
@@ -1028,16 +1030,11 @@
    if (process.env.NODE_ENV === 'production') {
      _url = document.location.origin + '/file/oss/upload'
    }
    if (/^http:\/\/(qingqiumarket.cn|cloud.mk9h.cn|sso.mk9h.cn)/.test(_url)) {
      _url = window.GLOB.location + ':8080/file/oss/upload'
      if (process.env.NODE_ENV === 'production') {
        _url = document.location.origin + ':8080/file/oss/upload'
      }
    } else if (/^https:\/\/(qingqiumarket.cn|cloud.mk9h.cn|sso.mk9h.cn)/.test(_url)) {
      _url = window.GLOB.location + ':8443/file/oss/upload'
      if (process.env.NODE_ENV === 'production') {
        _url = document.location.origin + ':8443/file/oss/upload'
      }
    if (/qingqiumarket.cn|cloud.mk9h.cn/.test(_url)) {
      _url = _url.replace('http://qingqiumarket.cn', 'http://qingqiumarket.cn:8080')
      _url = _url.replace('http://cloud.mk9h.cn', 'http://cloud.mk9h.cn:8080')
      _url = _url.replace('https://qingqiumarket.cn', 'https://qingqiumarket.cn:8443')
      _url = _url.replace('https://cloud.mk9h.cn', 'https://cloud.mk9h.cn:8443')
    }
    
    return axios({
@@ -1087,7 +1084,7 @@
  /**
   * @description sql检验
   */
  sDebug (sql, rduri = null) {
  sDebug (sql) {
    let param = {
      func: 's_debug_sql',
      exec_type: window.GLOB.execType || 'y',
@@ -1106,6 +1103,7 @@
    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid')}'`)
    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID')}'`)
    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey}'`)
    sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    // sql = sql.replace(/@datam@/ig, `''`)
    if (window.GLOB.externalDatabase !== null) {
@@ -1122,10 +1120,6 @@
    param = this.encryptParam(param)
    let url = '/webapi/dostars'
    if (rduri) {
      url = rduri
    }
    let timer = setTimeout(() => {
      let _param = {
src/assets/css/main.scss
@@ -728,6 +728,49 @@
    vertical-align: bottom;
  }
}
.fixed-table-height {
  tr, td, th {
    overflow: hidden;
  }
  ::-webkit-scrollbar {
    width: 17px;
    height: 17px;
  }
  ::-webkit-scrollbar-thumb {
    background: rgba(193, 193, 193, 0.7);
  }
  ::-webkit-scrollbar-track {
    background: #fafafa;
  }
  .ant-table-body {
    min-height: 1px;
    border-bottom: 1px solid rgba(0, 0, 0, .05);
    .ant-table-fixed {
      border-bottom: 0;
    }
  }
}
@media screen and (max-width: 1400px) {
  .fixed-table-height {
    ::-webkit-scrollbar {
      width: 16px;
    }
  }
}
@media screen and (min-width: 1600px) {
  .fixed-table-height {
    ::-webkit-scrollbar {
      width: 18px;
    }
  }
}
@media screen and (min-width: 1900px) {
  .fixed-table-height {
    ::-webkit-scrollbar {
      width: 21px;
    }
  }
}
// 系统色设置
.mk-main-view {
src/components/breadview/index.jsx
@@ -18,7 +18,9 @@
const Iframe = asyncComponent(() => import('@/tabviews/iframe'))
const RoleManage = asyncComponent(() => import('@/tabviews/rolemanage'))
moment.locale('zh-cn')
if (sessionStorage.getItem('lang') === 'zh-CN') {
  moment.locale('zh-cn')
}
class BreadView extends Component {
  state = {
@@ -32,7 +34,7 @@
  UNSAFE_componentWillMount () {
    let home = {
      MenuID: 'home_page_id',
      MenuName: '首页',
      MenuName: window.GLOB.dict['home'] || '首页',
      type: 'Home'
    }
    this.setState({tabview: home})
@@ -138,7 +140,7 @@
  gotoHome = () => {
    let home = {
      MenuID: 'home_page_id',
      MenuName: '首页',
      MenuName: window.GLOB.dict['home'] || '首页',
      type: 'Home'
    }
    this.setState({tabview: home})
src/components/header/index.jsx
@@ -34,7 +34,8 @@
    thdMenuList: [],
    debug: sessionStorage.getItem('debug') === 'true' && window.GLOB.memberLevel > 0,
    collapse: sessionStorage.getItem('collapse') === 'true',
    lang: sessionStorage.getItem('lang') || ''
    lang: sessionStorage.getItem('lang') || '',
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -113,16 +114,18 @@
  }
  logout = () => {
    const { dict } = this.state
    // 退出登录
    let _this = this
    confirm({
      title: '您确定要退出吗?',
      title: dict['logout_query'] || '您确定要退出吗?',
      content: '',
      okText: '确定',
      cancelText: '取消',
      okText: dict['ok'] || '确定',
      cancelText: dict['cancel'] || '取消',
      onOk() {
        sessionStorage.clear()
        _this.props.history.replace('/login')
        window.location.reload()
      },
      onCancel() {}
    })
@@ -441,11 +444,10 @@
          sessionStorage.setItem('CloudLogo', res.open_logo || '')
          let _url = window.location.href.split('#')[0] + 'cloud'
          if (param.remember) {
            localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify({time: new Date().getTime(), username: param.username, password: param.password}))))
            localStorage.setItem(window.GLOB.sysSign + 'cloud', window.btoa(window.encodeURIComponent(JSON.stringify({time: new Date().getTime(), username: param.username, password: param.password}))))
          } else {
            localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify({time: new Date().getTime(), username: param.username, password: ''}))))
            localStorage.setItem(window.GLOB.sysSign + 'cloud', window.btoa(window.encodeURIComponent(JSON.stringify({time: new Date().getTime(), username: param.username, password: ''}))))
          }
          window.GLOB.mainMenu = null
@@ -563,15 +565,19 @@
  }
  verup = () => {
    const { dict } = this.state
    confirm({
      title: '页面更新',
      content: '重新加载应用信息',
      title: dict['page_upd'] || '页面更新',
      content: dict['reload_app'] || '重新加载应用信息',
      okText: dict['ok'] || '确定',
      cancelText: dict['cancel'] || '取消',
      onOk() {
        return new Promise(resolve => {
          if (!window.GLOB.IndexDB) {
            notification.warning({
              top: 92,
              message: '更新失败,请刷新页面重试!',
              message: dict['exc_fail'] || '更新失败,请刷新页面重试!',
              duration: 2
            })
            resolve()
@@ -583,7 +589,7 @@
            setTimeout(() => {
              notification.success({
                top: 92,
                message: '更新成功!',
                message: dict['exc_success'] || '更新成功!',
                duration: 2
              })
              resolve()
@@ -597,7 +603,8 @@
  about = () => {
    Modal.success({
      title: '系统版本v' + window.GLOB.appVersion
      title: (window.GLOB.dict['sys_ver'] || '系统版本') + ' v' + window.GLOB.appVersion,
      okText: window.GLOB.dict['got_it'] || '知道了',
    })
  }
@@ -608,32 +615,32 @@
  }
  render () {
    const { thdMenuList, searchkey, debug, menulist, collapse } = this.state
    const { thdMenuList, searchkey, debug, menulist, collapse, dict } = this.state
    const navBar = window.GLOB.navBar
    const menu = (
      <Menu className="header-dropdown">
        {debug && <Menu.Item key="switch">
          编辑
          {dict['edit'] || '编辑'}
          <Switch size="small" style={{marginLeft: '7px'}} checked={false} onChange={this.changeEditState} />
        </Menu.Item>}
        <Menu.Item key="password" onClick={this.changePassword}>修改密码</Menu.Item>
        {this.state.systems.length ? <Menu.SubMenu style={{minWidth: '110px'}} title="切换系统">
        <Menu.Item key="password" onClick={this.changePassword}>{dict['ch_pwd'] || '修改密码'}</Menu.Item>
        {this.state.systems.length ? <Menu.SubMenu style={{minWidth: '110px'}} title={dict['swt_sys'] || '切换系统'}>
          {this.state.systems.map((system, index) => (
            <Menu.Item style={{minWidth: '100px', lineHeight: '30px'}} key={'sub' + index} onClick={() => {this.changeSystem(system)}}> {system.AppName} </Menu.Item>
          ))}
        </Menu.SubMenu> : null}
        <Menu.Item key="doc" onClick={this.gotoDoc}>文档中心</Menu.Item>
        <Menu.Item key="doc" onClick={this.gotoDoc}>{dict['doc_center'] || '文档中心'}</Menu.Item>
        <Menu.Item key="verup" onClick={this.verup}>
          页面更新
          {dict['page_upd'] || '页面更新'}
        </Menu.Item>
        {window.GLOB.WXNotice ? <Menu.Item key="wxnotice" onClick={() => this.setState({wxVisible: true})}>
          微信消息
        </Menu.Item> : null}
        {window.GLOB.appVersion ? <Menu.Item key="version" onClick={this.about}>
          关于
          {dict['about'] || '关于'}
        </Menu.Item> : null}
        <Menu.Item key="logout" onClick={this.logout}>退出</Menu.Item>
        <Menu.Item key="logout" onClick={this.logout}>{dict['logout'] || '退出'}</Menu.Item>
      </Menu>
    )
src/components/header/loginform.jsx
@@ -3,8 +3,6 @@
import { Form, Input, Checkbox } from 'antd'
import { UserOutlined, LockOutlined } from '@ant-design/icons'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
import './index.scss'
class HeaderLoginForm extends Component {
@@ -13,7 +11,6 @@
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    remember: false,
    username: '',
    password: '',
@@ -22,8 +19,7 @@
  }
  UNSAFE_componentWillMount () {
    let _url = window.location.href.split('#')[0] + 'cloud'
    let _user = localStorage.getItem(_url)
    let _user = localStorage.getItem(window.GLOB.sysSign + 'cloud')
    
    if (_user) {
      try {
@@ -36,7 +32,7 @@
    if (_user && new Date().getTime() - _user.time > 1000 * 7 * 24 * 60 * 60) {
      _user = ''
      localStorage.removeItem(_url)
      localStorage.removeItem(window.GLOB.sysSign + 'cloud')
    }
    if (_user) {
@@ -86,10 +82,9 @@
  rememberChange = (e) => {
    let val = e.target.checked
    let _url = window.location.href.split('#')[0] + 'cloud'
    if (!val) {
      localStorage.removeItem(_url)
      localStorage.removeItem(window.GLOB.sysSign + 'cloud')
    }
  }
@@ -116,12 +111,12 @@
        </Form.Item> : null}
        <Form.Item style={{marginBottom: '0px', height: '60px'}}>
          {getFieldDecorator('username', {
            rules: [{ required: true, message: this.state.dict['login.username.empty'] }],
            rules: [{ required: true, message: '请输入用户名' }],
            initialValue: username,
          })(
            <Input
              prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }}/>}
              placeholder={this.state.dict['login.username']}
              placeholder="用户名"
              autoComplete="off"
              onPressEnter={(e) => {this.handleSubmit(e, 'password')}}
            />
@@ -133,10 +128,10 @@
            rules: [
              {
                required: true,
                message: this.state.dict['login.password.empty'],
                message: '请输入密码',
              }
            ]
          })(<Input.Password onPressEnter={(e) => {this.handleSubmit(e, 'username')}} placeholder={this.state.dict['login.password']} prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
          })(<Input.Password onPressEnter={(e) => {this.handleSubmit(e, 'username')}} placeholder="密码" prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
        </Form.Item>
        {window.GLOB.keepKey ? <Form.Item style={{marginBottom: '10px'}}>
          {getFieldDecorator('remember', {
src/components/normalform/modalform/index.jsx
@@ -385,7 +385,7 @@
    }
    return (
      <Form {...formItemLayout} className="normal-form-field">
      <Form {...formItemLayout} className="normal-form-field" id="normal-form-field">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
src/components/normalform/modalform/mkSelect/index.jsx
@@ -1,4 +1,4 @@
import React, {Component} from 'react'
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { Select } from 'antd'
@@ -115,24 +115,7 @@
    const { value, config, options } = this.state
    if (config.type !== 'multiselect') {
      if (config.extendName) {
        return (
          <Select
            showSearch
            allowClear
            value={value}
            dropdownMatchSelectWidth={config.dropdown !== 'false'}
            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
              option.props.extend.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            onSelect={this.selectChange}
            onChange={(val) => val === undefined && this.selectChange('')}
          >
            {options.map((option, i) =>
              <Select.Option key={i} disabled={option.disabled} title={option.label || option.text} extend={option[config.extendName] || ''} value={option.value || option.field || ''}>{option.label || option.text}</Select.Option>
            )}
          </Select>
        )
      } else {
      if (config.joint) {
        return (
          <Select
            showSearch
@@ -142,13 +125,30 @@
            filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            onSelect={this.selectChange}
            onChange={(val) => val === undefined && this.selectChange('')}
            getPopupContainer={() => document.getElementById('normal-form-field')}
          >
            {options.map((option, i) =>
              <Select.Option key={i} disabled={option.disabled} value={option.value || option.field || ''}>{option.label || option.text}</Select.Option>
              <Select.Option key={i} disabled={option.disabled} value={option.field || ''}>{`${option.label}(${option.field})`}</Select.Option>
            )}
          </Select>
        )
      }
      return (
        <Select
          showSearch
          allowClear
          value={value}
          dropdownMatchSelectWidth={config.dropdown !== 'false'}
          filterOption={(input, option) => (option.props.children + option.props.extend).toLowerCase().indexOf(input.toLowerCase()) >= 0}
          onSelect={this.selectChange}
          onChange={(val) => val === undefined && this.selectChange('')}
          getPopupContainer={() => document.getElementById('normal-form-field')}
        >
          {options.map((option, i) =>
            <Select.Option key={i} disabled={option.disabled} title={option.label || option.text} extend={config.extendName ? (option[config.extendName] || '') : ''} value={option.value || option.field || ''}>{option.label || option.text}</Select.Option>
          )}
        </Select>
      )
    } else {
      return (<Select
        showSearch
@@ -156,6 +156,7 @@
        defaultValue={value}
        filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
        onChange={this.mutilselectChange}
        getPopupContainer={() => document.getElementById('normal-form-field')}
      >
        {options.map((option, i) =>
          <Select.Option key={i} disabled={option.disabled} value={option.value || option.field}>{option.label || option.text}</Select.Option>
src/components/pasteboard/index.jsx
@@ -46,7 +46,7 @@
      _config = JSON.parse(window.decodeURIComponent(window.atob(_config)))
      if (typeof(_config) === 'object' && _config.$srcId) {
        let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
        let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
        if (srcid && _config.$srcId !== srcid) {
          notification.warning({
            top: 92,
src/components/resetPassword/index.jsx
@@ -14,7 +14,8 @@
    visible: false,
    loading: false,
    type: 'account',
    okText: '确定',
    okText: window.GLOB.dict['ok'] || '确定',
    dict: window.GLOB.dict,
    smsId: '',
    mob: '',
    code: ''
@@ -40,7 +41,7 @@
      visible: true,
      loading: false,
      type: 'account',
      okText: '确定',
      okText: window.GLOB.dict['ok'] || '确定',
      mob: '',
      code: '',
      smsId: sessionStorage.getItem('mk_sms_id') || ''
@@ -48,7 +49,7 @@
  }
  resetPwdSubmit = () => {
    const { type } = this.state
    const { type, dict } = this.state
    if (type === 'account') {
      this.formRef.handleConfirm().then(res => {
@@ -77,7 +78,7 @@
            })
            notification.success({
              top: 92,
              message: '修改成功,请重新登录。',
              message: dict['re_login'] || '修改成功,请重新登录。',
              duration: 2
            })
            this.callback && this.callback()
@@ -98,7 +99,7 @@
        if (!/^1[3456789]\d{9}$/.test(res.phone)) {
          notification.warning({
            top: 92,
            message: '手机号格式错误,请重填!',
            message: dict['phone_error'] || '手机号格式错误,请重填!',
            duration: 5
          })
          return
@@ -114,7 +115,7 @@
        this.setState({
          code: res.vercode,
          type: 'phonepwd',
          okText: '确定'
          okText: dict['ok'] || '确定'
        })
      }, () => {})
    } else if (type === 'phonepwd') {
@@ -146,7 +147,7 @@
            })
            notification.success({
              top: 92,
              message: '修改成功,请重新登录。',
              message: dict['re_login'] || '修改成功,请重新登录。',
              duration: 2
            })
            this.callback && this.callback()
@@ -166,23 +167,23 @@
  }
  render() {
    const { visible, loading, okText, type, mob, smsId } = this.state
    const { visible, loading, okText, type, mob, smsId, dict } = this.state
    return (
      <Modal
        title="修改密码"
        title={dict['ch_pwd'] || '修改密码'}
        wrapClassName="reset-password-modal"
        visible={visible}
        maskClosable={false}
        onOk={this.resetPwdSubmit}
        onCancel={() => { this.setState({ visible: false })}}
        okText={okText}
        cancelText="取消"
        cancelText={dict['cancel'] || '取消'}
        confirmLoading={loading}
        destroyOnClose
      >
        <Resetpwd type={type} mob={mob} smsId={smsId} wrappedComponentRef={(inst) => this.formRef = inst} resetPwdSubmit={this.resetPwdSubmit}/>
        {type === 'account' && smsId ? <div className="forget-pwd"><span onClick={() => this.setState({type: 'mob', okText: '下一步'})}>忘记密码?</span></div> : null}
        {type === 'account' && smsId ? <div className="forget-pwd"><span onClick={() => this.setState({type: 'mob', okText: dict['next'] || '下一步'})}>{dict['forgot_pwd'] || '忘记密码?'}</span></div> : null}
      </Modal>
    )
  }
src/components/resetPassword/resetpwd/index.jsx
@@ -9,7 +9,8 @@
  state = {
    confirmDirty: false,
    autoCompleteResult: [],
    level: localStorage.getItem(window.location.href.split('#')[0] + 'pwdlevel') || ''
    level: localStorage.getItem(window.GLOB.sysSign + 'pwdlevel') || '',
    dict: window.GLOB.dict,
  }
  LoginTimer = null
@@ -63,7 +64,7 @@
  compareToFirstPassword = (rule, value, callback) => {
    const { form } = this.props
    if (value && value !== form.getFieldValue('password')) {
      callback('两次输入密码不一致!')
      callback(window.GLOB.dict['pwd_notM'] || '两次输入密码不一致!')
    } else {
      callback()
    }
@@ -71,16 +72,16 @@
  validateToNextPassword = (rule, value, callback) => {
    const { form } = this.props
    const { level } = this.state
    const { level, dict } = this.state
    if (value && this.state.confirmDirty) {
      form.validateFields(['confirm'], { force: true })
    }
    if (level === 'letter_num' && value && /^[0-9a-zA-Z!@#$%^&*()_]*$/.test(value) && /^([^0-9]*|[^a-zA-Z]*)$/.test(value)) {
      callback('密码中必须含有数字和字母。')
      callback(dict['pwd_letter_num'] || '密码中必须包含数字与字母')
    } 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('密码中必须含有数字、字母和特殊字符。')
      callback(dict['pwd_char_num'] || '密码中必须含有数字、字母以及特殊字符')
    } else {
      callback()
    }
@@ -191,12 +192,12 @@
  render() {
    const { type } = this.props
    const { getFieldDecorator } = this.props.form
    const { level, delay, verdisabled } = this.state
    const { level, delay, verdisabled, dict } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 6 }
        sm: { span: 7 }
      },
      wrapperCol: {
        xs: { span: 24 },
@@ -208,38 +209,38 @@
    if (level) {
      rules.push({
        min: 8,
        message: '密码长度不可小于8位!'
        message: dict['pwd_min'] || '密码长度不可小于8位'
      })
    }
    return (
      <>
        {type === 'account' ? <Form {...formItemLayout} onKeyDown={this.onEnterSubmit} id="reset-password-form">
          <Form.Item label="原密码">
          <Form.Item label={dict['ori_pwd'] || '原密码'}>
            {getFieldDecorator('originpwd', {
              rules: [
                {
                  required: true,
                  message: '请输入原密码!'
                  message: dict['oripwd_required'] || '请输入原密码!'
                }
              ]
            })(<Input.Password autoFocus/>)}
          </Form.Item>
          <Form.Item label="新密码" hasFeedback>
          <Form.Item label={dict['new_pwd'] || '新密码'} hasFeedback>
            {getFieldDecorator('password', {
              rules: [
                {
                  required: true,
                  message: '请输入新密码!'
                  message: dict['newpwd_required'] || '请输入新密码!'
                },
                {
                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
                  message: '密码只允许包含数字、字母以及!@#$%&*()_。'
                  message: dict['password_format'] || '密码只允许包含数字、字母以及!@#$%&*()_。'
                },
                ...rules,
                {
                  max: 50,
                  message: '最大密码长度为50位!'
                  message: dict['pwd_max'] || '密码长度不可超过50个字符!'
                },
                {
                  validator: this.validateToNextPassword
@@ -247,12 +248,12 @@
              ]
            })(<Input.Password />)}
          </Form.Item>
          <Form.Item label="确认密码" hasFeedback>
          <Form.Item label={dict['con_pwd'] || '确认密码'} hasFeedback>
            {getFieldDecorator('confirm', {
              rules: [
                {
                  required: true,
                  message: '请确认密码!'
                  message: dict['conpwd_required'] || '请确认密码!'
                },
                {
                  validator: this.compareToFirstPassword
@@ -262,21 +263,21 @@
          </Form.Item>
        </Form> : null}
        {type === 'phonepwd' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
          <Form.Item label="新密码" hasFeedback>
          <Form.Item label={dict['new_pwd'] || '新密码'} hasFeedback>
            {getFieldDecorator('password', {
              rules: [
                {
                  required: true,
                  message: '请输入新密码!'
                  message: dict['newpwd_required'] || '请输入新密码!'
                },
                {
                  pattern: /^[0-9a-zA-Z!@#$%^&*()_]*$/ig,
                  message: '密码只允许包含数字、字母以及!@#$%&*()_。'
                  message: dict['password_format'] || '密码只允许包含数字、字母以及!@#$%&*()_。'
                },
                ...rules,
                {
                  max: 50,
                  message: '最大密码长度为50位!'
                  message: dict['pwd_max'] || '密码长度不可超过50个字符!'
                },
                {
                  validator: this.validateToNextPassword
@@ -284,12 +285,12 @@
              ]
            })(<Input.Password />)}
          </Form.Item>
          <Form.Item label="确认密码" hasFeedback>
          <Form.Item label={dict['con_pwd'] || '确认密码'} hasFeedback>
            {getFieldDecorator('confirm', {
              rules: [
                {
                  required: true,
                  message: '请确认密码!'
                  message: dict['conpwd_required'] || '请确认密码!'
                },
                {
                  validator: this.compareToFirstPassword
@@ -299,16 +300,16 @@
          </Form.Item>
        </Form> : null}
        {type === 'mob' ? <Form {...formItemLayout} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
          <Form.Item label="手机号">
          <Form.Item label={dict['phone_no'] || '手机号'}>
            {getFieldDecorator('phone', {
              initialValue: '',
              rules: [
                {
                  required: true,
                  message: '请输入手机号!'
                  message: dict['phone_no_required'] || '请输入手机号'
                }
              ]
            })(<Input placeholder="请输入手机号" autoComplete="off" />)}
            })(<Input placeholder={dict['phone_no'] || '手机号'} autoComplete="off" />)}
          </Form.Item>
        </Form> : null}
        {type === 'code' ? <Form wrapperCol={{ xs: { span: 24 }, sm: { span: 20 }}} onKeyDown={(e) => e.key === 'Enter' && this.props.resetPwdSubmit()}>
@@ -318,16 +319,16 @@
              rules: [
                {
                  required: true,
                  message: '请输入验证码!'
                  message: dict['vercode_required'] || '请输入验证码'
                }
              ]
            })(<Input
              addonAfter={
                <Button type="link" size="small" disabled={verdisabled} onClick={this.getvercode}>
                  {delay ? `${delay}s后重新获取` : '获取验证码'}
                  {delay ? `${delay}s` : dict['query_vercode'] || '获取验证码'}
                </Button>
              }
              placeholder="请输入验证码"
              placeholder={dict['vercode'] || '验证码'}
              autoComplete="off"
            />)}
          </Form.Item>
src/components/tabview/index.jsx
@@ -19,7 +19,9 @@
const Iframe = asyncComponent(() => import('@/tabviews/iframe'))
const RoleManage = asyncComponent(() => import('@/tabviews/rolemanage'))
moment.locale('zh-cn')
if (sessionStorage.getItem('lang') === 'zh-CN') {
  moment.locale('zh-cn')
}
class TabViews extends Component {
  state = {
@@ -36,7 +38,7 @@
        activeId: 'home_page_id',
        tabviews: [{
          MenuID: 'home_page_id',
          MenuName: '首页',
          MenuName: window.GLOB.dict['home'] || '首页',
          type: 'Home'
        }]
      })
src/index.js
@@ -1,9 +1,12 @@
import React from 'react'
import ReactDOM from 'react-dom'
import { ConfigProvider } from 'antd'
import zhCN from 'antd/es/locale/zh_CN'
import Route from './router'
import md5 from 'md5'
import * as serviceWorker from './serviceWorker'
import options, { styles } from '@/store/options.js'
import options, { styles, langs } from '@/store/options.js'
import '@/assets/css/main.scss'
import '@/assets/css/action.scss'
import '@/assets/css/viewstyle.scss'
@@ -17,13 +20,6 @@
    }
    return uuid.join('')
  })())
}
const render = Component => {
  ReactDOM.render(
    <Component/>,
    document.getElementById('root')
  )
}
fetch('../options.json')
@@ -61,6 +57,11 @@
    GLOB.upStatus = false
    GLOB.navBar = 'shutter' // 默认为百叶窗
    GLOB.style = 'bg_black_style_blue'
    GLOB.defLang = ''
    if (langs[config.defaultLang]) {
      GLOB.defLang = config.defaultLang
    }
    GLOB.sysType = options.sysType
    if (GLOB.sysType !== 'cloud') {
@@ -160,8 +161,39 @@
      }
    }
    let _href = window.location.href.split('#')[0]
    let _systemMsg = localStorage.getItem(_href + 'system')
    if (process.env.NODE_ENV === 'production') { // 用于校验是否存在开发权限
      let _service = window.location.href.replace(/\/admin(.*)/ig, '').replace(new RegExp(document.location.origin + '/?', 'ig'), '')
      GLOB.service = _service ? _service + '/' : ''
      GLOB.host = window.location.host + (_service ? '_' + _service : '')
      GLOB.baseurl = document.location.origin + '/' + GLOB.service
      GLOB.linkurl = GLOB.baseurl + 'index.html'
    } else {
      GLOB.location = config.host
      GLOB.service = config.service
      GLOB.host = config.host.replace(/http(s)?:\/\//ig, '') + (config.service ? '_' + config.service.replace(/\//ig, '') : '')
      GLOB.baseurl = GLOB.location + '/' + GLOB.service
      GLOB.linkurl = GLOB.baseurl + 'index.html'
      GLOB.dataFormat = false
      let mark = sessionStorage.getItem('system_mark')
      let _mark = `sys_${GLOB.service.replace('/', '') || 'service'}`
      if (mark && mark !== _mark) {
        sessionStorage.clear()
      }
      sessionStorage.setItem('system_mark', _mark)
    }
    if (config.mainkey && GLOB.sysType !== 'cloud' && config.mainkey !== options.cakey) {
      GLOB.localkey = GLOB.appkey
      GLOB.appkey = config.mainkey
    }
    let lang = localStorage.getItem(window.location.href.split('#')[0] + 'lang') || GLOB.defLang || 'zh-CN'
    sessionStorage.setItem('lang', lang)
    GLOB.sysSign = GLOB.service + 'admin/' + lang + '/'
    let _systemMsg = localStorage.getItem(GLOB.sysSign + 'system')
    let className = 'mk-blue-black'
    if (_systemMsg) {
@@ -224,38 +256,12 @@
      GLOB.filter = true
    }
    if (process.env.NODE_ENV === 'production') { // 用于校验是否存在开发权限
      let _service = window.location.href.replace(/\/admin(.*)/ig, '').replace(new RegExp(document.location.origin + '/?', 'ig'), '')
      GLOB.service = _service ? _service + '/' : ''
      GLOB.host = window.location.host + (_service ? '_' + _service : '')
      GLOB.baseurl = document.location.origin + '/' + GLOB.service
      GLOB.linkurl = GLOB.baseurl + 'index.html'
    } else {
      GLOB.location = config.host
      GLOB.service = config.service
      GLOB.host = config.host.replace(/http(s)?:\/\//ig, '') + (config.service ? '_' + config.service.replace(/\//ig, '') : '')
      GLOB.baseurl = GLOB.location + '/' + GLOB.service
      GLOB.linkurl = GLOB.baseurl + 'index.html'
      GLOB.dataFormat = false
      let mark = sessionStorage.getItem('system_mark')
      let _mark = `sys_${GLOB.service.replace('/', '') || 'service'}`
      if (mark && mark !== _mark) {
        sessionStorage.clear()
      }
      sessionStorage.setItem('system_mark', _mark)
    if (lang !== 'zh-CN') {
      GLOB.WXNotice = false
    }
    if (config.mainkey && GLOB.sysType !== 'cloud' && config.mainkey !== options.cakey) {
      GLOB.localkey = GLOB.appkey
      GLOB.appkey = config.mainkey
    }
    let lang = localStorage.getItem(_href + 'lang') || (config.defaultLang !== 'en-US' ? 'zh-CN' : 'en-US')
    sessionStorage.setItem('lang', lang)
    if (localStorage.getItem(_href + 'files') === md5(_href + 'files')) {
      let d = localStorage.getItem(_href + 'filesDate')
    if (localStorage.getItem(GLOB.sysSign + 'files') === md5(GLOB.sysSign + 'files')) {
      let d = localStorage.getItem(GLOB.sysSign + 'filesDate')
      GLOB.storeFiles = true
      GLOB.storeDate = Math.ceil((new Date(d).getTime() - new Date().getTime()) / 86400000)
@@ -277,6 +283,17 @@
        d = d.slice(0, 4) + '-' + d.slice(4, 6) + '-' + d.slice(6)
        GLOB.storeDate = Math.ceil((new Date(d).getTime() - new Date().getTime()) / 86400000)
      }
    }
    GLOB.dict = {}
    if (localStorage.getItem(GLOB.sysSign + 'js_trans')) {
      let js_trans = JSON.parse(localStorage.getItem(GLOB.sysSign + 'js_trans'))
      js_trans.forEach(item => {
        if (lang !== item.lang) return
        GLOB.dict[item.key] = item.val
      })
    }
    GLOB.mkActions = {}  // 按钮权限集
@@ -348,7 +365,20 @@
    window.GLOB.SyncData = new Map()     // 存储同步查询数据
    window.GLOB.mkThdMenus = new Map()   // 三级菜单
    render(Route)
    if (lang === 'zh-CN' || !/#\/(login|main|billprint|docprint|tab|iframe|view|ssologin)/.test(window.location.href)) { // 开发使用中文
      ReactDOM.render(
        <ConfigProvider locale={zhCN}>
          <Route/>
        </ConfigProvider>,
        document.getElementById('root')
      )
    } else {
      ReactDOM.render(
        <Route/>,
        document.getElementById('root')
      )
    }
  })
serviceWorker.unregister()
src/locales/en-US/login.js
File was deleted
src/locales/zh-CN/login.js
File was deleted
src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -58,7 +58,7 @@
    try {
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, Radio, Tooltip, InputNumber, Cascader, Popover, message, AutoComplete } from 'antd'
import { Form, Row, Col, Input, Select, Radio, Checkbox, Tooltip, InputNumber, Cascader, Popover, message, AutoComplete } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { formRule } from '@/utils/option.js'
@@ -228,7 +228,7 @@
      }
    } else if (this.record.eleType === 'formula') {
      if (this.record.eval !== 'func') {
        _options.push('prefix', 'postfix', 'fixStyle', 'alignItems')
        _options.push('prefix', 'postfix', 'fixStyle', 'alignItems', 'evalchars')
      }
      if (this.record.eval === 'true') {
        _options.push('decimal')
@@ -578,6 +578,24 @@
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'checkbox') {
        fields.push(
          <Col span={12} key={index}>
            <Form.Item label={label}>
              {getFieldDecorator(item.key, {
                initialValue: item.initVal,
                rules: [{
                  required: item.required,
                  message: '请选择' + item.label + '!'
                }]
              })(
                <Checkbox.Group style={{whiteSpace: 'nowrap'}}>
                  {item.options.map(option => <Checkbox key={option.value} value={option.value}>{option.text}</Checkbox>)}
                </Checkbox.Group>
              )}
            </Form.Item>
          </Col>
        )
      } else if (item.type === 'color') {
        fields.push(
          <Col span={12} key={index} className="color-form">
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -695,6 +695,21 @@
      required: true
    },
    {
      type: 'checkbox',
      key: 'evalchars',
      label: '替换字符',
      initVal: card.evalchars || ['enter', 'space'],
      tooltip: '公式解析后,可替换回车、空格等字符,实现换行、字间距控制等页面效果。',
      required: false,
      options: [{
        value: 'enter',
        text: '回车符'
      }, {
        value: 'space',
        text: '空格'
      }]
    },
    {
      type: 'radio',
      key: 'noValue',
      label: '空值',
src/menu/components/card/data-card/options.jsx
@@ -209,8 +209,21 @@
      controlFields: subtype !== 'propcard' ? [
        {field: 'printHeight', values: ['flex']},
        {field: 'cardFloat', values: ['grid']},
        {field: 'zHeight', values: ['grid']},
      ] : [{field: 'cardFloat', values: ['grid']}],
      forbid: subtype === 'tablecard'
    },
    {
      type: 'number',
      field: 'zHeight',
      label: '最大高度',
      initval: wrap.zHeight || '',
      tooltip: '卡片内容区的最大高度(不包含标题、翻页等元素),添加高度后组件中第一个属性卡将固定于头部。注:小于等于100大于0时为高度的百分比,小于0时为窗口高度减去此值。',
      min: -1000,
      max: 3000,
      precision: 0,
      required: false,
      forbid: subtype !== 'datacard' || appType === 'mob'
    },
    {
      type: 'radio',
@@ -565,6 +578,7 @@
      tooltip: '用于控制行数据是否可选择。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns,
      controlFields: [
        {field: 'controlVal', notNull: true},
src/menu/components/card/double-data-card/options.jsx
@@ -61,6 +61,18 @@
      required: true
    },
    {
      type: 'number',
      field: 'zHeight',
      label: '最大高度',
      initval: wrap.zHeight || '',
      tooltip: '卡片内容区的最大高度(不包含标题、翻页等元素),添加高度后组件中第一个属性卡将固定于头部。注:小于等于100大于0时为高度的百分比,小于0时为窗口高度减去此值。',
      min: -1000,
      max: 3000,
      precision: 0,
      required: false,
      forbid: appType === 'mob'
    },
    {
      type: 'radio',
      field: 'pagestyle',
      label: '分页风格',
@@ -170,6 +182,7 @@
      tooltip: '用于控制行数据是否可选择。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns,
      controlFields: [
        {field: 'controlVal', notNull: true},
@@ -203,26 +216,14 @@
      tooltip: '设置卡片区域的最小宽度,显示区域小于此值将出现横向滚动。',
      required: false
    },
    {
      type: 'number',
      field: 'zHeight',
      label: '高度',
      min: 10,
      max: 5000,
      precision: 0,
      initval: wrap.zHeight,
      tooltip: '卡片区域高度,内容超出时纵向滚动。注:小于等于100时为高度的百分比,第一个扩展属性卡将定位在顶部。',
      required: false,
      forbid: appType === 'mob'
    },
    {
      type: 'color',
      field: 'zBColor',
      label: '边框颜色',
      initval: wrap.zBColor || 'transparent',
      tooltip: '卡片区域设置高度或最小宽度时,滚动区域边框的颜色。',
      required: false
    },
    // {
    //   type: 'color',
    //   field: 'zBColor',
    //   label: '边框颜色',
    //   initval: wrap.zBColor || 'transparent',
    //   tooltip: '卡片区域设置高度或最小宽度时,滚动区域边框的颜色。',
    //   required: false
    // },
    {
      type: 'radio',
      field: 'permission',
src/menu/components/form/formaction/actionform/index.jsx
@@ -105,9 +105,9 @@
        shows.push('innerFunc')
      } else {
        shows.push('sql', 'sqlType')
        if (this.record.execSuccess === 'never' && this.record.resetForms && this.record.resetForms[0]) {
          shows.push('returnValue')
        }
        // if (this.record.execSuccess === 'never' && this.record.resetForms && this.record.resetForms[0]) {
        //   shows.push('returnValue')
        // }
      }
      
      if (this.record.linkmenu && this.record.linkmenu !== 'goback') {
@@ -170,7 +170,6 @@
  getFields() {
    const { getFieldDecorator } = this.props.form
    const { interType, callbackType } = this.state
    const fields = []
    this.state.formlist.forEach((item, index) => {
@@ -206,7 +205,7 @@
            message: formRule.func.maxMessage
          }]
        } else if (item.key === 'output') {
          if (interType === 'system' || ((interType === 'outer' || interType === 'custom') && callbackType === 'script')) {
          if (this.record.intertype === 'system' || ((this.record.intertype === 'outer' || this.record.intertype === 'custom') && this.record.callbackType === 'script')) {
            _rules = [{
              pattern: /^@[0-9a-zA-Z_]+@?$/,
              message: '变量以@符开头,可使用字母、数字以及_'
@@ -373,8 +372,12 @@
          if (values.outerBlacklist) {
            values.outerBlacklist = values.outerBlacklist.replace(/\s/ig, '')
          }
          if (values.resetForms && values.resetForms.length === 0) {
            values.resetForms = null
          if (values.resetForms) {
            if (values.resetForms.length === 0) {
              values.resetForms = null
            } else {
              values.returnValue = 'true'
            }
          }
          resolve(values)
        } else {
src/menu/components/form/formaction/formconfig.jsx
@@ -429,6 +429,7 @@
      key: 'execSuccess',
      label: '成功后',
      initVal: card.execSuccess || 'grid',
      tooltip: '如需聚焦表单请以 @focus:聚焦字段@ 格式返回。',
      required: true,
      options: [{
        value: 'never',
@@ -449,7 +450,7 @@
      key: 'refreshTab',
      label: '刷新菜单',
      initVal: card.refreshTab || [],
      tooltip: '执行成功后(或功能按钮中标签关闭类型),需要同步刷新的菜单',
      tooltip: '执行成功后(或执行失败且存在刷新项时),需要同步刷新的菜单',
      required: false,
      forbid: appType === 'pc' || appType === 'mob' || viewType === 'popview',
      options: menulist
@@ -490,7 +491,7 @@
      key: 'syncComponent',
      label: '同步刷新',
      initVal: card.syncComponent,
      tooltip: '执行成功后需要刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      tooltip: '执行成功后(或执行失败且存在刷新项时)需要刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      required: false,
      options: modules
    },
@@ -532,20 +533,20 @@
      mode: 'multiple',
      options: resets
    },
    {
      type: 'radio',
      key: 'returnValue',
      label: '更新表单',
      initVal: card.returnValue || 'false',
      tooltip: '与重置表单配合使用,开启时,必须在自定义脚本中返回数据,用于替换字段集和填充表单。',
      options: [{
        value: 'false',
        text: '禁用'
      }, {
        value: 'true',
        text: '启用'
      }]
    },
    // {
    //   type: 'radio',
    //   key: 'returnValue',
    //   label: '更新表单',
    //   initVal: card.returnValue || 'false',
    //   tooltip: '与重置表单配合使用,开启时,必须在自定义脚本中返回数据,用于替换字段集和填充表单。',
    //   options: [{
    //     value: 'false',
    //     text: '禁用'
    //   }, {
    //     value: 'true',
    //     text: '启用'
    //   }]
    // },
    {
      type: 'radio',
      key: 'reload',
src/menu/components/form/formaction/index.jsx
@@ -226,7 +226,7 @@
            <ProfileOutlined className="profile" title="setting" onClick={() => this.profileAction()} />
          </div>
        } trigger="hover">
          <Button type="link" className="submit mk-primary" onDoubleClick={this.changeMenu} style={resetStyle(group.subButton.style)}>{group.subButton.label}</Button>
          <Button type="link" className="submit" onDoubleClick={this.changeMenu} style={resetStyle(group.subButton.style)}>{group.subButton.label}</Button>
        </Popover>
        {group.resetButton && group.resetButton.enable === 'true' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
src/menu/components/form/simple-form/index.jsx
@@ -7,7 +7,7 @@
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { getModalForm } from '@/templates/zshare/formconfig'
import { resetStyle, getTables, checkComponent } from '@/utils/utils-custom.js'
import { resetStyle, getTables, checkComponent, getInterfaces } from '@/utils/utils-custom.js'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
import getWrapForm from './options'
@@ -340,6 +340,8 @@
    card.subcards[0].fields = card.subcards[0].fields.filter(item => !item.focus)
    this.setState({card, visible: false, editform: null})
    this.updateComponent(card)
  }
  /**
@@ -466,9 +468,9 @@
        _card.setting.supModule = ''
      }
    } else if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let interfaces = getInterfaces()
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      let d = interfaces.filter(m => m.value === res.publicId)[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
src/menu/components/form/simple-form/options.jsx
@@ -1,4 +1,4 @@
import MenuUtils from '@/utils/utils-custom.js'
import MenuUtils, { getInterfaces } from '@/utils/utils-custom.js'
/**
 * @description Wrap表单配置信息
@@ -45,18 +45,7 @@
    }
  }
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  }
  let interfaces = getInterfaces()
  let buttons = []
  if (!wrap.enable || wrap.enable === 'true') {
src/menu/components/module/invoice/verifycard/callbackcustomscript/index.jsx
@@ -253,7 +253,6 @@
                filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                onChange={this.selectScript}
              >
                <Select.Option key="default" value="defaultSql">默认sql</Select.Option>
                {systemScripts.map((option, i) =>
                  <Select.Option key={i} value={option.value}>{option.name}</Select.Option>
                )}
src/menu/components/search/main-search/dragsearch/index.jsx
@@ -52,7 +52,7 @@
    try {
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/menu/components/search/main-search/index.jsx
@@ -250,7 +250,7 @@
        return
      }
      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && res.database !== 'sso' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
@@ -258,13 +258,8 @@
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '')
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        
        Api.sDebug(sql, rduri).then(result => {
        Api.sDebug(sql).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
@@ -381,7 +376,7 @@
    let _style = resetStyle(card.style)
    return (
      <div className={`main-search-edit-list ${card.wrap.float} ${showField ? 'show-field' : ''}`} onClick={this.clickComponent} id={card.uuid} style={_style}>
      <div className={`main-search-edit-list ${card.wrap.float} ${showField ? 'show-field' : ''} mk-size-${card.wrap.searchSize || ''}`} onClick={this.clickComponent} id={card.uuid} style={_style}>
        <FieldsComponent config={card} type="search" />
        <Switch checkedChildren="开" size="small" unCheckedChildren="关" defaultChecked={showField} onChange={this.onFieldChange} />
        <DragElement
@@ -422,7 +417,7 @@
          title="搜索条件-编辑"
          wrapClassName="mk-scroll-modal"
          visible={visible}
          width={850}
          width={950}
          maskClosable={false}
          onOk={this.handleSubmit}
          confirmLoading={sqlVerifing}
src/menu/components/search/main-search/index.scss
@@ -153,6 +153,17 @@
  }
}
.main-search-edit-list.mk-size-small {
  .page-card {
    height: 45px;
  }
  .mk-search-item-wrap.action {
    .ant-form-item {
      height: 45px!important;
    }
  }
}
.main-search-edit-list:not(.show-field) {
  .ant-form-explain {
    display: none;
src/menu/components/search/main-search/options.jsx
@@ -160,6 +160,18 @@
    },
    {
      type: 'radio',
      field: 'searchSize',
      label: '搜索间距',
      initval: wrap.searchSize || 'middle',
      tooltip: '搜索条件的上下间距。',
      required: false,
      options: [
        {value: 'middle', label: '默认'},
        {value: 'small', label: '小'},
      ],
    },
    {
      type: 'radio',
      field: 'cacheSearch',
      label: '搜索缓存',
      initval: wrap.cacheSearch || 'false',
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -221,7 +221,7 @@
        }
        reRequired.innerFunc = true
      } else {
        shows.push('sql', 'sqlType', 'output')
        shows.push('sql', 'sqlType', 'output', 'database')
      }
      if (Ot === 'required') {
@@ -299,7 +299,7 @@
        shows.push('innerFunc', 'extraParam')
        reRequired.innerFunc = true
      } else {
        shows.push('sql', 'sqlType')
        shows.push('sql', 'sqlType', 'database')
      }
      if (this.record.execSuccess === 'goback') {
@@ -349,6 +349,8 @@
      } else if (this.record.intertype === 'inner') {
        shows.push('innerFunc', 'extraParam')
        reRequired.innerFunc = true
      } else {
        shows.push('database')
      }
      if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
        shows.push('resetPageIndex')
@@ -384,6 +386,8 @@
      } else if (this.record.intertype === 'inner') {
        shows.push('innerFunc', 'extraParam')
        reRequired.innerFunc = true
      } else {
        shows.push('database')
      }
      if (this.record.execSuccess === 'grid' || this.record.execError === 'grid') {
        shows.push('resetPageIndex')
src/menu/components/share/actioncomponent/dragaction/index.jsx
@@ -74,7 +74,7 @@
    try {
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -26,6 +26,10 @@
    type = 'chart'
  }
  if (card.color && (type !== 'datacard' || appType !== 'mob') && !card.class) {
    card.class = 'primary'
  }
  let opentypes = [
    {
      value: 'pop',
@@ -711,7 +715,7 @@
      key: 'execSuccess',
      label: '成功后',
      initVal: card.execSuccess || 'grid',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮(弹窗按钮)中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮(弹窗按钮)中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需聚焦表单请以 @focus:聚焦字段@ 格式返回。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需聚焦表单请以 @focus:聚焦字段@ 格式返回。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      required: true,
      options: [{
        value: 'never',
@@ -975,7 +979,7 @@
      key: 'syncComponent',
      label: '刷新组件',
      initVal: card.syncComponent || [],
      tooltip: '执行成功后(或弹窗标签关闭时),需要同步刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      tooltip: '执行成功后(执行失败且存在刷新项、弹窗标签关闭),需要同步刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      required: false,
      options: modules.length ? [...modules, {value: 'multiComponent', label: '多组件'}] : []
    },
@@ -1015,7 +1019,7 @@
      key: 'refreshTab',
      label: '刷新菜单',
      initVal: card.refreshTab || [],
      tooltip: '执行成功后(或功能按钮中标签关闭类型),需要同步刷新的菜单',
      tooltip: '执行成功后(或执行失败且存在刷新项时),需要同步刷新的菜单',
      required: false,
      forbid: isApp || viewType === 'popview',
      options: menulist
@@ -1363,6 +1367,19 @@
      }, {
        value: 'true',
        text: '是'
      }]
    },
    {
      type: 'radio',
      key: 'database',
      label: '数据库',
      initVal: card.database || 'local',
      options: [{
        value: 'local',
        text: '本地'
      }, {
        value: 'sso',
        text: '单点'
      }]
    },
    {
@@ -2064,7 +2081,7 @@
      key: 'execSuccess',
      label: '成功后',
      initVal: card.execSuccess || 'grid',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮(弹窗按钮)中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      tooltip: refresh.length ? '执行刷新源组件时,请在源按钮(弹窗按钮)中设置关闭后刷新那一项,注:此时会同步刷新当前组件和上级组件-行。如需聚焦表单请以 @focus:聚焦字段@ 格式返回。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。' : '选择刷新行时,如果选择多条数据会刷新组件;选择刷新行 / 组件时,如果当前行数据不存在会刷新组件。注:上级组件在数据源中添加。如需聚焦表单请以 @focus:聚焦字段@ 格式返回。如需语音播报请以@speak@开头,播报内容或文件放置于<<>>中。返回信息(@retmsg)特殊标识:@close_tab@ 执行(关闭标签-管理系统);@close_popup@ 执行(关闭弹窗);@goback@ 执行(返回上一页-子应用);@no_target_menu@ 不执行打开菜单。',
      required: true,
      options: [{
        value: 'never',
@@ -2276,7 +2293,7 @@
      key: 'syncComponent',
      label: '刷新组件',
      initVal: card.syncComponent || [],
      tooltip: '执行成功后(或弹窗标签关闭时),需要同步刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      tooltip: '执行成功后(执行失败且存在刷新项、弹窗标签关闭),需要同步刷新的组件。注:选择当前组件的上级组件无效,刷新上级组件请选择成功后“刷新上级组件 - 行”。',
      required: false,
      options: modules.length ? [...modules, {value: 'multiComponent', label: '多组件'}] : []
    },
@@ -2314,7 +2331,7 @@
      key: 'refreshTab',
      label: '刷新菜单',
      initVal: card.refreshTab || [],
      tooltip: '执行成功后(或功能按钮中标签关闭类型),需要同步刷新的菜单',
      tooltip: '执行成功后(或执行失败且存在刷新项时),需要同步刷新的菜单',
      required: false,
      forbid: viewType === 'popview',
      options: menulist
@@ -2558,6 +2575,19 @@
    },
    {
      type: 'radio',
      key: 'database',
      label: '数据库',
      initVal: card.database || 'local',
      options: [{
        value: 'local',
        text: '本地'
      }, {
        value: 'sso',
        text: '单点'
      }]
    },
    {
      type: 'radio',
      key: 'permission',
      label: '权限验证',
      initVal: card.permission || 'true',
src/menu/components/share/actioncomponent/index.jsx
@@ -162,6 +162,8 @@
  addButton = (cardId, element) => {
    if (cardId !== this.props.config.uuid) return
    delete element.eleType
    const { actionlist } = this.state
    this.setState({actionlist: [...actionlist, element]})
src/menu/components/share/copycomponent/index.jsx
@@ -19,7 +19,7 @@
    try {
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/menu/components/share/searchcomponent/dragsearch/index.jsx
@@ -46,7 +46,7 @@
    try {
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/menu/components/share/searchcomponent/index.jsx
@@ -205,7 +205,7 @@
        return
      }
      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['select', 'multiselect', 'link', 'checkcard'].includes(res.type) && res.resourceType === '1' && res.database !== 'sso' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
@@ -213,13 +213,8 @@
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '')
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        
        Api.sDebug(sql, rduri).then(result => {
        Api.sDebug(sql).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
@@ -286,7 +281,7 @@
        <Modal
          title="搜索条件-编辑"
          visible={visible}
          width={850}
          width={950}
          maskClosable={false}
          onOk={this.handleSubmit}
          confirmLoading={sqlVerifing}
src/menu/components/table/base-table/columns/editColumn/formconfig.jsx
@@ -442,6 +442,21 @@
      required: true
    },
    {
      type: 'checkbox',
      key: 'evalchars',
      label: '替换字符',
      initVal: card.evalchars || ['enter', 'space'],
      tooltip: '公式解析后,可替换回车、空格等字符,实现换行、字间距控制等页面效果。',
      required: false,
      options: [{
        value: 'enter',
        text: '回车符'
      }, {
        value: 'space',
        text: '空格'
      }]
    },
    {
      type: 'radio',
      key: 'noValue',
      label: '空值',
src/menu/components/table/base-table/columns/editColumn/index.jsx
@@ -95,8 +95,13 @@
      } else if (this.record.perspective === 'linkurl') {
        _options.push('linkurl', 'open')
      }
    } else if (this.record.type === 'formula' && this.record.eval === 'true') {
      _options.push('decimal')
    } else if (this.record.type === 'formula') {
      if (this.record.eval === 'true') {
        _options.push('decimal')
      }
      if (this.record.eval !== 'func') {
        _options.push('evalchars')
      }
    } else if (this.record.type === 'custom' && this.record.IsSort === 'true') {
      _options.push('sortField')
    }
src/menu/components/table/base-table/columns/index.jsx
@@ -193,10 +193,10 @@
        val = '$Index'
      } else if (column.type === 'formula') {
        val = column.formula
        if (column.eval === 'false') {
          val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
          val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        }
        // if (column.eval === 'false') {
        //   val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        //   val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        // }
      }
      return (
        <td style={{...style}} className={className}>
@@ -549,7 +549,7 @@
      cols: columns.filter(col => !col.origin)
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/menu/components/table/base-table/options.jsx
@@ -76,6 +76,18 @@
        {value: 'mini', label: '迷你'},
      ]
    },
    {
      type: 'radio',
      field: 'searchSize',
      label: '搜索间距',
      initval: wrap.searchSize || 'middle',
      tooltip: '搜索条件的上下间距。',
      required: false,
      options: [
        {value: 'middle', label: '默认'},
        {value: 'small', label: '小'},
      ],
    },
    // {
    //   type: 'radio',
    //   field: 'selected',
@@ -151,10 +163,10 @@
    {
      type: 'number',
      field: 'height',
      label: '表格高度',
      label: '最大高度',
      initval: wrap.height || '',
      tooltip: '表格高度,空值时高度自适应。注:小于等于100时为高度的百分比。',
      min: 10,
      tooltip: '表格内容区的最大高度(不包含表头),空值时高度自适应。注:小于等于100大于0时为高度的百分比,小于0时为窗口高度减去此值。',
      min: -1000,
      max: 3000,
      precision: 0,
      required: false,
@@ -186,6 +198,7 @@
      tooltip: '鼠标悬浮于行上方时的提示信息。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns
    },
    {
@@ -196,6 +209,7 @@
      tooltip: '用于控制行数据是否可选择。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns,
      controlFields: [
        {field: 'controlVal', notNull: true},
src/menu/components/table/edit-table/columns/editColumn/formconfig.jsx
@@ -446,7 +446,7 @@
      key: 'dataSource',
      label: '数据源',
      initVal: card.dataSource || '',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值@BID@。',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@BID@、@Appkey@、@UserID@、@SessionUid@、@LoginUID@、@lang@。',
      required: true,
    },
    {
@@ -562,6 +562,7 @@
      tooltip: '用于控制行数据是否可选择。字段值为true时,选项不可选。',
      required: false,
      allowClear: true,
      joint: true,
      options: 'columns'
    },
    {
@@ -694,7 +695,7 @@
        text: '本地'
      }, {
        value: 'sso',
        text: '系统'
        text: '单点'
      }]
    },
    {
@@ -831,6 +832,21 @@
      options: fields
    },
    {
      type: 'checkbox',
      key: 'evalchars',
      label: '替换字符',
      initVal: card.evalchars || ['enter', 'space'],
      tooltip: '公式解析后,可替换回车、空格等字符,实现换行、字间距控制等页面效果。',
      required: false,
      options: [{
        value: 'enter',
        text: '回车符'
      }, {
        value: 'space',
        text: '空格'
      }]
    },
    {
      type: 'radio',
      key: 'noValue',
      label: '空值',
src/menu/components/table/edit-table/columns/editColumn/index.jsx
@@ -1,7 +1,7 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, InputNumber, Radio, Tooltip, Modal, notification, Popover } from 'antd'
import { Form, Row, Col, Input, Select, InputNumber, Radio, Checkbox, Tooltip, Modal, notification, Popover } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import Api from '@/api'
@@ -107,8 +107,13 @@
        _options.push('hourFormat')
      }
    }
    if (this.record.type === 'formula' && this.record.eval === 'true') {
      _options.push('decimal')
    if (this.record.type === 'formula') {
      if (this.record.eval === 'true') {
        _options.push('decimal')
      }
      if (this.record.eval !== 'func') {
        _options.push('evalchars')
      }
    } else if (this.record.type === 'custom' && this.record.IsSort === 'true') {
      _options.push('sortField')
    }
@@ -402,6 +407,15 @@
        content = <Radio.Group onChange={(e) => {this.typeChange(item.key, e.target.value)}}>
          {item.options.map(option => <Radio key={option.value} value={option.value}>{option.text}</Radio>)}
        </Radio.Group>
      } else if (item.type === 'checkbox') {
        rules = [
          { required: item.required, message: '请选择' + item.label + '!' }
        ]
        initVal = item.initVal
        content = <Checkbox.Group onChange={(e) => {this.typeChange(item.key, e.target.value)}}>
          {item.options.map(option => <Checkbox key={option.value} value={option.value}>{option.text}</Checkbox>)}
        </Checkbox.Group>
      } else if (item.type === 'multiselect') { // 多选
        content = <Select
          showSearch
@@ -447,6 +461,7 @@
          extra = <span className="add-resource-empty" onClick={this.handleEmpty}>空</span>
        }
        if (item.placeholder) {
          className = 'show-public-var'
          extra = <><span className="resource-public-var">{item.placeholder}</span>{extra}</>
        }
@@ -580,7 +595,7 @@
          if (!pass) return
        }
        if (values.editType === 'select' && values.resourceType === '1' && values.dataSource) {
        if (values.editType === 'select' && values.resourceType === '1' && values.database !== 'sso' && values.dataSource) {
          let _option = Utils.getSelectQueryOptions(values)
          let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
@@ -588,13 +603,8 @@
  
          // LoginUID|SessionUid|UserID|Appkey 已替换
          sql = sql.replace(/@\$|\$@/ig, '')
          let rduri = ''
          if (window.GLOB.mainSystemApi && values.database === 'sso') {
            rduri = window.GLOB.mainSystemApi
          }
          
          Api.sDebug(sql, rduri).then(result => {
          Api.sDebug(sql).then(result => {
            if (result.status || result.ErrCode === '-2') {
              this.setState({visible: false, loading: false, formlist: null})
              this.props.submitCol(values)
@@ -692,7 +702,7 @@
          title="显示列编辑"
          wrapClassName="mk-scroll-modal"
          visible={visible}
          width={900}
          width={950}
          maskClosable={false}
          onOk={this.handleSubmit}
          onCancel={this.editModalCancel}
src/menu/components/table/edit-table/columns/editColumn/index.scss
@@ -44,11 +44,16 @@
    cursor: pointer;
    font-size: 14px;
  }
  .show-public-var {
    margin-top: 20px;
  }
  .resource-public-var {
    position: absolute;
    left: 0px;
    top: -25px;
    font-size: 14px;
    top: -45px;
    right: 40px;
    font-size: 13px;
    color: rgba(0, 0, 0, 0.65);
  }
}
.formula-fields {
src/menu/components/table/edit-table/columns/index.jsx
@@ -47,7 +47,7 @@
      cols: [column]
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
@@ -195,10 +195,10 @@
        val = '$Index'
      } else if (column.type === 'formula') {
        val = column.formula
        if (column.eval === 'false') {
          val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
          val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        }
        // if (column.eval === 'false') {
        //   val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        //   val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        // }
      }
      return (
        <td style={style} className={className}>
@@ -553,7 +553,7 @@
      cols: columns.filter(col => !col.origin)
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/menu/components/table/edit-table/columns/tableIn/customscript/index.jsx
@@ -271,7 +271,7 @@
          </Col> : null}
          {!type ? <Col span={24} className="sqlfield">
            <Form.Item label="可用字段">
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, 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},data_type(注:jskey为主键值,新增时前端生成;data_type为操作类型,新增 - add、修改 - upt、删除 - del)
            </Form.Item>
src/menu/components/table/edit-table/options.jsx
@@ -45,10 +45,10 @@
    {
      type: 'number',
      field: 'height',
      label: '高度',
      label: '最大高度',
      initval: wrap.height || '',
      tooltip: '表格高度,空值时高度自适应。注:小于等于100时为高度的百分比。',
      min: 10,
      tooltip: '表格内容区的最大高度(不包含表头),空值时高度自适应。注:小于等于100大于0时为高度的百分比,小于0时为窗口高度减去此值。',
      min: -1000,
      max: 3000,
      precision: 0,
      required: false
@@ -127,6 +127,18 @@
        {value: 'small', label: '小'},
        // {value: 'mini', label: '迷你'},
      ]
    },
    {
      type: 'radio',
      field: 'searchSize',
      label: '搜索间距',
      initval: wrap.searchSize || 'middle',
      tooltip: '搜索条件的上下间距。',
      required: false,
      options: [
        {value: 'middle', label: '默认'},
        {value: 'small', label: '小'},
      ],
    },
    {
      type: 'radio',
@@ -225,6 +237,7 @@
      tooltip: '鼠标悬浮于行上方时的提示信息。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns
    },
    {
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -513,6 +513,21 @@
      required: true
    },
    {
      type: 'checkbox',
      key: 'evalchars',
      label: '替换字符',
      initVal: card.evalchars || ['enter', 'space'],
      tooltip: '公式解析后,可替换回车、空格等字符,实现换行、字间距控制等页面效果。',
      required: false,
      options: [{
        value: 'enter',
        text: '回车符'
      }, {
        value: 'space',
        text: '空格'
      }]
    },
    {
      type: 'radio',
      key: 'noValue',
      label: '空值',
src/menu/components/table/normal-table/columns/editColumn/index.jsx
@@ -94,8 +94,13 @@
      } else if (this.record.perspective === 'linkurl') {
        _options.push('linkurl', 'open')
      }
    } else if (this.record.type === 'formula' && this.record.eval === 'true') {
      _options.push('decimal')
    } else if (this.record.type === 'formula') {
      if (this.record.eval === 'true') {
        _options.push('decimal')
      }
      if (this.record.eval !== 'func') {
        _options.push('evalchars')
      }
    } else if (this.record.type === 'custom' && this.record.IsSort === 'true') {
      _options.push('sortField')
    } else if (this.record.type === 'extend') {
src/menu/components/table/normal-table/columns/index.jsx
@@ -47,7 +47,7 @@
      cols: [column]
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
@@ -195,10 +195,10 @@
        val = '$Index'
      } else if (column.type === 'formula') {
        val = column.formula
        if (column.eval === 'false') {
          val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
          val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        }
        // if (column.eval === 'false') {
        //   val = val.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        //   val = <span style={{fontWeight: 'inherit'}} dangerouslySetInnerHTML={{__html: val}}></span>
        // }
      }
      return (
        <td style={{...style}} className={className}>
@@ -518,7 +518,7 @@
      cols: columns.filter(col => !col.origin)
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/menu/components/table/normal-table/options.jsx
@@ -52,10 +52,10 @@
    {
      type: 'number',
      field: 'height',
      label: '高度',
      label: '最大高度',
      initval: wrap.height || '',
      tooltip: '表格高度,空值时高度自适应。注:小于等于100时为高度的百分比。',
      min: 10,
      tooltip: '表格内容区的最大高度(不包含表头),空值时高度自适应。注:小于等于100大于0时为高度的百分比,小于0时为窗口高度减去此值。',
      min: -1000,
      max: 3000,
      precision: 0,
      required: false,
@@ -161,6 +161,19 @@
    },
    {
      type: 'radio',
      field: 'searchSize',
      label: '搜索间距',
      initval: wrap.searchSize || 'middle',
      tooltip: '搜索条件的上下间距。',
      required: false,
      options: [
        {value: 'middle', label: '默认'},
        {value: 'small', label: '小'},
      ],
      forbid: appType === 'mob'
    },
    {
      type: 'radio',
      field: 'mode',
      label: '模式',
      initval: wrap.mode || 'default',
@@ -233,6 +246,7 @@
      tooltip: '鼠标悬浮于行上方时的提示信息。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns
    },
    {
@@ -243,6 +257,7 @@
      tooltip: '用于控制行数据是否可选择。',
      required: false,
      allowClear: true,
      joint: true,
      options: columns,
      controlFields: [
        {field: 'controlVal', notNull: true},
src/menu/datasource/verifycard/customscript/index.jsx
@@ -243,9 +243,9 @@
          </Col>
          <Col span={24}>
            <Form.Item label="可用字段" className="field-able">
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename, datam</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'排序、分页以及搜索条件变量,请按照@xxx@格式使用。使用@pageSize@或@orderBy@代表自定义分页,总数请以mk_total返回。'}>orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}{type === 'calendar' ? ', mk_year' : ''}{hasExtend ? ', mk_time' : ''}</Tooltip>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'排序、分页以及搜索条件变量,请按照@xxx@格式使用。使用@pageSize@、@orderBy@ 或脚本中存在 @mk_total 代表自定义分页,总数请以mk_total返回。'}>orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}{type === 'calendar' ? ', mk_year' : ''}{hasExtend ? ', mk_time' : ''}</Tooltip>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'url变量,请按照@xxx@格式使用。'}>{urlFields ? ', ' : ''}<span style={{color: '#13c2c2'}}>{urlFields}</span></Tooltip>
              {window.GLOB.process ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'工作流变量,请按照@xxx@格式使用。'}>, <span style={{color: 'purple'}}>works_flow_code</span></Tooltip> : null}
            </Form.Item>
src/menu/datasource/verifycard/index.jsx
@@ -4,7 +4,6 @@
import { Form, Tabs, Popconfirm, notification, Modal, Typography, Spin, message, Button, Input } from 'antd'
import { StopOutlined, CheckCircleOutlined, TableOutlined, EditOutlined, SwapOutlined, DeleteOutlined, CopyOutlined, BorderOutlined, SnippetsOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -683,8 +682,6 @@
      let r = SettingUtils.getDebugSql(setting, _scripts, _columns, searches, config.subtype, config.hasExtend)
      let _debugId = md5(r.sql)
      if (r.custompage && setting.laypage === 'true' && _columns.findIndex(col => col.field === 'mk_total') === -1) {
        if (config.subtype !== 'basetable') {
          Modal.warning({
@@ -704,7 +701,7 @@
        }
      }
      if (debugId === _debugId) {
      if (debugId === r.debugId) {
        resolve()
        return
      }
@@ -719,7 +716,7 @@
      Api.sDebug(r.sql).then(result => {
        if (result.status || result.ErrCode === '-2') {
          this.setState({debugId: _debugId}, () => {
          this.setState({debugId: r.debugId}, () => {
            resolve()
          })
        } else {
src/menu/datasource/verifycard/settingform/index.jsx
@@ -105,6 +105,9 @@
          if (values.interType === 'system' && values.onload === 'false') {
            values.sync = 'false'
          }
          if (values.interType === 'system' && values.database === 'sso') {
            values.sync = 'false'
          }
          // 数据源前端验证
          if (values.interType === 'system' && values.execute !== 'false' && values.dataresource) {
@@ -515,6 +518,17 @@
                </Radio.Group>)}
              </Form.Item>
            </Col> : null}
            {setting.interType === 'system' ? <Col span={8}>
              <Form.Item label="数据库">
                {getFieldDecorator('database', {
                  initialValue: setting.database || 'local'
                })(
                <Radio.Group>
                  <Radio value="local">本地</Radio>
                  <Radio value="sso">单点</Radio>
                </Radio.Group>)}
              </Form.Item>
            </Col> : null}
            {/* 1、不分页且不存在上级模块 */}
            {!['navbar', 'interface', 'calendar'].includes(config.type) && !['editable', 'basetable', 'dualdatacard', 'invoice', 'invTable'].includes(config.subtype) && (!config.pageable || (config.pageable && setting.laypage === 'false')) && (setting.supModule.length === 0 || setting.supModule[0] === 'empty') && setting.interType === 'system' && setting.onload !== 'false' ? <Col span={8}>
              <Form.Item label={
src/menu/datasource/verifycard/utils.jsx
@@ -1,4 +1,5 @@
import md5 from 'md5'
import { getSearchRegs, joinMainSearchkey } from '@/utils/utils-custom.js'
export default class SettingUtils {
@@ -49,34 +50,24 @@
      })
    }
    let getuuid = () => {
      let uuid = []
      let timestamp = new Date().getTime()
      let _options = '0123456789abcdefghigklmnopqrstuv'
      for (let i = 0; i < 19; i++) {
        uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
      }
      uuid = timestamp + uuid.join('')
      return uuid
    }
    let regs = [
      {reg: /@time_id@/ig, value: `'${getuuid()}'`},
      {reg: /@BID@/ig, value: `'${getuuid()}'`},
      {reg: /@upid@/ig, value: `'${getuuid()}'`},
      // {reg: /@time_id@/ig, value: `'${getuuid()}'`}, // 计算md5后替换
      // {reg: /@BID@/ig, value: `'${getuuid()}'`},
      // {reg: /@upid@/ig, value: `'${getuuid()}'`},
      {reg: /@typename@/ig, value: `'debug'`},
      {reg: /@datam@/ig, value: `''`},
      {reg: /@LoginUID@/ig, value: `'${sessionStorage.getItem('LoginUID')}'`},
      {reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid')}'`},
      {reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID')}'`},
      {reg: /@Appkey@/ig, value: `'${window.GLOB.appkey}'`},
      {reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      {reg: /@\$|\$@/ig, value: ''},
      {reg: /@select\$|\$select@/ig, value: ''},
      {reg: /@sum\$|\$sum@/ig, value: ''},
    ]
    if (window.GLOB.process && type !== 'invoice') {
      regs.push({reg: /@works_flow_code@/ig, value: `'${getuuid()}'`})
      regs.push({reg: /@works_flow_code@/ig, value: `'mk_flow_code'`})
    }
    if (hasExtend) {
@@ -114,7 +105,7 @@
    }
    // 正则替换
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    let custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_dataresource + _customScript)
    let _regoptions = getSearchRegs(searches)
    let _search = joinMainSearchkey(searches)
@@ -182,6 +173,29 @@
        ${_dataresource}`
    }
    let debugId = md5(sql + window.GLOB.appkey)
    let getuuid = () => {
      let uuid = []
      let timestamp = new Date().getTime()
      let _options = '0123456789abcdefghigklmnopqrstuv'
      for (let i = 0; i < 19; i++) {
        uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
      }
      uuid = timestamp + uuid.join('')
      return uuid
    }
    let _regs = [
      {reg: /@time_id@/ig, value: `'${getuuid()}'`},
      {reg: /@BID@/ig, value: `'${getuuid()}'`},
      {reg: /@upid@/ig, value: `'${getuuid()}'`},
    ]
    _regs.forEach(item => {
      sql = sql.replace(item.reg, item.value)
    })
    let errors = []
    if (/@[0-9a-zA-Z_]+@/ig.test(sql)) {
@@ -214,8 +228,6 @@
      })
      arr.forEach(item => {
        if (/@time_id@/ig.test(item)) return
        let reg = new RegExp(item, 'i')
        if (reg.test(_dataresource)) {
          errors.push(`数据源中存在未替换值${item}`)
@@ -232,6 +244,6 @@
      })
    }
    return { error, sql, errors: errors.join(';'), custompage }
    return { error, sql, errors: errors.join(';'), custompage, debugId }
  }
}
src/menu/debug/index.jsx
@@ -1956,7 +1956,7 @@
    item.setting.dataresource = _dataresource
    item.setting.customScript = _customScript
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    let custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_dataresource + _customScript)
    if (_dataresource) {
      if (custompage) {
src/menu/sysinterface/index.jsx
@@ -74,7 +74,7 @@
  copy = (item) => {
    let msg = { key: 'interface', type: 'line', data: item }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      msg.$srcId = srcid
    }
src/menu/tablenodes/index.jsx
@@ -548,11 +548,11 @@
        }
      } else if (menu.param.type === 'app') {
        if (menu.param.typename !== 'pc') {
          let _param = {...menu.param}
          let _param = {...menu.param, lang: sessionStorage.getItem('lang')}
          _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
          window.open(`#/mobdesign/${_param}`)
        } else {
          let _param = {...menu.param}
          let _param = {...menu.param, lang: sessionStorage.getItem('lang')}
          _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
          window.open(`#/pcdesign/${_param}`)
        }
src/mob/colorsketch/index.jsx
@@ -12,7 +12,6 @@
  '#eb2f96', '#aeb303', '#c32539', '#1d3661', '#ffd591', '#ffe58f', '#fffb8f', '#eaff8f', '#b7eb8f', '#87e8de', '#91d5ff',
  '#adc6ff', '#EBE9E9', '#d9d9d9', 'rgba(0, 0, 0, 0.65)', 'rgba(0, 0, 0, 0.85)', '#000000', '#ffffff', 'transparent'
]
const _href = window.location.href.split('#')[0]
let loading = false
class ColorSketch extends Component {
@@ -79,7 +78,7 @@
  getColors = (appColors) => {
    let colors = JSON.parse(JSON.stringify(presetColors))
    let normal_colors = localStorage.getItem(_href + 'normal_colors')
    let normal_colors = localStorage.getItem(window.GLOB.sysSign + 'normal_colors')
    if (normal_colors) {
      try {
@@ -135,7 +134,7 @@
    const { initVal, color } = this.state
    
    if (!status && color && color !== initVal && color !== 'rgba(0, 0, 0, 0)' && color !== 'transparent' && !/rgba\(\d+,\s*\d+,\s*\d+,\s*0\)/.test(color)) {
      let normal_colors = localStorage.getItem(_href + 'normal_colors')
      let normal_colors = localStorage.getItem(window.GLOB.sysSign + 'normal_colors')
      if (normal_colors) {
        try {
@@ -154,7 +153,7 @@
        normal_colors.length = 10
      }
      localStorage.setItem(_href + 'normal_colors', JSON.stringify(normal_colors))
      localStorage.setItem(window.GLOB.sysSign + 'normal_colors', JSON.stringify(normal_colors))
    }
  }
src/mob/components/formdragelement/index.jsx
@@ -66,7 +66,7 @@
    delete val.$srcId
    
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/mob/components/menubar/normal-menubar/menucomponent/options.jsx
@@ -82,6 +82,7 @@
      required: false,
      options: menulist,
      extendName: 'MenuNo',
      dropdown: 'false',
      controlFields: [
        {field: 'clearMenu', notNull: true},
      ],
src/mob/components/navbar/normal-navbar/menus/menuform/index.jsx
@@ -168,6 +168,7 @@
                <Select
                  allowClear
                  showSearch
                  dropdownMatchSelectWidth={false}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
                    option.props.extend.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={(val) => this.setState({copyMenu: val})}
src/mob/searchconfig/index.jsx
@@ -223,7 +223,7 @@
        return
      }
      if (['checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['checkcard'].includes(res.type) && res.resourceType === '1' && res.database !== 'sso' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
@@ -232,12 +232,7 @@
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '')
        
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        Api.sDebug(sql, rduri).then(result => {
        Api.sDebug(sql).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
@@ -537,7 +532,7 @@
        <Modal
          title="编辑"
          visible={this.state.visible}
          width={850}
          width={950}
          onCancel={this.editModalCancel}
          onOk={this.handleSubmit}
          confirmLoading={this.state.sqlVerifing}
src/mob/searchconfig/searchdragelement/index.jsx
@@ -55,7 +55,7 @@
    delete val.$srcId
    
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx
@@ -159,7 +159,7 @@
              {getFieldDecorator('copyMenuId', {
                initialValue: menu.copyMenuId || ''
              })(
                <Select allowClear onChange={(val) => this.setState({copyMenu: val})}>
                <Select allowClear dropdownMatchSelectWidth={false} onChange={(val) => this.setState({copyMenu: val})}>
                  {appMenus.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
                </Select>
              )}
src/pc/createview/index.jsx
@@ -87,8 +87,8 @@
        MenuName: res.MenuName || '',
        PageParam: JSON.stringify({Template: 'webPage'}),
        open_edition: '',
        LText: '',
        LTexttb: ''
        // LText: '',
        // LTexttb: ''
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
src/pc/createview/settingform/index.jsx
@@ -120,6 +120,7 @@
                <Select
                  allowClear
                  showSearch
                  dropdownMatchSelectWidth={false}
                  onChange={(val) => this.setState({copymenuId: val})}
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
src/setupProxy.js
@@ -36,6 +36,12 @@
    changeOrigin: true
  }))
  app.use(proxy('/wechat', {
    target: `${options.host}/${options.service}`,
    secure: false,
    changeOrigin: true
  }))
//   app.use(proxy('/trans', {
//     target: `${host}/${service}`,
//     secure: false,
src/store/options.js
@@ -45,4 +45,19 @@
  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',
}
/**
 * @description 语言
 */
export const langs = {
  'zh-CN': '简体中文',
  'en-US': 'English',
  'fr-FR': 'Français',
  'de-DE': 'Deutsch',
  'ko-KR': '한국어',
  'pt-BR': 'Português',
  'ja-jp': '日本語',
  'ar-AE': 'عربي ،',
  'ru-RU': 'русский язык'
}
src/tabviews/basetable/index.jsx
@@ -504,12 +504,6 @@
    if (cell.OpenType === 'excelOut') { // 导出
      cell.$menuName = item.$menuname
      if (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0) {
        cell.errorType = 'error1'
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom' && item.setting.interType !== 'system') {
        cell.errorType = 'error2'
      }
    }
    if (cell.verify) {
@@ -677,7 +671,7 @@
      component.setting.customScript = _customScript // 整理后自定义脚本
      component.setting.tailScript = _tailScript     // 后置自定义脚本
      component.setting.custompage = /@pageSize@|@orderBy@/i.test(component.setting.dataresource + component.setting.customScript)
      component.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(component.setting.dataresource + component.setting.customScript)
      if (!component.setting.execute || component.setting.custompage) {
        component.forbidLine = true
src/tabviews/commontable/index.jsx
@@ -305,12 +305,6 @@
        if (item.OpenType === 'excelOut') { // 导出
          item.$menuName = MenuName
          if (!item.verify || !item.verify.columns || item.verify.columns.length === 0) {
            item.errorType = 'error1'
          } else if (item.intertype === 'system' && item.verify.dataType !== 'custom' && config.setting.interType !== 'system') {
            item.errorType = 'error2'
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
src/tabviews/custom/components/calendar/board/index.jsx
@@ -10,7 +10,9 @@
const { Option } = Select
moment.locale('zh-cn')
if (sessionStorage.getItem('lang') === 'zh-CN') {
  moment.locale('zh-cn')
}
class CalendarBoard extends Component {
  static propTpyes = {
src/tabviews/custom/components/card/cardcellList/index.jsx
@@ -991,8 +991,10 @@
  
        if (val !== '') {
          if (val && typeof(val) === 'string') {
            val = val.replace(/\n/ig, '<br/>')
            if (!/<(span|div|p|a|img)\s/g.test(val)) {
            if (!card.evalchars || card.evalchars.includes('enter')) {
              val = val.replace(/\n/ig, '<br/>')
            }
            if ((!card.evalchars || card.evalchars.includes('space')) && !/<(span|div|p|a|img)\s/g.test(val)) {
              val = val.replace(/\s/ig, '&nbsp;')
            }
src/tabviews/custom/components/card/data-card/index.jsx
@@ -188,6 +188,23 @@
      }
    }
    if (_config.wrap.zHeight) {
      if (_config.wrap.zHeight <= 100) {
        if (_config.wrap.zHeight < 0) {
          _config.wrap.zHeight = `calc(100vh - ${-_config.wrap.zHeight}px)`
        } else {
          _config.wrap.zHeight = _config.wrap.zHeight + 'vh'
        }
      }
      if (_config.style) {
        delete _config.style.height
      }
      _config.wrap.layout += ' fix-height'
    } else {
      _config.wrap.zHeight = 'none'
    }
    this.setState({
      pageSize: _config.setting.pageSize || 10,
      pageOptions,
@@ -599,7 +616,7 @@
      MKEmitter.emit('resetSelectLine', config.uuid, last ? last.$$uuid : '', last)
      MKEmitter.emit('syncBalconyData', config.uuid, items, data.length > 0 && data.length === keys.length)
      if (items.length === 0) {
        message.warning('未获取到数据!')
        message.warning(window.GLOB.dict['no_data'] || '未获取到数据!')
      }
    } else {
      this.setState({
@@ -1205,10 +1222,10 @@
            selectedData={selectedData}
          /> : null
        }
        {config.wrap.pickup === 'true' && this.state.data.length > 0 ? <div className="pickup-wrap"><Switch title="收起" checkedChildren="开" unCheckedChildren="关" checked={pickup} onChange={this.pickupChange} /></div> : null}
        {config.wrap.pickup === 'true' && this.state.data.length > 0 ? <div className="pickup-wrap"><Switch title="收起" checkedChildren={window.GLOB.dict['open'] || '开'} unCheckedChildren={window.GLOB.dict['shut'] || '关'} checked={pickup} onChange={this.pickupChange} /></div> : null}
        <div className={`data-zoom ${config.wrap.wrapClass}`}>
          {switchable ? <div className={'prev-page ' + (pageIndex === 1 ? 'disabled' : '')} onClick={this.prevPage}><div><div><img src={preImg} alt=""/></div></div></div> : null}
          <Row className={'card-row-list ' + config.wrap.layout}>
          <Row className={'card-row-list ' + config.wrap.layout} style={{maxHeight: config.wrap.zHeight}}>
            {precards.map((item, index) => (
              <Col key={'pre' + index} className="extend-card" style={item.wStyle} span={item.setting.width || 6}>
                {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
@@ -1254,8 +1271,8 @@
          {switchable ? <div className={'prev-page ' + (total <= _total ? 'disabled' : '')} onClick={this.nextPage}><div><div><img src={nextImg} alt=""/></div></div></div> : null}
        </div>
        {config.$empty && data.length === 0 ? <Empty description={false}/> : null}
        {config.wrap.pagestyle === 'page' ? <Pagination size="small" total={total} showTotal={(t, range) => total > 0 ? `${range[0]}-${range[1]} 共 ${total} 条` : `共 ${total} 条`} pageSize={pageSize} showSizeChanger={true} pageSizeOptions={this.state.pageOptions} onChange={this.changePageIndex} onShowSizeChange={this.pageSizeChange} current={pageIndex}/> : null}
        {config.wrap.pagestyle === 'more' && data.length > 0 ? <div className={'mk-more' + (pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>查看更多<DownOutlined/></div> : null}
        {config.wrap.pagestyle === 'page' ? <Pagination size="small" total={total} showTotal={(t, range) => total > 0 ? `${range[0]}-${range[1]} ${window.GLOB.dict['of'] || '共'} ${total} ${window.GLOB.dict['items'] || '条'}` : `${total} ${window.GLOB.dict['items'] || '条'}`} pageSize={pageSize} showSizeChanger={true} pageSizeOptions={this.state.pageOptions} onChange={this.changePageIndex} onShowSizeChange={this.pageSizeChange} current={pageIndex}/> : null}
        {config.wrap.pagestyle === 'more' && data.length > 0 ? <div className={'mk-more' + (pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>{window.GLOB.dict['view_more'] || '查看更多'}<DownOutlined/></div> : null}
      </div>
    )
  }
src/tabviews/custom/components/card/data-card/index.scss
@@ -8,6 +8,7 @@
  .pickup-wrap {
    float: right;
    margin-bottom: 3px;
    button {
      margin-top: 3px;
    }
@@ -64,6 +65,25 @@
  .card-row-list {
    flex: 10;
    max-width: 100%;
  }
  .card-row-list.fix-height {
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    overflow-y: auto;
    .extend-card:first-child {
      position: sticky;
      top: 0;
      z-index: 1;
      .card-item-box {
        margin-top: 0!important;
        margin-bottom: 0!important;
      }
    }
    div:last-child {
      .card-item-box {
        border-bottom: none!important;
      }
    }
  }
  .card-row-list.flex-layout {
    display: flex;
@@ -275,16 +295,16 @@
    }
  }
}
.custom-data-card-box::-webkit-scrollbar {
.custom-data-card-box::-webkit-scrollbar, .custom-data-card-box .card-row-list::-webkit-scrollbar {
  width: 7px;
  height: 7px;
}
.custom-data-card-box::-webkit-scrollbar-thumb {
.custom-data-card-box::-webkit-scrollbar-thumb, .custom-data-card-box .card-row-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);
}
.custom-data-card-box::-webkit-scrollbar-track {
.custom-data-card-box::-webkit-scrollbar-track, .custom-data-card-box .card-row-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);
src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -129,6 +129,26 @@
    _config.wrap.wrapClass =  `${_config.wrap.selStyle} ${_config.wrap.cardType || ''}`
    if (_config.wrap.zHeight || _config.wrap.minWidth) {
      if (_config.wrap.zHeight) {
        if (_config.wrap.zHeight <= 100) {
          if (_config.wrap.zHeight < 0) {
            _config.wrap.zHeight = `calc(100vh - ${-_config.wrap.zHeight}px)`
          } else {
            _config.wrap.zHeight = _config.wrap.zHeight + 'vh'
          }
        }
        _config.wrap.wrapClass += ' fix-height'
      }
      _config.wrap.minWidth = _config.wrap.minWidth ? _config.wrap.minWidth + 'px' : '100%'
      _config.wrap.zoomStyle = {
        maxHeight: _config.wrap.zHeight || 'none',
        '--mk-data-zoom-width': _config.wrap.minWidth
      }
    } else {
      _config.wrap.zoomStyle = null
    }
    if (_config.wrap.shifting === 'true') {
      _config.wrap.shifting = 'shifting'
    } else {
@@ -173,19 +193,6 @@
      if (_config.wrap.maxPageSize) {
        pageOptions = pageOptions.filter(item => item <= _config.wrap.maxPageSize)
      }
    }
    if (_config.wrap.zHeight) {
      _config.wrap.zHeight = _config.wrap.zHeight <= 100 ? _config.wrap.zHeight + 'vh' : _config.wrap.zHeight
    }
    if (_config.wrap.zHeight || _config.wrap.minWidth) {
      _config.wrap.zoomStyle = {
        border: `1px solid ${_config.wrap.zBColor || 'transparent'}`,
        height: _config.wrap.zHeight || 'auto'
      }
    } else {
      _config.wrap.zoomStyle = null
    }
    this.setState({
@@ -1152,10 +1159,10 @@
            selectedData={selectedData}
          /> : null
        }
        {config.wrap.pickup === 'true' && this.state.data.length > 0 ? <div className="pickup-wrap"><Switch title="收起" checkedChildren="开" unCheckedChildren="关" checked={pickup} onChange={this.pickupChange} /></div> : null}
        {config.wrap.pickup === 'true' && this.state.data.length > 0 ? <div className="pickup-wrap"><Switch title="收起" checkedChildren={window.GLOB.dict['open'] || '开'} unCheckedChildren={window.GLOB.dict['shut'] || '关'} checked={pickup} onChange={this.pickupChange} /></div> : null}
        <div className={config.wrap.zoomStyle ? 'data-zoom-box' : ''} style={config.wrap.zoomStyle}>
          <div className={`data-zoom ${config.wrap.wrapClass}`} style={config.wrap.minWidth ? {minWidth: config.wrap.minWidth} : null}>
            <Row className={'card-row-list '}>
          <div className={`data-zoom ${config.wrap.wrapClass}`}>
            <Row className="card-row-list">
              {precards.map((item, index) => (
                <Col key={'pre' + index} className="extend-card" style={item.wStyle} span={item.setting.width || 6}>
                  {item.setting.cardRole === 'header' ? <TableHeader card={item} data={extendData} refresh={this.refreshByHeader}>
@@ -1232,8 +1239,8 @@
          </div>
          {config.$empty && data.length === 0 ? <Empty description={false}/> : null}
        </div>
        {config.wrap.pagestyle === 'page' ? <Pagination size="small" total={total} showTotal={(t, range) => total > 0 ? `${range[0]}-${range[1]} 共 ${total} 条` : `共 ${total} 条`} pageSize={pageSize} showSizeChanger={true} pageSizeOptions={this.state.pageOptions} onChange={this.changePageIndex} onShowSizeChange={this.pageSizeChange} current={pageIndex}/> : null}
        {config.wrap.pagestyle === 'more' && data.length > 0 ? <div className={'mk-more' + (pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>查看更多<DownOutlined/></div> : null}
        {config.wrap.pagestyle === 'page' ? <Pagination size="small" total={total} showTotal={(t, range) => total > 0 ? `${range[0]}-${range[1]} ${window.GLOB.dict['of'] || '共'} ${total} ${window.GLOB.dict['items'] || '条'}` : `${total} ${window.GLOB.dict['items'] || '条'}`} pageSize={pageSize} showSizeChanger={true} pageSizeOptions={this.state.pageOptions} onChange={this.changePageIndex} onShowSizeChange={this.pageSizeChange} current={pageIndex}/> : null}
        {config.wrap.pagestyle === 'more' && data.length > 0 ? <div className={'mk-more' + (pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>{window.GLOB.dict['view_more'] || '查看更多'}<DownOutlined/></div> : null}
      </div>
    )
  }
src/tabviews/custom/components/card/double-data-card/index.scss
@@ -8,6 +8,7 @@
  .pickup-wrap {
    float: right;
    margin-bottom: 3px;
    button {
      margin-top: 3px;
    }
@@ -26,6 +27,7 @@
  .data-zoom {
    display: flex;
    position: relative;
    min-width: var(--mk-data-zoom-width, 100%);
    .mk-disabled {
      >.card-item-box {
        cursor: not-allowed;
@@ -42,14 +44,6 @@
  .card-row-list {
    flex: 10;
    max-width: 100%;
  }
  .card-row-list.flex-layout {
    display: flex;
    width: 100%;
    >.ant-col {
      width: 5%;
      flex: 1;
    }
  }
  .card-item-box {
    position: relative;
@@ -279,19 +273,31 @@
    width: 100%;
    overflow-x: auto;
    overflow-y: auto;
    padding-bottom: 10px;
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    .extend-card:first-child {
      position: sticky;
      top: 0px;
      z-index: 2;
    .fix-height .card-row-list {
      .extend-card:first-child {
        position: sticky;
        top: 0;
        z-index: 1;
        .card-item-box {
          margin-top: 0!important;
          margin-bottom: 0!important;
        }
      }
      div:last-child {
        .sub-card-wrap {
          .card-item-box {
            border-bottom: none!important;
          }
        }
      }
    }
  }
  .data-zoom-box::-webkit-scrollbar {
    height: 9px;
    width: 9px;
    width: 7px;
  }
  .data-zoom-box::-webkit-scrollbar-thumb {
    border-radius: 5px;
@@ -322,16 +328,16 @@
    }
  }
}
.double-data-card-box::-webkit-scrollbar {
.double-data-card-box::-webkit-scrollbar, .double-data-card-box .card-row-list::-webkit-scrollbar {
  width: 7px;
  height: 7px;
}
.double-data-card-box::-webkit-scrollbar-thumb {
.double-data-card-box::-webkit-scrollbar-thumb, .double-data-card-box .card-row-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);
}
.double-data-card-box::-webkit-scrollbar-track {
.double-data-card-box::-webkit-scrollbar-track, .double-data-card-box .card-row-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);
src/tabviews/custom/components/card/table-card/index.jsx
@@ -612,7 +612,7 @@
          {data && data.length === 0 ? <Empty description={false}/> : null}
        </Row>
        {config.wrap.pagestyle === 'page' ? <Pagination size="small" current={pageIndex} total={total} onChange={this.changePageIndex} /> : null}
        {config.wrap.pagestyle === 'more' && data && data.length > 0 ? <div className={'mk-more' + (config.setting.pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>查看更多<DownOutlined/></div> : null}
        {config.wrap.pagestyle === 'more' && data && data.length > 0 ? <div className={'mk-more' + (config.setting.pageSize * pageIndex >= total ? ' disabled' : '')} onClick={this.loadMore}>{window.GLOB.dict['view_more'] || '查看更多'}<DownOutlined/></div> : null}
      </div>
    )
  }
src/tabviews/custom/components/module/invoice/index.jsx
@@ -233,7 +233,7 @@
    item.setting.customScript = _customScript // 整理后自定义脚本
    item.setting.tailScript = _tailScript     // 后置自定义脚本
    item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
    item.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)
    return item
  }
@@ -714,6 +714,7 @@
    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    sql = sql.replace(/@typename@/ig, `'admin'`)
    if (window.GLOB.externalDatabase !== null) {
@@ -957,6 +958,7 @@
    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    sql = sql.replace(/@typename@/ig, `'admin'`)
    if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -446,7 +446,12 @@
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      } else if (content !== '') {
        content = `${col.prefix || ''}${content}${col.postfix || ''}`
        content = content.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        if (!col.evalchars || col.evalchars.includes('enter')) {
          content = content.replace(/\n/ig, '<br/>')
        }
        if (!col.evalchars || col.evalchars.includes('space')) {
          content = content.replace(/\s/ig, '&nbsp;')
        }
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      }
@@ -868,7 +873,7 @@
      MKEmitter.emit('resetSelectLine', MenuID, '', '')
      MKEmitter.emit('syncBalconyData', MenuID, data, data.length > 0)
      if (data.length === 0) {
        message.warning('未获取到数据!')
        message.warning(window.GLOB.dict['no_data'] || '未获取到数据!')
      }
    } else {
      this.setState({
@@ -1158,7 +1163,7 @@
        pageSizeOptions: pageOptions,
        showSizeChanger: true,
        total: this.props.total || 0,
        showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
        showTotal: (total, range) => `${range[0]}-${range[1]} ${window.GLOB.dict['of'] || '共'} ${total} ${window.GLOB.dict['items'] || '条'}`
      }
    }
@@ -1169,8 +1174,14 @@
    }
    let height = setting.height || false
    if (height && height <= 100) {
      height = height + 'vh'
    if (height) {
      if (height <= 100) {
        if (height < 0) {
          height = `calc(100vh - ${-height}px)`
        } else {
          height = height + 'vh'
        }
      }
    }
    let loading = this.props.loading
    if (setting.mask === 'hidden') {
@@ -1195,9 +1206,9 @@
    }
    return (
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed}`} style={style}>
      <div className={`normal-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || 'middle'} table-col-${columns.length} ${fixed}`} style={style}>
        {(setting.tableType === 'radio' || setting.tableType === 'checkbox') && data && data.length > 0 ?
          <Switch title="收起" className="main-pickup" checkedChildren="开" unCheckedChildren="关" checked={pickup} onChange={this.pickupChange} /> : null
          <Switch title="收起" className="main-pickup" checkedChildren={window.GLOB.dict['open'] || '开'} unCheckedChildren={window.GLOB.dict['shut'] || '关'} checked={pickup} onChange={this.pickupChange} /> : null
        }
        <Table
          components={components}
src/tabviews/custom/components/share/normalTable/index.scss
@@ -154,21 +154,6 @@
      // }
    }
  }
  // .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);
  // }
  .fix-header {
    .ant-table-body {
      min-height: unset
@@ -218,7 +203,7 @@
    background-color: #fafafa!important;
  }
}
.normal-custom-table:not(.fixed-height) {
.normal-custom-table:not(.fixed-table-height) {
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
@@ -233,14 +218,6 @@
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
}
.normal-custom-table.fixed-height {
  .ant-table-body {
    border-bottom: 1px solid rgba(0, 0, 0, .05);
    .ant-table-fixed {
      border-bottom: 0;
    }
  }
}
.normal-custom-table.hidden {
src/tabviews/custom/components/table/edit-table/index.jsx
@@ -251,6 +251,7 @@
    config.dataSource = config.dataSource.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    config.dataSource = config.dataSource.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    config.dataSource = config.dataSource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    config.dataSource = config.dataSource.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    if (/\s/.test(config.dataSource)) { // 拼接别名
      config.dataSource = '(' + config.dataSource + ') tb'
src/tabviews/custom/components/table/edit-table/normalTable/index.jsx
@@ -978,7 +978,12 @@
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      } else if (content !== '') {
        content = `${col.prefix || ''}${content}${col.postfix || ''}`
        content = content.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        if (!col.evalchars || col.evalchars.includes('enter')) {
          content = content.replace(/\n/ig, '<br/>')
        }
        if (!col.evalchars || col.evalchars.includes('space')) {
          content = content.replace(/\s/ig, '&nbsp;')
        }
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      }
@@ -1292,7 +1297,12 @@
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      } else if (content !== '') {
        content = `${col.prefix || ''}${content}${col.postfix || ''}`
        content = content.replace(/\n/ig, '<br/>').replace(/\s/ig, '&nbsp;')
        if (!col.evalchars || col.evalchars.includes('enter')) {
          content = content.replace(/\n/ig, '<br/>')
        }
        if (!col.evalchars || col.evalchars.includes('space')) {
          content = content.replace(/\s/ig, '&nbsp;')
        }
        content = <span dangerouslySetInnerHTML={{__html: content}}></span>
      }
@@ -1373,7 +1383,8 @@
    allColumns: null,
    checkForms: [],
    allForms: [],
    reseting: false
    reseting: false,
    dict: window.GLOB.dict
  }
  timer = null
@@ -1615,7 +1626,7 @@
  }
  checkLine = () => {
    const { edData, forms, checkForms } = this.state
    const { edData, forms, checkForms, dict } = this.state
    let data = edData.filter(item => item.$$uuid === this.blurId)[0]
@@ -1658,7 +1669,7 @@
      if (col.type === 'text') {
        let val = record[col.field] !== undefined ? (record[col.field] + '') : ''
        if (col.required === 'true' && !val) {
          err = `${col.label}不可为空`
          err = `${col.label}${dict['not_empty'] || '不可为空'}`
        } else if (col.datatype === 'datetime' && !val) {
          val = '1949-10-01'
        }
@@ -1667,27 +1678,27 @@
        let val = record[col.field]
        if (col.required === 'true' && !val) {
          err = `${col.label}不可为${col.noValue === 'hide' ? '空' : '0'}`
          err = `${col.label}${col.noValue === 'hide' ? (dict['not_empty'] || '不可为空') : dict['not_zero'] || '不可为0'}`
        } else if (col.noValue === 'hide' && !val) {
          if (col.clearField && checkForms.includes(col.clearField) && !record[col.clearField]) {
            err = `请填写 ${col.label} 或 ${col.clearName}`
            err = `${dict['input_tip'] || '请填写 '}${col.label} ${dict['or'] || '或'} ${col.clearName}`
          }
          val = 0
        } else if (!val && val !== 0) {
          err = `${col.label}不可为空`
          err = `${col.label}${dict['not_empty'] || '不可为空'}`
        } else {
          val = +val
          if (isNaN(val)) {
            err = `${col.label}数据格式错误`
            err = `${col.label} ${dict['data_format'] || '数据格式错误'}`
            return
          }
  
          val = +val.toFixed(col.decimal || 0)
          
          if (typeof(col.max) === 'number' && val > col.max) {
            err = `${col.label}不可大于${col.max}`
            err = `${col.label}${dict['max_limit'] || ' 不可大于 '}${col.max}`
          } else if (typeof(col.min) === 'number' && val < col.min) {
            err = `${col.label}不可小于${col.min}`
            err = `${col.label}${dict['less_limit'] || ' 不可小于 '}${col.min}`
          }
        }
@@ -2220,7 +2231,7 @@
  checkData = () => {
    const { setting } = this.props
    const { edData, forms, checkForms, selectedRowKeys } = this.state
    const { edData, forms, checkForms, selectedRowKeys, dict } = this.state
    let data = fromJS(edData).toJS()
@@ -2234,7 +2245,7 @@
      if (data.length === 0) {
        notification.warning({
          top: 92,
          message: '请选择需要提交的数据!',
          message: dict['select_row'] || '请选择需要提交的数据!',
          duration: 5
        })
        return null
@@ -2244,7 +2255,7 @@
    if (data.length === 0) {
      notification.warning({
        top: 92,
        message: '数据未修改,不可提交!',
        message: dict['un_modified'] || '数据未修改,不可提交!',
        duration: 5
      })
      return null
@@ -2278,7 +2289,7 @@
        if (col.type === 'text') {
          let val = item[col.field] !== undefined ? (item[col.field] + '') : ''
          if (col.required === 'true' && !val) {
            line.push(`${col.label}不可为空`)
            line.push(`${col.label}${dict['not_empty'] || '不可为空'}`)
          } else if (col.datatype === 'datetime' && !val) {
            val = '1949-10-01'
          }
@@ -2286,31 +2297,31 @@
        } else if (col.type === 'number') {
          let val = item[col.field]
          if (col.required === 'true' && !val) {
            err = `${col.label}不可为${col.noValue === 'hide' ? '空' : '0'}`
            err = `${col.label}${col.noValue === 'hide' ? (dict['not_empty'] || '不可为空') : dict['not_zero'] || '不可为0'}`
          } else if (col.noValue === 'hide' && !val) {
            if (col.clearField && checkForms.includes(col.clearField) && !item[col.clearField]) {
              let msg = `请填写 ${col.label} 或 ${col.clearName}`
              let msg = `${dict['input_tip'] || '请填写 '}${col.label} ${dict['or'] || '或'} ${col.clearName}`
              if (!line.includes(msg)) {
                line.push(msg)
              }
            }
            val = 0
          } else if (!val && val !== 0) {
            line.push(`${col.label}不可为空`)
            line.push(`${col.label}${dict['not_empty'] || '不可为空'}`)
            return
          } else {
            val = +val
            if (isNaN(val)) {
              line.push(`${col.label}数据格式错误`)
              line.push(`${col.label} ${dict['data_format'] || '数据格式错误'}`)
              return
            }
  
            val = +val.toFixed(col.decimal || 0)
            
            if (typeof(col.max) === 'number' && val > col.max) {
              line.push(`${col.label}不可大于${col.max}`)
              line.push(`${col.label}${dict['max_limit'] || ' 不可大于 '}${col.max}`)
            } else if (typeof(col.min) === 'number' && val < col.min) {
              line.push(`${col.label}不可小于${col.min}`)
              line.push(`${col.label}${dict['less_limit'] || ' 不可小于 '}${col.min}`)
            }
          }
@@ -2319,7 +2330,7 @@
      })
      if (line.length > 0) {
        err += `第${Index}行:` + line.join(',') + ';'
        err += (dict['line'] ? `${dict['line']} ${Index}:` : `第${Index}行:`) + line.join(',') + ';'
      }
      if (!item.$deleted) {
        Index++
@@ -2343,14 +2354,14 @@
  submit = (record) => {
    const { submit, BID, setting } = this.props
    const { forms } = this.state
    const { forms, dict } = this.state
    this.setState({visible: false, midData: null})
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
@@ -2428,17 +2439,18 @@
  execSuccess = (res, record) => {
    const { submit } = this.props
    const { edData } = this.state
    const { edData, dict } = this.state
    if (res && res.ErrCode === 'S') { // 执行成功
      notification.success({
        top: 92,
        message: res.message || '执行成功',
        message: res.message || dict['exc_success'] || '执行成功',
        duration: submit.stime ? submit.stime : 2
      })
    } else if (res && res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message || '执行成功'
        title: res.message || dict['exc_success'] || '执行成功',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res && res.ErrCode === '-1') { // 完成后不提示
@@ -2484,26 +2496,28 @@
  execError = (res, record) => {
    const { submit } = this.props
    const { dict } = this.state
    if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: submit.ntime ? submit.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: submit.ftime ? submit.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    
    this.setState({
@@ -2617,7 +2631,7 @@
  render() {
    const { setting, lineMarks, submit } = this.props
    const { edData, columns, loading, pageOptions, selectedRowKeys, visible, midData, reseting } = this.state
    const { edData, columns, loading, pageOptions, selectedRowKeys, visible, midData, reseting, dict } = this.state
    if (reseting) return null
@@ -2648,13 +2662,19 @@
        pageSizeOptions: pageOptions,
        showSizeChanger: true,
        total: this.props.total || 0,
        showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
        showTotal: (total, range) => `${range[0]}-${range[1]} ${dict['of'] || '共'} ${total} ${dict['items'] || '条'}`
      }
    }
    let height = setting.height || false
    if (height && height <= 100) {
      height = height + 'vh'
    if (height) {
      if (height <= 100) {
        if (height < 0) {
          height = `calc(100vh - ${-height}px)`
        } else {
          height = height + 'vh'
        }
      }
    }
    let style = {
@@ -2667,9 +2687,9 @@
    return (
      <>
        {setting.hasSubmit && edData.length > 0 ? <div className="edit-custom-table-btn-wrap" style={submit.wrapStyle}>
          <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-table" type="link">提交</Button>
          <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-table" type="link">{dict['submit'] || '提交'}</Button>
        </div> : null}
        <div className={`edit-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} style={style}>
        <div className={`edit-custom-table ${setting.tableHeader || ''} ${setting.parity === 'true' ? 'mk-parity' : ''} ${height ? 'fixed-table-height' : ''} ${setting.mode || ''} table-vertical-${setting.vertical || ''} mk-edit-${setting.editType || 'simple'}`} style={style}>
          <Table
            rowKey="$$uuid"
            components={components}
@@ -2691,7 +2711,7 @@
            onChange={this.changeTable}
            pagination={_pagination}
          />
          {setting.hasSubmit && _data.length > 10 ? <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-footer-table" type="link">提交</Button> : null}
          {setting.hasSubmit && _data.length > 10 ? <Button style={submit.style} onClick={() => setTimeout(() => {this.submit()}, 10)} loading={loading} className="submit-footer-table" type="link">{dict['submit'] || '提交'}</Button> : null}
        </div>
        <Modal
          className="mk-user-confirm"
@@ -2700,13 +2720,13 @@
          maskClosable={false}
          closable={false}
          footer={[
            <Button key="cancel" onClick={() => { this.setState({ visible: false, midData: null }) }}>取消</Button>,
            <Button key="refresh" className="table-refresh" onClick={() => { midData && this.updateMutil(midData) }}>刷新表格</Button>,
            <Button key="confirm" type="primary" onClick={() => setTimeout(() => {this.submit()}, 10)}>提交数据</Button>
            <Button key="cancel" onClick={() => { this.setState({ visible: false, midData: null }) }}>{dict['cancel'] || '取消'}</Button>,
            <Button key="refresh" className="table-refresh" onClick={() => { midData && this.updateMutil(midData) }}>{dict['refresh'] || '刷新表格'}</Button>,
            <Button key="confirm" type="primary" onClick={() => setTimeout(() => {this.submit()}, 10)}>{dict['submit'] || '提交数据'}</Button>
          ]}
          destroyOnClose
        >
          <div><QuestionCircleOutlined />表格中有数据尚未提交</div>
          <div><QuestionCircleOutlined />{dict['data_not_sub'] || '表格中有数据尚未提交'}</div>
        </Modal>
      </>
    )
src/tabviews/custom/components/table/edit-table/normalTable/index.scss
@@ -294,7 +294,7 @@
    background-color: #fafafa!important;
  }
}
.edit-custom-table:not(.fixed-height) {
.edit-custom-table:not(.fixed-table-height) {
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
@@ -309,14 +309,6 @@
    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 {
src/tabviews/custom/index.jsx
@@ -791,6 +791,9 @@
          return cell.eleType !== 'button' || pass || permAction[cell.uuid] || cell.permission === 'false'
        })
      } else if (item.type === 'form') {
        if (item.wrap.datatype === 'public') {
          balMap.set(item.wrap.publicId + 'public', true)
        }
        item.subcards = item.subcards.map(group => {
          group.subButton.uuid = group.uuid
          group.subButton.OpenType = 'formSubmit'
@@ -897,7 +900,7 @@
          item.setting.customScript = _customScript // 整理后自定义脚本
          item.setting.tailScript = _tailScript     // 后置自定义脚本
          item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
          item.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
@@ -953,16 +956,6 @@
    if (cell.OpenType === 'excelOut') { // 导出
      cell.$menuName = item.$menuname
      if (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0) {
        cell.errorType = 'error1'
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom') {
        if (item.setting.interType !== 'system') {
          cell.errorType = 'error2'
        } else if (item.type === 'balcony' || item.subtype === 'propcard') {
          cell.errorType = 'error2'
        }
      }
    } else if (cell.OpenType === 'pop' && item.$cache && item.$time && cell.modal) {
      cell.modal.$cache = item.$cache
      cell.modal.$time = item.$time
@@ -1334,7 +1327,7 @@
      inter.setting.customScript = _customScript // 整理后自定义脚本
      inter.setting.tailScript = _tailScript     // 后置自定义脚本
      inter.setting.custompage = /@pageSize@|@orderBy@/i.test(inter.setting.dataresource + inter.setting.customScript)
      inter.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(inter.setting.dataresource + inter.setting.customScript)
      return inter
    })
src/tabviews/custom/popview/index.jsx
@@ -513,6 +513,9 @@
          return true
        })
      } else if (item.type === 'form') {
        if (item.wrap.datatype === 'public') {
          balMap.set(item.wrap.publicId + 'public', true)
        }
        item.subcards = item.subcards.map(group => {
          group.subButton.uuid = group.uuid
          group.subButton.OpenType = 'formSubmit'
@@ -609,7 +612,7 @@
          item.setting.customScript = _customScript // 整理后自定义脚本
          item.setting.tailScript = _tailScript     // 后置自定义脚本
          item.setting.custompage = /@pageSize@|@orderBy@/i.test(item.setting.dataresource + item.setting.customScript)
          item.setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(item.setting.dataresource + item.setting.customScript)
          if (!item.setting.execute || item.setting.custompage) {
            item.forbidLine = true
@@ -664,16 +667,6 @@
    if (cell.OpenType === 'excelOut') { // 导出
      cell.$menuName = item.$menuname
      if (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0) {
        cell.errorType = 'error1'
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom') {
        if (item.setting.interType !== 'system') {
          cell.errorType = 'error2'
        } else if (item.type === 'balcony' || item.subtype === 'propcard') {
          cell.errorType = 'error2'
        }
      }
    }
    if (cell.verify) {
src/tabviews/subtable/index.jsx
@@ -230,12 +230,6 @@
        if (item.OpenType === 'excelOut') { // 导出
          item.$menuName = Tab.label
          if (!item.verify || !item.verify.columns || item.verify.columns.length === 0) {
            item.errorType = 'error1'
          } else if (item.intertype === 'system' && item.verify.dataType !== 'custom' && config.setting.interType !== 'system') {
            item.errorType = 'error2'
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
src/tabviews/subtabtable/index.jsx
@@ -203,12 +203,6 @@
        if (item.OpenType === 'excelOut') { // 导出
          item.$menuName = Tab.label
          if (!item.verify || !item.verify.columns || item.verify.columns.length === 0) {
            item.errorType = 'error1'
          } else if (item.intertype === 'system' && item.verify.dataType !== 'custom' && config.setting.interType !== 'system') {
            item.errorType = 'error2'
          }
        }
        if (item.verify && item.verify.invalid === 'true') {
src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -125,7 +125,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: window.GLOB.dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -162,7 +162,9 @@
    param[setting.primaryKey] = primaryId
    confirm({
      title: '确定要执行吗?',
      title: window.GLOB.dict['exec_sure'] || '确定要执行吗?',
      okText: window.GLOB.dict['ok'] || '确定',
      cancelText: window.GLOB.dict['cancel'] || '取消',
      onOk() {
        return new Promise(resolve => {
          Api.genericInterface(param).then(res => {
src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -29,6 +29,7 @@
    disabled: false,
    hidden: false,
    primaryId: '',
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -108,7 +109,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { setting, BID, btn, selectedData, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -119,20 +120,14 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        duration: 5
      })
    } else if (!btn.verify || !btn.verify.sheet || !btn.verify.columns || btn.verify.columns.length === 0) {
      notification.warning({
        top: 92,
        message: 'excel导入验证信息未设置!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
    } else {
@@ -164,16 +159,18 @@
   */
  execSuccess = (res = {}) => {
    const { btn } = this.props
    const { dict } = this.state
    if (res.ErrCode === 'S' || !res.ErrCode) { // 执行成功
      notification.success({
        top: 92,
        message: res.message || '执行成功!',
        message: res.message || dict['exc_success'] || '执行成功!',
        duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
      })
    } else if (res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message || '执行成功!'
        title: res.message || dict['exc_success'] || '执行成功!',
        okText: dict['got_it'] || '知道了',
      })
    } else if (res.ErrCode === '-1') { // 完成后不提示
@@ -226,6 +223,7 @@
   */
  execError = (res = {}) => {
    const { btn } = this.props
    const { dict } = this.state
    if (!['LoginError', 'C', '-2', 'E', 'N', 'F', 'NM'].includes(res.ErrCode)) {
      res.ErrCode = 'E'
@@ -233,23 +231,24 @@
    if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    
    this.setState({
@@ -260,6 +259,24 @@
      MKEmitter.emit('popclose')
    } else if (btn.execError !== 'never') {
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.execError, btn, '', this.state.selines)
      if (btn.syncComponentId) {
        if (btn.syncComponentId === 'multiComponent') {
          btn.syncComponentIds.forEach((id, i) => {
            setTimeout(() => {
              if (/\$focus/.test(id)) {
                MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
              } else {
                MKEmitter.emit('reloadData', id)
              }
            }, 20 * i)
          })
        } else if (/\$focus/.test(btn.syncComponentId)) {
          MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
        } else {
          MKEmitter.emit('reloadData', btn.syncComponentId)
        }
      }
    }
    if (btn.execError === 'popclose' && btn.$tabId) { // 标签关闭刷新
@@ -336,6 +353,10 @@
        param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp)
      }
      if (btn.database === 'sso' && window.GLOB.mainSystemApi) {
        param.rduri = window.GLOB.mainSystemApi
      }
      param.menuname = btn.logLabel
      
      if (window.GLOB.probation) {
@@ -358,8 +379,10 @@
          } else if (res.ErrCode === 'C') {
            const _this = this
            confirm({
              title: '请确认',
              title: window.GLOB.dict['exec_sure'] || '请确认',
              content: res.message,
              okText: window.GLOB.dict['ok'] || '确定',
              cancelText: window.GLOB.dict['cancel'] || '取消',
              onOk() {
                return new Promise(resolve => {
                  Api.genericInterface(unCheckParam).then(result => {
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -23,9 +23,10 @@
  }
  state = {
    loading: false, // 导出中
    loading: false,
    hidden: false,
    disabled: false
    disabled: false,
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -92,7 +93,7 @@
   */
  actionTrigger = (triggerId, _, type, lid) => {
    const { setting, BID, btn, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -101,19 +102,7 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        duration: 5
      })
    } else if (btn.errorType === 'error1') {
      notification.warning({
        top: 92,
        message: '请设置导出列!',
        duration: 5
      })
    } else if (btn.errorType === 'error2') {
      notification.warning({
        top: 92,
        message: '按钮需自定义导出数据源!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
    } else {
@@ -145,7 +134,7 @@
      if (!valid) {
        notification.warning({
          top: 92,
          message: '搜索条件不可为空!',
          message: window.GLOB.dict['miss_search'] || '搜索条件不可为空!',
          duration: 5
        })
        return
@@ -159,7 +148,9 @@
    if (btn.pagination !== 'true') {
      if (btn.intertype === 'system') { // 使用系统函数
        let param = this.getExcelDefaultParam(viewParam.orderBy, viewParam.search)
        if (btn.database === 'sso' && window.GLOB.mainSystemApi) {
          param.rduri = window.GLOB.mainSystemApi
        }
        Api.genericInterface(param).then(result => {
          if (result.status) {
            this.exportExcel(result.data, result.ErrCode, result.message, viewParam.search)
@@ -343,7 +334,7 @@
        Api.genericInterface(res).then(result => {
          if (result.status) {
            if (!result.data) {
              this.execError({ErrCode: 'N', message: '未获取到数据信息!'})
              this.execError({ErrCode: 'N', message: window.GLOB.dict['no_data'] || '未获取到数据信息!'})
            } else if (result.data.length >= pageSize) {
              data = data.concat(result.data)
              pageIndex++
@@ -376,6 +367,9 @@
    let param = null
    if (btn.intertype === 'system') { // 使用系统函数
      param = this.getExcelDefaultParam(viewParam.orderBy, viewParam.search, true, pageIndex, pageSize)
      if (btn.database === 'sso' && window.GLOB.mainSystemApi) {
        param.rduri = window.GLOB.mainSystemApi
      }
    } else if (btn.intertype === 'inner') { // 使用内部函数
      param = this.getExcelCustomParam(viewParam.orderBy, viewParam.search, true, pageIndex, pageSize)
      param.func = btn.innerFunc
@@ -422,7 +416,7 @@
    Api.genericInterface(param).then(result => {
      if (result.status) {
        if (!result.data) {
          this.execError({ErrCode: 'N', message: '未获取到数据信息!'})
          this.execError({ErrCode: 'N', message: window.GLOB.dict['no_data'] || '未获取到数据信息!'})
        } else if (result.data.length >= pageSize) {
          data = data.concat(result.data)
          pageIndex++
@@ -445,6 +439,7 @@
   */
  exportExcel = (data = [], ErrCode, msg, search) => {
    const { btn } = this.props
    const { dict } = this.state
    
    let imgCol = false
    let merge = false
@@ -518,7 +513,7 @@
      if (errors.length) {
        notification.error({
          top: 92,
          message: '数据中缺少字段:' + errors.join('、'),
          message: (dict['miss_field'] || '数据中缺少字段') + ':' + errors.join('、'),
          duration: 5
        })
@@ -535,7 +530,7 @@
        // eslint-disable-next-line
        let func = new Function('XLSX', 'data', 'columns', 'searches', 'callback', btn.verify.excel_func)
        func(XLSX, data, columns, search, (res) => {
          res = res || {ErrCode: ErrCode || 'S', message: msg || '导出成功!'}
          res = res || {ErrCode: ErrCode || 'S', message: msg || dict['exc_success'] || '导出成功!'}
          this.execSuccess(res)
        })
      } else if (imgCol) {
@@ -616,7 +611,7 @@
        this.table2excel(column, table)
        this.execSuccess({ErrCode: ErrCode || 'S', message: msg || '导出成功!'})
        this.execSuccess({ErrCode: ErrCode || 'S', message: msg || dict['exc_success'] || '导出成功!'})
      } else {
        let table = []
        let _header = []
@@ -776,7 +771,7 @@
  
        XLSX.writeFile(wb, `${btn.verify.excelName || btn.$menuName || ''}${moment().format('YYYYMMDDHHmmss')}.xlsx`)
  
        this.execSuccess({ErrCode: ErrCode || 'S', message: msg || '导出成功!'})
        this.execSuccess({ErrCode: ErrCode || 'S', message: msg || dict['exc_success'] || '导出成功!'})
      }
    } catch (e) {
      console.warn(e)
@@ -914,11 +909,18 @@
        _tailScript = _tailScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
      }
      if (btn.$flowId && window.GLOB.UserCacheMap.has(btn.$flowId)) {
        let flow = window.GLOB.UserCacheMap.get(btn.$flowId)
        _setting.dataresource = _setting.dataresource.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
        _customScript = _customScript.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
        _tailScript = _tailScript.replace(/@works_flow_code@/ig, `'${flow.flow_code}'`)
      }
      _setting.customScript = _customScript // 整理后自定义脚本
      _setting.tailScript = _tailScript     // 后置自定义脚本
      _setting.laypage = pagination
      _setting.custompage = /@pageSize@|@orderBy@/i.test(_setting.dataresource + _setting.customScript)
      _setting.custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_setting.dataresource + _setting.customScript)
      _setting.queryType = btn.verify.queryType
      _setting.$name = btn.logLabel
@@ -973,7 +975,8 @@
      })
    } else if (res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message
        title: res.message,
        okText: window.GLOB.dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === '-1') { // 完成后不提示
@@ -1026,6 +1029,7 @@
   */
  execError = (res = {}) => {
    const { btn } = this.props
    const { dict } = this.state
    if (!['LoginError', 'C', '-2', 'E', 'N', 'F', 'NM'].includes(res.ErrCode)) {
      res.ErrCode = 'E'
@@ -1033,23 +1037,24 @@
    if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    
    this.setState({
@@ -1060,6 +1065,24 @@
      MKEmitter.emit('popclose')
    } else if (btn.execError !== 'never') {
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.execError, btn, '', [])
      if (btn.syncComponentId) {
        if (btn.syncComponentId === 'multiComponent') {
          btn.syncComponentIds.forEach((id, i) => {
            setTimeout(() => {
              if (/\$focus/.test(id)) {
                MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
              } else {
                MKEmitter.emit('reloadData', id)
              }
            }, 20 * i)
          })
        } else if (/\$focus/.test(btn.syncComponentId)) {
          MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
        } else {
          MKEmitter.emit('reloadData', btn.syncComponentId)
        }
      }
    }
    if (btn.execError === 'popclose' && btn.$tabId) { // 标签关闭刷新
src/tabviews/zshare/actionList/funcbutton/index.jsx
@@ -23,6 +23,7 @@
    loading: false,
    disabled: false,
    hidden: false,
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -102,7 +103,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { btn, BID, selectedData, LID } = this.props
    const { loading } = this.state
    const { loading, dict } = this.state
    if (loading) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -112,14 +113,14 @@
    let error = ''
    if (btn.funcType === 'shareLink' && window.GLOB.systemType === 'production' && !btn.shareProUrl) {
      error = '尚未设置正式系统链接地址!'
      error = dict['no_prod_link'] || '尚未设置正式系统链接地址!'
    } else if (btn.funcType === 'refund') {
      if (data.length === 0) {
        error = '请选择行!'
        error = dict['select_row'] || '请选择行!'
      } else if (data.length !== 1) {
        error = '请选择单行数据!'
        error = dict['select_single_row'] || '请选择单行数据!'
      } else if (!data[0].$$uuid) {
        error = '未获取到订单编号!'
        error = dict['no_ordercode'] || '未获取到订单编号!'
      }
    }
@@ -160,7 +161,9 @@
      const that = this
      confirm({
        title: btn.tipTitle || '确定要执行吗?',
        title: btn.tipTitle || dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          that.execRefund(orderId)
        },
@@ -172,7 +175,7 @@
  execRefund = (orderId) => {
    Api.setRefund(orderId).then(res => {
      if (!res.status) {
        this.execError({ErrCode: 'E', message: '执行失败!', ...res})
        this.execError({ErrCode: 'E', message: window.GLOB.dict['exc_fail'] || '执行失败!', ...res})
      } else {
        this.execSuccess({ErrCode: 'S', ...res})
      }
@@ -243,22 +246,24 @@
        title: btn.shareTip
      })
    } else {
      message.success('已复制到剪切板。')
      message.success(window.GLOB.dict['copied'] || '已复制到剪切板。')
    }
  }
  execSuccess = (res = {}) => {
    const { btn } = this.props
    const { dict } = this.state
    if (res.ErrCode === 'S' || !res.ErrCode) { // 执行成功
      notification.success({
        top: 92,
        message: res.message || '执行成功!',
        message: res.message || dict['exc_success'] || '执行成功!',
        duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
      })
    } else if (res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message || '执行成功!'
        title: res.message || dict['exc_success'] || '执行成功!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === '-1') { // 完成后不提示
@@ -275,6 +280,7 @@
  execError = (res) => {
    const { btn } = this.props
    const { dict } = this.state
    if (!['LoginError', 'C', '-2', 'E', 'N', 'F', 'NM'].includes(res.ErrCode)) {
      res.ErrCode = 'E'
@@ -282,23 +288,24 @@
    if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    
    this.setState({
src/tabviews/zshare/actionList/funczip/index.jsx
@@ -22,6 +22,7 @@
    loading: false,
    disabled: false,
    hidden: false,
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -101,7 +102,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { BID, btn, selectedData, setting, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -112,21 +113,21 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
      return
    } else if (btn.Ot !== 'notRequired' && data.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return
    } else if (btn.Ot === 'requiredSgl' && data.length !== 1) {
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -351,43 +352,47 @@
   */
  execError = (res) => {
    const { btn } = this.props
    const { dict } = this.state
    this.setState({
      loading: false
    })
    if (res.ErrCode === '01') {
      message.error('未获取到下载文件。')
      message.error(dict['exc_fail'] || '未获取到下载文件。')
      return
    } else if (res.ErrCode === '02') {
      Modal.error({
        title: '部分文件下载失败:1、请检查文件路径是否正确,2、请检查文件是否跨域。',
        title: dict['exc_fail'] || '部分文件下载失败:1、请检查文件路径是否正确,2、请检查文件是否跨域。',
        okText: dict['got_it'] || '知道了'
      })
      return
    } else if (res.ErrCode === '03') {
      Modal.error({
        title: '文件下载失败:1、请检查文件路径是否正确,2、请检查文件是否跨域。',
        title: dict['exc_fail'] || '文件下载失败:1、请检查文件路径是否正确,2、请检查文件是否跨域。',
        okText: dict['got_it'] || '知道了'
      })
      return
    } else if (res.ErrCode === 'E') {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    if (btn.execError !== 'never') {
src/tabviews/zshare/actionList/index.jsx
@@ -231,7 +231,7 @@
          <div className="button-list toolbar-button">
            {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>
              <div className="mk-button-more">{window.GLOB.dict['more'] || '更多'}<DownOutlined/></div>
            </Dropdown> : null}
          </div>
        </Affix>
@@ -241,7 +241,7 @@
        <div className="button-list toolbar-button">
          {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>
            <div className="mk-button-more">{window.GLOB.dict['more'] || '更多'}<DownOutlined/></div>
          </Dropdown> : null}
        </div>
      )
src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -114,7 +114,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: window.GLOB.dict['select_row'] || '请选择行!',
        duration: 5
      })
      return
@@ -122,14 +122,14 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: window.GLOB.dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
    } else if (btn.pageTemplate === 'custom' && window.GLOB.systemType === 'production' && !btn.proUrl) {
      notification.warning({
        top: 92,
        message: '尚未设置正式系统链接地址!',
        message: window.GLOB.dict['no_prod_link'] || '尚未设置正式系统链接地址!',
        duration: 5
      })
      return
@@ -145,12 +145,12 @@
    let Id = ''
    let name = ''
    let MenuNo = ''
    let Remark = ''
    let lang = ''
    if (btn.Ot === 'requiredSgl' && data[0]) {
      Id = data[0].$$uuid || ''
      name = data[0].PrintTempName || ''
      MenuNo = data[0].PrintTempNO || ''
      Remark = data[0].Remark || ''
      lang = data[0].lang_s || ''
    }
    let _name = '新页面'
@@ -228,12 +228,10 @@
        }
      }
    } else if (btn.pageTemplate === 'billprintTemp') {
      let src = '#/menudesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'billPrint', MenuId: Id, MenuNo: MenuNo, MenuName: name || '打印', Remark: Remark })))
      let src = '#/menudesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({ MenuType: 'billPrint', MenuId: Id, MenuNo: MenuNo, MenuName: name || '打印', lang })))
      window.open(src)
    } else if (btn.pageTemplate === 'print') {
      let cloudmsg = '&cuid=' + (sessionStorage.getItem('CloudUserID') || '') + '&clid=' + (sessionStorage.getItem('CloudLoginUID') || '') + '&cun=' + (sessionStorage.getItem('CloudUserName') || '')
      let msg = '&uid=' + sessionStorage.getItem('UserID') + '&lid=' + sessionStorage.getItem('LoginUID') + '&un=' + sessionStorage.getItem('User_Name')
      let src = '#/print/' + window.btoa('ID=' + Id + msg + cloudmsg)
      let src = '#/print/' + window.btoa(window.encodeURIComponent(JSON.stringify({ ID: Id, lang })))
      window.open(src)
    } else if (btn.pageTemplate === 'pay') {
      let _p = `ID=${Id}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID')}&logo=${window.GLOB.doclogo}&name=${sessionStorage.getItem('Full_Name')}&icp=${window.GLOB.ICP}&copyRight=${window.GLOB.copyRight}`
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -44,7 +44,8 @@
    hidden: false,
    autoMatic: false,
    check: false,
    count: 0
    count: 0,
    dict: window.GLOB.dict
  }
  moduleParams = null
@@ -206,7 +207,7 @@
   */
  actionTrigger = (triggerId, record, type, lid, callback) => {
    const { btn, selectedData, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (type === 'preButton') {
      if (btn.uuid !== triggerId) return
@@ -242,7 +243,9 @@
    } else if (btn.OpenType === 'prompt') {
      this.setState({loading: true})
      confirm({
        title: btn.tipTitle || '确定要执行吗?',
        title: btn.tipTitle || dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          return new Promise(resolve => {
            _this.execSubmit(data, resolve)
@@ -319,7 +322,7 @@
  preTrigger = (callback) => {
    const { btn, selectedData } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) {
      callback()
@@ -352,7 +355,9 @@
    } else if (btn.OpenType === 'prompt') {
      this.setState({loading: true})
      confirm({
        title: btn.tipTitle || '确定要执行吗?',
        title: btn.tipTitle || dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          return new Promise(resolve => {
            _this.execSubmit(data, resolve)
@@ -402,11 +407,12 @@
  checkBtnData = (data) => {
    const { BID, btn, setting } = this.props
    const { dict } = this.state
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
      return false
@@ -414,7 +420,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return false
@@ -422,42 +428,17 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return false
    } else if (btn.intertype === 'system') {
      if (data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return false
      }
    } else if (btn.intertype === 'custom' || btn.intertype === 'outer') {
      if (btn.callbackType === 'script' && (!btn.verify || !btn.verify.cbScripts || !btn.verify.cbScripts.filter(item => item.status !== 'false').length === 0)) {
        notification.warning({
          top: 92,
          message: '使用自定义脚本回调时,回调脚本不可为空!',
          duration: 5
        })
        return false
      } else if (btn.procMode === 'system' && data.length === 0 && btn.verify && btn.verify.voucher && btn.verify.voucher.enabled) {
        notification.warning({
          top: 92,
          message: '使用创建凭证函数,需要选择行!',
          duration: 5
        })
        return false
      } else if (btn.intertype === 'custom' && window.GLOB.systemType === 'production' && !btn.proInterface) {
        notification.warning({
          top: 92,
          message: '尚未设置正式系统接口地址!',
          duration: 5
        })
        return false
      }
    } else if (btn.intertype === 'custom' && window.GLOB.systemType === 'production' && !btn.proInterface) {
      notification.warning({
        top: 92,
        message: dict['no_prod_link'] || '尚未设置正式系统接口地址!',
        duration: 5
      })
      return false
    }
    return true
@@ -1081,7 +1062,7 @@
    if (times > 50) {
      notification.warning({
        top: 92,
        message: '前置按钮加载失败!',
        message: window.GLOB.dict['pre_btn_failed'] || '前置按钮加载失败!',
        duration: 5
      })
      this.setState({loading: false})
@@ -1119,7 +1100,7 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: window.GLOB.dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
      _resolve()
@@ -1134,6 +1115,12 @@
        if (btn.returnValue === 'true') {
          params = params.map(item => {
            item.script_type = 'Y'
            return item
          })
        }
        if (btn.database === 'sso' && window.GLOB.mainSystemApi) {
          params = params.map(item => {
            item.rduri = window.GLOB.mainSystemApi
            return item
          })
        }
@@ -1726,6 +1713,7 @@
      sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
      sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
      sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
      sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
      sql = sql.replace(/@typename@/ig, `'admin'`)
      if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
@@ -1839,8 +1827,10 @@
        }
        const _this = this
        confirm({
          title: '请确认',
          title: window.GLOB.dict['exec_sure'] || '请确认',
          content: msg,
          okText: window.GLOB.dict['ok'] || '确定',
          cancelText: window.GLOB.dict['cancel'] || '取消',
          onOk() {
            return new Promise(resolve => {
              Api.genericInterface(unCheckParam).then(result => {
@@ -2237,7 +2227,7 @@
   */
  execSuccess = (res = {}) => {
    const { btn } = this.props
    const { autoMatic } = this.state
    const { autoMatic, dict } = this.state
    if (btn.resetForms) {
      let data = {}
@@ -2272,6 +2262,17 @@
    }
    let sign = ''
    let focusField = ''
    if (/@focus:[a-z0-9_]+@/i.test(res.message)) {
      let val = res.message.match(/@focus:[a-z0-9_]+@/i)
      res.message = res.message.replace(/@focus:[a-z0-9_]+@/i, '')
      focusField = val ? val[0].replace(/@focus:|@/ig, '') : ''
      if (!res.message) {
        res.ErrCode = '-1'
      }
    }
    if (/^@speak@/i.test(res.message)) {
      res.message = res.message.replace(/^@speak@/i, '')
      let val = res.message.match(/<<.*>>/)
@@ -2287,7 +2288,8 @@
      if (!res.message) {
        res.ErrCode = '-1'
      }
    } else if (/@close_tab@|@close_popup@|@goback@|@no_target_menu@/i.test(res.message)) {
    }
    if (/@close_tab@|@close_popup@|@goback@|@no_target_menu@/i.test(res.message)) {
      sign = res.message.match(/@close_tab@|@close_popup@|@goback@|@no_target_menu@/i)[0].toLowerCase()
      res.message = res.message.replace(/@close_tab@|@close_popup@|@goback@|@no_target_menu@/i, '')
    }
@@ -2307,20 +2309,21 @@
      if (btn.formType !== 'counter' || res.message) {
        notification.success({
          top: 92,
          message: res.message || '执行成功!',
          message: res.message || dict['exc_success'] || '执行成功!',
          duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
        })
      }
    } else if (res.ErrCode === 'Y') { // 执行成功
      let msg = res.message || '执行成功!'
      let msg = res.message || dict['exc_success'] || '执行成功!'
      if (/\n|\r/.test(msg)) {
        msg = msg.replace(/\n|\r/ig, '<br/>')
        msg = <span dangerouslySetInnerHTML={{__html: msg}}></span>
      }
      Modal.success({
        title: msg,
        okText: dict['got_it'] || '知道了',
        onOk: () => {
          this.successContinue(sign, id, res)
          this.successContinue(sign, id, res, focusField)
        }
      })
      return
@@ -2328,12 +2331,16 @@
    }
    this.successContinue(sign, id, res)
    this.successContinue(sign, id, res, focusField)
  }
  successContinue = (sign, id, res) => {
  successContinue = (sign, id, res, focusField) => {
    const { btn } = this.props
    const { btnconfig } = this.state
    if (focusField) {
      MKEmitter.emit('resetFocus', btn.uuid, focusField)
    }
    this.setState({
      loadingNumber: '',
@@ -2444,7 +2451,7 @@
        if (!url) {
          notification.warning({
            top: 92,
            message: '尚未添加正式系统链接地址!',
            message: window.GLOB.dict['no_prod_link'] || '尚未设置正式系统链接地址!',
            duration: 5
          })
          return
@@ -2963,7 +2970,7 @@
   */
  execError = (res = {}) => {
    const { btn } = this.props
    const { autoMatic } = this.state
    const { autoMatic, dict } = this.state
    if (this.preCallback) {
      this.setState({
@@ -2975,7 +2982,7 @@
    } else if (autoMatic) {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: 10
      })
@@ -3015,13 +3022,14 @@
    }
    if (res.ErrCode === 'E') {
      let msg = res.message || '执行失败!'
      let msg = res.message || dict['exc_fail'] || '执行失败!'
      if (/\n|\r/.test(msg)) {
        msg = msg.replace(/\n|\r/ig, '<br/>')
        msg = <span dangerouslySetInnerHTML={{__html: msg}}></span>
      }
      Modal.error({
        title: msg,
        okText: dict['got_it'] || '知道了',
        onOk: () => {
          this.errorContinue(sign)
        }
@@ -3030,18 +3038,18 @@
    } else if (res.ErrCode === 'N') {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    } else if (res.ErrCode === '-2') {
      this.setState({
        loadingNumber: '',
@@ -3078,8 +3086,47 @@
    } else if (btn.execError === 'closepoptab' || sign === '@close_popup@') {
      MKEmitter.emit('popclose')
    } else if (btn.execError !== 'never') {
      let tabId = ''
      if (btn.refreshTab && btn.refreshTab.length > 0) {
        tabId = btn.refreshTab[btn.refreshTab.length - 1]
      }
      if (tabId && btn.$MenuID === tabId) { // 刷新当前菜单时,停止其他操作
        MKEmitter.emit('reloadMenuView', tabId, 'table')
        return
      }
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.execError, btn, '', this.state.selines)
      if (btn.syncComponentId) {
        if (btn.syncComponentId === 'multiComponent') {
          btn.syncComponentIds.forEach((id, i) => {
            setTimeout(() => {
              if (/\$focus/.test(id)) {
                MKEmitter.emit('reloadData', id.split('$')[0], id.split('$')[1])
              } else {
                MKEmitter.emit('reloadData', id)
              }
            }, 20 * i)
          })
        } else if (/\$focus/.test(btn.syncComponentId)) {
          MKEmitter.emit('reloadData', btn.syncComponentId.split('$')[0], btn.syncComponentId.split('$')[1])
        } else {
          if (btn.syncDelay) {
            this.delayTimer && clearTimeout(this.delayTimer)
            this.delayTimer = setTimeout(() => {
              MKEmitter.emit('reloadData', btn.syncComponentId)
            }, btn.syncDelay)
          } else {
            MKEmitter.emit('reloadData', btn.syncComponentId)
          }
        }
      }
      if (tabId) {
        MKEmitter.emit('reloadMenuView', tabId, 'table')
      }
    }
    if (btn.OpenType === 'form') {
      let data = this.props.selectedData && this.props.selectedData[0] ? this.props.selectedData[0] : null
@@ -3235,7 +3282,7 @@
  modelconfirm = () => {
    const { BID } = this.props
    const { btnconfig, selines } = this.state
    const { btnconfig, selines, dict } = this.state
    let _this = this
    let result = []
@@ -3379,7 +3426,9 @@
      this.execSubmit(selines, () => {}, result)
    } else {
      confirm({
        title: btnconfig.setting.tipTitle || '确定要执行吗?',
        title: btnconfig.setting.tipTitle || dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          return new Promise(resolve => {
            _this.execSubmit(selines, resolve, result)
@@ -3398,7 +3447,7 @@
   */
  getModels = () => {
    const { BID, btn, BData } = this.props
    const { btnconfig, visible } = this.state
    const { btnconfig, visible, dict } = this.state
    if (!btnconfig || !btnconfig.setting) return null
@@ -3434,10 +3483,10 @@
          />
          <div className="ant-drawer-footer" style={{ position: 'absolute', zIndex: 1, right: 0, bottom: 0, width: '100%', borderTop: '1px solid #e9e9e9', padding: '10px 16px', background: '#fff', textAlign: 'right'}}>
            <Button onClick={this.handleCancel} style={{ marginRight: 8 }}>
              {btnconfig.setting.formType !== 'check' ? '取消' : '关闭'}
              {btnconfig.setting.formType !== 'check' ? dict['cancel'] || '取消' : dict['close'] || '关闭'}
            </Button>
            {btnconfig.setting.formType !== 'check' ? <Button onClick={this.handleOk} loading={this.state.confirmLoading} type="primary">
              确定
              {dict['ok'] || '确定'}
            </Button> : null}
          </div>
        </Drawer>
@@ -3465,6 +3514,8 @@
          wrapClassName={'action-modal' + (btnconfig.setting.moveable === 'true' ? ' moveable-modal modal-' + btn.uuid : '')}
          visible={visible}
          width={width}
          okText={dict['ok'] || '确定'}
          cancelText={dict['cancel'] || '取消'}
          onOk={this.handleOk}
          maskStyle={btnconfig.setting.moveable === 'true' ?  {backgroundColor: 'rgba(0, 0, 0, 0.15)'} : null}
          confirmLoading={this.state.confirmLoading}
@@ -3529,7 +3580,7 @@
  changeLineCount = (count) => {
    const { btn, selectedData } = this.props
    const { disabled } = this.state
    const { disabled, dict } = this.state
    if (disabled) return
@@ -3539,7 +3590,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return
@@ -3547,7 +3598,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx
@@ -35,10 +35,10 @@
    let val = count - 1
    if (btn.min !== '' && val < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      message.warning(`${window.GLOB.dict['less_limit'] || '不可小于'}${btn.min}!`)
      return
    } else if (btn.max !== '' && val > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      message.warning(`${window.GLOB.dict['max_limit'] || '不可大于'}${btn.max}!`)
      return
    }
@@ -58,10 +58,10 @@
    let val = count + 1
    if (btn.min !== '' && val < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      message.warning(`${window.GLOB.dict['less_limit'] || '不可小于'}${btn.min}!`)
      return
    } else if (btn.max !== '' && val > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      message.warning(`${window.GLOB.dict['max_limit'] || '不可大于'}${btn.max}!`)
      return
    }
@@ -79,14 +79,14 @@
    const { count, orival } = this.state
    if (count === '') {
      message.warning(`不可为空!`)
      message.warning(window.GLOB.dict['not_empty'] || '不可为空!')
      this.setState({count: 0})
      return
    } else if (btn.min !== '' && count < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      message.warning(`${window.GLOB.dict['less_limit'] || '不可小于'}${btn.min}!`)
      return
    } else if (btn.max !== '' && count > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      message.warning(`${window.GLOB.dict['max_limit'] || '不可大于'}${btn.max}!`)
      return
    }
src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -30,6 +30,7 @@
    disabled: false,
    hidden: false,
    loading: false,
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -143,7 +144,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { setting, BID, btn, selectedData, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -154,7 +155,7 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
      return
@@ -162,7 +163,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: data.length === 0 ? '请选择行!' : '请选择单行数据!',
        message: data.length === 0 ? dict['select_row'] || '请选择行!' : dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -230,7 +231,7 @@
  getPop = () => {
    const { btn } = this.props
    const { popData, primaryId, visible } = this.state
    const { popData, primaryId, visible, dict } = this.state
    let ratio = btn.ratio || 85
@@ -248,7 +249,7 @@
        visible={visible}
        onCancel={this.popclose}
        footer={[
          <Button key="close" onClick={this.popclose}>关闭</Button>
          <Button key="close" onClick={this.popclose}>{dict['close'] || '关闭'}</Button>
        ]}
        destroyOnClose
      >
@@ -292,7 +293,7 @@
          {btn.$view === 'popview' ? <PopView Tab={btn} param={{$BID: (popData ? primaryId : this.props.BID), ...(popData || this.props.BData || {})}} /> : null}
          <div className="close-drawer">
            <Button onClick={this.popclose}>
              关闭
              {dict['close'] || '关闭'}
            </Button>
          </div>
        </Drawer>
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -37,7 +37,8 @@
    loading: false,
    disabled: false,
    hidden: false,
    autoMatic: false
    autoMatic: false,
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -132,7 +133,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { BID, btn, selectedData, setting, LID } = this.props
    const { loading, disabled } = this.state
    const { loading, disabled, dict } = this.state
    if (loading || disabled) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -141,7 +142,7 @@
    if (setting.supModule && !BID) {
      notification.warning({
        top: 92,
        message: '需要上级主键值!',
        message: dict['sup_key_req'] || '需要上级主键值!',
        duration: 5
      })
      return
@@ -156,7 +157,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return
@@ -164,21 +165,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        duration: 5
      })
      return
    } else if (!btn.verify || !btn.verify.printMode) {
      notification.warning({
        top: 92,
        message: '请完善打印验证信息!',
        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: '自定义打印数据请设置数据源!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -203,7 +190,9 @@
    } else if (btn.execMode === 'prompt') {
      this.setState({ loading: true })
      confirm({
        title: '确定要执行吗?',
        title: dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          _this.triggerPrint(data)
        },
@@ -507,7 +496,7 @@
      if (list.length === 0) {
        notification.warning({
          top: 92,
          message: '未获取到打印数据!',
          message: window.GLOB.dict['no_data'] || '未获取到打印数据!',
          duration: 5
        })
        return false
@@ -534,7 +523,7 @@
      if (!result.ConfigParam) {
        notification.warning({
          top: 92,
          message: '未获取到打印模板信息!',
          message: window.GLOB.dict['no_print_temp'] || '未获取到打印模板信息!',
          duration: 5
        })
        this.setState({ loading: false })
@@ -785,7 +774,7 @@
      notification.warning({
        top: 92,
        message: '自定义函数执行错误!',
        message: window.GLOB.dict['func_error'] || '自定义函数执行错误!',
        duration: 5
      })
    }
@@ -1009,7 +998,7 @@
    }
    let isDataM = sessionStorage.getItem('dataM') === 'true'
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript + _tailScript)
    let custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_dataresource + _customScript + _tailScript)
    let regoptions = [
      { reg: /@orderBy@/ig, value: btn.verify.setting.order },
      { reg: /@pageSize@/ig, value: '9999' },
@@ -1020,6 +1009,7 @@
      { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      { reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      { reg: /@typename@/ig, value: `'admin'`},
      { reg: /\$@/ig, value: isDataM ? '/*' : ''},
      { reg: /@\$/ig, value: isDataM ? '*/' : ''},
@@ -1344,7 +1334,7 @@
    let imgs = []
    if (!res.ConfigParam) {
      error = '未获取到打印模板信息!'
      error = window.GLOB.dict['no_print_temp'] || '未获取到打印模板信息!'
    } else {
      try {
        configParam = JSON.parse(window.decodeURIComponent(window.atob(res.ConfigParam)))
@@ -1501,7 +1491,7 @@
    if (list.length === 0) {
      notification.warning({
        top: 92,
        message: '未获取到打印数据!',
        message: window.GLOB.dict['no_data'] || '未获取到打印数据!',
        duration: 5
      })
      this.setState({ loading: false })
@@ -1620,7 +1610,7 @@
    Api.postekPrint(param).then(res => {
      if (res.retval === '0') {
        if (params.length === 0) {
          this.execSuccess({ ErrCode: 'S', message: '打印请求已发出。', status: true })
          this.execSuccess({ ErrCode: 'S', message: window.GLOB.dict['print_out'] || '打印请求已发出。', status: true })
        } else {
          setTimeout(() => {
            this.loopRFIDPrint(params)
@@ -1638,6 +1628,8 @@
  execPrint = (list, template) => {
    const { btn } = this.props
    const { dict } = this.state
    let _errors = []
    let defaultPrinter = btn.verify.defaultPrinter || 'lackprinter'
@@ -1738,13 +1730,13 @@
      if (btn.verify.emptyTip === 'false') {
        this.execSuccess({
          ErrCode: '-1',
          message: '未获取到打印信息!',
          message: dict['no_data'] || '未获取到打印信息!',
          status: true
        })
      } else {
        this.execError({
          ErrCode: 'N',
          message: '未获取到打印信息!',
          message: dict['no_data'] || '未获取到打印信息!',
          status: false
        })
      }
@@ -1758,7 +1750,7 @@
          lackerror.push(`数据中未获取到模板(${err.title})${err.lacks.join('、')} 字段`)
        }
        if (err.emptys.length > 0) {
          emptyerror.push(`数据中模板(${err.title}) ${err.emptys.join('、')} 字段不可为空`)
          emptyerror.push(dict['not_empty'] ? `${err.title}: ${err.emptys.join('、')} ${dict['not_empty']}` : `数据中模板(${err.title}) ${err.emptys.join('、')} 字段不可为空`)
        }
      })
@@ -1782,7 +1774,7 @@
    if (printerList.length === 0) {
      this.execSuccess({
        ErrCode: '-1',
        message: '未获取到打印信息!',
        message: dict['no_data'] || '未获取到打印信息!',
        status: true
      })
      return
@@ -1794,7 +1786,7 @@
      this.syncMessageSend(printerList, () => {
        this.execSuccess({
          ErrCode: 'S',
          message: '打印请求已发出。',
          message: dict['print_out'] || '打印请求已发出。',
          status: true
        })
      })
@@ -1805,7 +1797,7 @@
      this.syncMessageSend(printerList, () => {
        this.execSuccess({
          ErrCode: 'S',
          message: '打印请求已发出。',
          message: dict['print_out'] || '打印请求已发出。',
          status: true
        })
      })
@@ -1856,7 +1848,7 @@
    socket.onerror = () => {
      this.execError({
        ErrCode: 'N',
        message: '无法连接到:' + btn.verify.linkUrl,
        message: (dict['un_connect'] || '无法连接到') + ':' + btn.verify.linkUrl,
        status: false
      })
    }
@@ -1892,17 +1884,18 @@
   */
  execSuccess = (res = {}) => {
    const { btn } = this.props
    const { autoMatic, btnconfig } = this.state
    const { autoMatic, btnconfig, dict } = this.state
    if ((res.ErrCode === 'S' || !res.ErrCode) || autoMatic) { // 执行成功
      notification.success({
        top: 92,
        message: res.message || '执行成功!',
        message: res.message || dict['exc_success'] || '执行成功!',
        duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
      })
    } else if (res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message || '执行成功!'
        title: res.message || dict['exc_success'] || '执行成功!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === '-1') { // 完成后不提示
@@ -1941,7 +1934,7 @@
   */
  execError = (res) => {
    const { btn } = this.props
    const { btnconfig, autoMatic } = this.state
    const { btnconfig, autoMatic, dict } = this.state
    if (!['LoginError', 'C', '-2', 'E', 'N', 'F', 'NM'].includes(res.ErrCode)) {
      res.ErrCode = 'E'
@@ -1949,23 +1942,24 @@
    if (res.ErrCode === 'E' && !autoMatic) {
      Modal.error({
        title: res.message || '执行失败!',
        title: res.message || dict['exc_fail'] || '执行失败!',
        okText: dict['got_it'] || '知道了'
      })
    } else if (res.ErrCode === 'N' || autoMatic) {
      notification.error({
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ntime ? btn.verify.ntime : 10
      })
    } else if (res.ErrCode === 'F') {
      notification.error({
        className: 'notification-custom-error',
        top: 92,
        message: res.message || '执行失败!',
        message: res.message || dict['exc_fail'] || '执行失败!',
        duration: btn.verify && btn.verify.ftime ? btn.verify.ftime : 10
      })
    } else if (res.ErrCode === 'NM') {
      message.error(res.message || '执行失败!')
      message.error(res.message || dict['exc_fail'] || '执行失败!')
    }
    
    this.setState({
@@ -2113,7 +2107,7 @@
  }
  modelconfirm = () => {
    const { btnconfig, selines } = this.state
    const { btnconfig, selines, dict } = this.state
    let _this = this
    let result = []
    let _data = {}
@@ -2256,7 +2250,9 @@
      this.execSubmit(selines, () => {}, result)
    } else {
      confirm({
        title: '确定要执行吗?',
        title: dict['exec_sure'] || '确定要执行吗?',
        okText: dict['ok'] || '确定',
        cancelText: dict['cancel'] || '取消',
        onOk() {
          _this.triggerPrint(selines, result)
        },
@@ -2272,7 +2268,7 @@
   */
  getModels = () => {
    const { BID, btn } = this.props
    const { btnconfig } = this.state
    const { btnconfig, dict } = this.state
    if (!this.state.visible || !btnconfig || !btnconfig.setting) return null
@@ -2306,6 +2302,8 @@
        visible={this.state.visible}
        confirmLoading={this.state.confirmLoading}
        width={width}
        okText={dict['ok'] || '确定'}
        cancelText={dict['cancel'] || '取消'}
        maskStyle={btnconfig.setting.moveable === 'true' ?  {backgroundColor: 'rgba(0, 0, 0, 0.15)'} : null}
        onOk={this.handleOk}
        onCancel={this.handleCancel}
src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -22,7 +22,8 @@
  state = {
    disabled: false,
    hidden: false,
    primaryId: ''
    primaryId: '',
    dict: window.GLOB.dict
  }
  UNSAFE_componentWillMount () {
@@ -102,7 +103,7 @@
   */
  actionTrigger = (triggerId, record, type, lid) => {
    const { btn, selectedData, BID, LID } = this.props
    const { disabled } = this.state
    const { disabled, dict } = this.state
    if (disabled || btn.multiMenus) return
    if (triggerId && btn.uuid !== triggerId) return
@@ -114,7 +115,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return false
@@ -122,7 +123,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -187,7 +188,7 @@
      if (!menu) {
        notification.warning({
          top: 92,
          message: '菜单已删除或没有访问权限!',
          message: dict['no_perm'] || '菜单已删除或没有访问权限!',
          duration: 5
        })
        return
@@ -219,6 +220,7 @@
  triggerMenu = (tab) => {
    const { btn, selectedData, BID } = this.props
    const { dict } = this.state
    let data = selectedData || []
@@ -226,7 +228,7 @@
      // 需要选择行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择行!',
        message: dict['select_row'] || '请选择行!',
        duration: 5
      })
      return false
@@ -234,7 +236,7 @@
      // 需要选择单行时,校验数据
      notification.warning({
        top: 92,
        message: '请选择单行数据!',
        message: dict['select_single_row'] || '请选择单行数据!',
        duration: 5
      })
      return
@@ -283,7 +285,7 @@
    if (!menu) {
      notification.warning({
        top: 92,
        message: '菜单已删除或没有访问权限!',
        message: dict['no_perm'] || '菜单已删除或没有访问权限!',
        duration: 5
      })
      return
src/tabviews/zshare/mutilform/index.jsx
@@ -6,7 +6,6 @@
import moment from 'moment'
import Api from '@/api'
import { formRule } from '@/utils/option.js'
import Utils from '@/utils/utils.js'
import asyncComponent from '@/utils/asyncComponent'
import MKEmitter from '@/utils/events.js'
@@ -48,7 +47,8 @@
    timestamp: '',
    n_id: '',
    focusId: '',
    reFocusId: ''
    reFocusId: '',
    dict: window.GLOB.dict
  }
  record = {}
@@ -56,6 +56,7 @@
  componentDidMount () {
    const { action, unload } = this.props
    const { dict } = this.state
    let data = {}
    let BData = {}
@@ -315,14 +316,14 @@
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
            message: item.label + (dict['not_empty'] || '不可为空!')
          })
        }
        item.rules.push({
          validator: (rule, value, callback) => {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
              callback(dict['single_quot'] || '不可使用英文状态的单引号!')
            // } else if (/--/.test(value)) {
            //   callback('不可使用 -- !')
            } else {
@@ -334,7 +335,7 @@
        if (!item.lenControl || item.lenControl === 'limit') {
          item.rules.push({
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
            message: (dict['max_char'] || '最多@max个字符').replace('@max', item.fieldlength)
          })
        }
@@ -346,7 +347,7 @@
            }
            item.rules.push({
              pattern: reg,
              message: item.regularText || formRule.input.numbermsg
              message: item.regularText || dict['enter_num'] || '请输入数字!'
            })
          } else if (item.regular === 'letter') {
            let reg = /^[a-zA-Z]*$/
@@ -355,7 +356,7 @@
            }
            item.rules.push({
              pattern: reg,
              message: item.regularText || formRule.input.lettermsg
              message: item.regularText || dict['enter_letter'] || '请输入字母!'
            })
          } else if (item.regular === 'letter_number') {
            let reg = /^[a-zA-Z0-9]*$/
@@ -364,7 +365,7 @@
            }
            item.rules.push({
              pattern: reg,
              message: item.regularText || '请输入数字或字母'
              message: item.regularText || dict['enter_num_letter'] || '请输入数字或字母'
            })
          } else if (item.regular === 'letter&number') {
            let reg = /^[a-zA-Z0-9@_.]*$/
@@ -373,24 +374,24 @@
            }
            item.rules.push({
              pattern: reg,
              message: item.regularText || '请输入数字、字母以及@_.'
              message: item.regularText || dict['enter_num_letter_char'] || '请输入数字、字母以及@_.'
            })
          } else if (item.regular === 'phone') {
            item.rules.push({
              pattern: /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
              message: item.regularText || '请正确输入手机号'
              message: item.regularText || dict['phone_error'] || '请正确输入手机号'
            })
          } else if (item.regular === 'email') {
            item.rules.push({
              pattern: /^([a-zA-Z0-9._-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/,
              message: item.regularText || '请正确输入邮箱地址'
              message: item.regularText || dict['email_error'] || '请正确输入邮箱地址'
            })
          }
        }
      } else if (item.type === 'number') {
        item.rules = [{
          required: true,
          message: item.label + '不可为空!'
          message: item.label + (dict['not_empty'] || '不可为空!')
        }]
        if (typeof(item.min) === 'number' || typeof(item.max) === 'number' || item.notZero === 'true') {
@@ -399,9 +400,9 @@
              if (isNaN(value)) {
                callback()
              } else if (item.notZero === 'true' && value === 0) {
                callback(item.label + '不可为0')
                callback(item.label + (dict['not_zero'] || '不可为0'))
              } else if (typeof(item.min) === 'number' && value < item.min) {
                if (item.min < 1e-6) {
                if (item.min > 0 && item.min < 1e-6) {
                  if (item.min === 1e-6) {
                    callback(item.label + '最小值为 0.000001')
                  } else if (item.min === 1e-7) {
@@ -415,13 +416,13 @@
                  } else if (item.min === 1e-11) {
                    callback(item.label + '最小值为 0.00000000001')
                  } else {
                    callback(item.label + '最小值为 ' + item.min)
                    callback(item.label + (dict['less_limit'] || '最小值为 ') + item.min)
                  }
                } else {
                  callback(item.label + '最小值为 ' + item.min)
                  callback(item.label + (dict['less_limit'] || '最小值为 ') + item.min)
                }
              } else if (typeof(item.max) === 'number' && value > item.max) {
                callback(item.label + '最大值为 ' + item.max)
                callback(item.label + (dict['max_limit'] || '最大值为 ') + item.max)
              } else {
                callback()
              }
@@ -432,14 +433,14 @@
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
            message: item.label + (dict['not_empty'] || '不可为空!')
          })
        }
        item.rules.push({
          validator: (rule, value, callback) => {
            if (/'/.test(value)) {
              callback('不可使用英文状态的单引号!')
              callback(dict['single_quot'] || '不可使用英文状态的单引号!')
            // } else if (/--/.test(value)) {
            //   callback('不可使用 -- !')
            } else {
@@ -448,38 +449,38 @@
          }
        }, {
          max: item.fieldlength,
          message: formRule.input.formMessage.replace('@max', item.fieldlength)
          message: (dict['max_char'] || '最多@max个字符').replace('@max', item.fieldlength)
        })
      } else if (item.type === 'brafteditor') {
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
            message: item.label + (dict['not_empty'] || '不可为空!')
          })
        }
        item.rules.push({
          max: item.fieldlength,
          message: formRule.input.formMessage.replace('@max', item.fieldlength)
          message: (dict['max_char'] || '最多@max个字符').replace('@max', item.fieldlength)
        })
      } else if (item.type === 'linkMain' || item.type === 'vercode') {
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: item.label + '不可为空!'
            message: item.label + (dict['not_empty'] || '不可为空!')
          })
        }
      } else {
        if (item.required === 'true') {
          item.rules.push({
            required: true,
            message: '请选择' + item.label + '!'
            message: (dict['select_tip'] || '请选择') + item.label + '!'
          })
        }
        if (['cascader', 'checkbox', 'checkcard', 'fileupload', 'multiselect'].includes(item.type) && item.fieldlength) {
          item.rules.push({
            max: item.fieldlength,
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
            message: (dict['max_char'] || '最多@max个字符').replace('@max', item.fieldlength)
          })
        }
      }
@@ -748,6 +749,7 @@
    if (action.subButton && action.subButton.resetForms) {
      MKEmitter.addListener('resetForms', this.resetForms)
    }
    MKEmitter.addListener('resetFocus', this.resetFocus)
  }
  componentWillUnmount () {
@@ -755,6 +757,27 @@
      return
    }
    MKEmitter.removeListener('resetForms', this.resetForms)
    MKEmitter.removeListener('resetFocus', this.resetFocus)
  }
  resetFocus = (id, field) => {
    const { action } = this.props
    if (id !== action.uuid) return
    let focusId = ''
    this.state.formlist.forEach(item => {
      if (item.field === field) {
        focusId = item.uuid
      }
    })
    if (!focusId) return
    setTimeout(() => {
      MKEmitter.emit('mkFC', 'focus', focusId)
    }, 20)
  }
  resetForms = (id, data) => {
src/tabviews/zshare/mutilform/mkPopSelect/index.jsx
@@ -39,6 +39,7 @@
    config.dataSource = config.dataSource.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    config.dataSource = config.dataSource.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    config.dataSource = config.dataSource.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    config.dataSource = config.dataSource.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    if (/\s/.test(config.dataSource)) { // 拼接别名
      config.dataSource = '(' + config.dataSource + ') tb'
src/tabviews/zshare/normalTable/index.jsx
@@ -1283,7 +1283,7 @@
    }
    return (
      <div className={'normal-data-table mingke-table ' + (height ? 'fixed-height' : '') + ` table-col-${columns.length}`}>
      <div className={'normal-data-table mingke-table ' + (height ? 'fixed-table-height' : '') + ` table-col-${columns.length}`}>
        <Table
          components={components}
          size={setting.size || 'middle'}
src/tabviews/zshare/normalTable/index.scss
@@ -249,7 +249,7 @@
    }
  }
}
.normal-data-table:not(.fixed-height) {
.normal-data-table:not(.fixed-table-height) {
  .ant-table-body::-webkit-scrollbar {
    width: 8px;
    height: 10px;
@@ -264,13 +264,5 @@
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
}
.normal-data-table.fixed-height {
  .ant-table-body {
    border-bottom: 1px solid rgba(0, 0, 0, .05);
    .ant-table-fixed {
      border-bottom: 0;
    }
  }
}
src/tabviews/zshare/topSearch/index.jsx
@@ -67,6 +67,7 @@
      _setting.wrapperCol = {style: {width: (100 - _setting.labelwidth) + '%'}}
      _setting.borderRadius = config.wrap.borderRadius
      _setting.resetContrl = config.wrap.resetContrl || 'init'
      _setting.size = config.wrap.searchSize || ''
      if (config.wrap.searchBtn === 'show') {
        _setting.showBtn = true
@@ -729,7 +730,7 @@
      const _rules = [
        {
          required: item.required,
          message: item.label + '不可为空!'
          message: item.label + (window.GLOB.dict['not_empty'] || '不可为空!')
        }
      ]
@@ -790,13 +791,13 @@
            wrapperCol={setting.wrapperCol}
          >
            {setting.show ? <Button style={style} type="primary" onClick={this.handleSubmit}>
              搜索
              {window.GLOB.dict['search'] || '搜索'}
            </Button> : null}
            {setting.show ? <Button style={{ marginLeft: 8, ...style }} onClick={this.handleReset}>
              重置
              {window.GLOB.dict['reset'] || '重置'}
            </Button> : null}
            {setting.showAdv ? <Button className={visible ? 'visible' : ''} type="link" onClick={this.handleAdvance}>
              高级{setting.advanceType === 'pulldown' ? <DownOutlined /> : null}
              {window.GLOB.dict['senior'] || '高级'}{setting.advanceType === 'pulldown' ? <DownOutlined /> : null}
            </Button> : null}
          </Form.Item>
        </Col>
@@ -806,7 +807,7 @@
        <Col className="mk-search-col search-button" key="actions">
          <Form.Item>
            <Button type="primary" onClick={this.handleSubmit}>
              搜索
              {window.GLOB.dict['search'] || '搜索'}
            </Button>
          </Form.Item>
        </Col>
@@ -892,7 +893,7 @@
      
            notification.warning({
              top: 92,
              message: '请输入' + labels.join('、') + ' !',
              message: (window.GLOB.dict['input_tip'] || '请输入') + labels.join('、') + ' !',
              duration: 3
            })
            return
@@ -1124,7 +1125,7 @@
    return (
      <>
        <Form {...formItemLayout} className={`mk-search-wrap mk-float-${setting.float}`} style={setting.style}>
        <Form {...formItemLayout} className={`mk-search-wrap mk-float-${setting.float} mk-size-${setting.size}`} style={setting.style}>
          <Row gutter={24}>{this.getFields()}</Row>
          {advanceValues.length && (setting.advanceType !== 'pulldown' || (setting.advanceType === 'pulldown' && !visible)) ? <Row gutter={24}>
            <div className="advanced-list">
@@ -1140,7 +1141,7 @@
          </Row> : null}
        </Form>
        {setting.advanceType === 'modal' ? <Modal
          title="高级搜索"
          title={window.GLOB.dict['adv_search'] || '高级搜索'}
          maskClosable={false}
          visible={visible}
          width={setting.advWidth}
@@ -1156,7 +1157,7 @@
          />
        </Modal> : null}
        {setting.advanceType === 'drawer' ? <Drawer
          title="高级搜索"
          title={window.GLOB.dict['adv_search'] || '高级搜索'}
          className="mk-search-drawer"
          width={setting.advWidth}
          height={setting.advHeight}
src/tabviews/zshare/topSearch/index.scss
@@ -132,6 +132,11 @@
    text-align: right;
  }
}
.mk-search-wrap.mk-size-small {
  .ant-form-item, .search-button {
    min-height: 45px;
  }
}
.mk-search-drawer {
  .ant-drawer-wrapper-body {
    position: relative;
src/templates/modalconfig/dragelement/index.jsx
@@ -66,7 +66,7 @@
    delete val.$srcId
    
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/templates/sharecomponent/actioncomponent/dragaction/index.jsx
@@ -70,7 +70,7 @@
      }
      delete _val.$srcId
    
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/templates/sharecomponent/actioncomponent/verifyexcelin/customscript/index.jsx
@@ -232,11 +232,25 @@
    let _value = ''
    if (value === 'default') {
      let fields = usefulfields.filter(item => item.import !== 'false')
      fields = fields.map(col => col.Column).join(',')
      let fields = []
      let decls = []
      usefulfields.forEach(col => {
        if (col.import === 'false') return
        if (col.type === 'date') {
          decls.push(`${col.Column} Nvarchar(50)`)
        } else {
          decls.push(`${col.Column} ${col.type}`)
        }
        fields.push(col.Column)
      })
      decls = decls.join(',')
      fields = fields.join(',')
      
      if (fields) {
        fields = fields + ','
        decls = decls + ','
      }
      let database = btn.sheet.match(/(.*)\.(.*)\.|@db@/ig) || ''
@@ -244,7 +258,7 @@
      database = database ? (database[0] || '') : ''
      _value = `Insert into ${database}${sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From #${sheet}`
      _value = `/* create table #${sheet} (${decls}jskey nvarchar(50),BID nvarchar(50) ) */\nInsert into ${database}${sheet} (${fields}createuserid,createuser,createstaff,bid)\nSelect ${fields}@userid@,@username,@fullname,@BID@ From #${sheet}`
    } else if (value === 'flowSql') {
      let sheet = btn.sheet.replace(/(.*)\.(.*)\.|@db@/ig, '')
@@ -318,7 +332,7 @@
          </Col> : null}
          {!type ? <Col span={24} className="sqlfield">
            <Form.Item label="可用字段">
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename</span></Tooltip>,&nbsp;
              {workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="工作流变量,请按照@xxx@格式使用。"><span style={{color: '#26C281'}}>works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, </span></Tooltip> : null}
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              {usefulfields}
src/templates/sharecomponent/actioncomponent/verifyexcelout/customscript/index.jsx
@@ -215,7 +215,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, typename</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, 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>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'排序、分页以及搜索条件变量,请按照@xxx@格式使用。'}>, orderBy, pageSize, pageIndex{usefulfields ? ', ' + usefulfields : ''}</Tooltip>
              {linefields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'表单及行变量,系统会定义变量并赋值。'}>,&nbsp;{linefields}</Tooltip> : null}
src/templates/sharecomponent/actioncomponent/verifyexcelout/utils.jsx
@@ -50,7 +50,7 @@
      _dataresource = '(' + _dataresource + ') tb'
    }
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    let custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_dataresource + _customScript)
    
    // 正则替换
    regoptions.push({
@@ -73,6 +73,10 @@
      value: ''
    })
    if (window.GLOB.process) {
      regoptions.push({reg: /@works_flow_code@/ig, value: `'mk_flow_code'`})
    }
    regoptions.forEach(item => {
      _dataresource = _dataresource.replace(item.reg, item.value)
      _customScript = _customScript.replace(item.reg, item.value)
src/templates/sharecomponent/actioncomponent/verifyprint/utils.jsx
@@ -34,7 +34,7 @@
      _dataresource = '(' + _dataresource + ') tb'
    }
    let custompage = /@pageSize@|@orderBy@/i.test(_dataresource + _customScript)
    let custompage = /@pageSize@|@orderBy@|@mk_total/i.test(_dataresource + _customScript)
    // 正则替换
    let regoptions = [{
src/templates/sharecomponent/columncomponent/index.jsx
@@ -373,7 +373,7 @@
      columns: columnlist
    }
    let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
    let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
    if (srcid) {
      val.$srcId = srcid
    }
src/templates/sharecomponent/searchcomponent/dragsearch/index.jsx
@@ -54,7 +54,7 @@
    try {
      delete _val.$srcId
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        _val.$srcId = srcid
      }
src/templates/sharecomponent/searchcomponent/index.jsx
@@ -205,7 +205,7 @@
        return
      }
      if (['checkcard', 'select', 'multiselect', 'link'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
      if (['checkcard', 'select', 'multiselect', 'link'].includes(res.type) && res.resourceType === '1' && res.database !== 'sso' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
@@ -213,13 +213,8 @@
        let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
        ${res.dataSource}`
        sql = sql.replace(/@\$|\$@/ig, '')
        let rduri = ''
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          rduri = window.GLOB.mainSystemApi
        }
        
        Api.sDebug(sql, rduri).then(result => {
        Api.sDebug(sql).then(result => {
          if (result.status || result.ErrCode === '-2') {
            this.setState({
              sqlVerifing: false,
@@ -330,8 +325,13 @@
    const { config } = this.props
    const { searchlist, visible, sqlVerifing, card, showField, setVisible } = this.state
    let size = ''
    if (config.wrap && config.wrap.searchSize) {
      size = ' mk-size-' + config.wrap.searchSize
    }
    return (
      <div className={'model-table-search-list length' + searchlist.length + (showField ? ' show-field' : '')}>
      <div className={'model-table-search-list length' + searchlist.length + (showField ? ' show-field' : '') + size}>
        <FieldsComponent config={{uuid: config.uuid, search: searchlist}} type="search" />
        <Switch className="switch-field-show" checkedChildren="开" unCheckedChildren="关" defaultChecked={showField} onChange={this.onFieldChange} />
        <DragElement
@@ -347,7 +347,7 @@
          title={card && card.copyType === 'search' ?  '搜索条件-复制' : '搜索条件-编辑'}
          wrapClassName="mk-scroll-modal"
          visible={visible}
          width={850}
          width={950}
          maskClosable={false}
          onOk={this.handleSubmit}
          confirmLoading={sqlVerifing}
src/templates/sharecomponent/searchcomponent/index.scss
@@ -141,4 +141,14 @@
      display: block;
    }
  }
}
.model-table-search-list.mk-size-small {
  .page-card {
    height: 45px;
  }
  .mk-search-item-wrap.action {
    .ant-form-item {
      height: 45px!important;
    }
  }
}
src/templates/sharecomponent/searchcomponent/searchform/index.jsx
@@ -234,8 +234,11 @@
        if (this.record.selectStyle === 'custom') {
          shows.push('backgroundColor')
        }
        if (this.record.multiple === 'dropdown' && this.record.resourceType === '1') {
          shows.push('mark', 'parentField')
        if (this.record.multiple === 'dropdown') {
          shows.push('mark')
          if (this.record.resourceType === '1') {
            shows.push('parentField')
          }
        }
      }
      shows.push('linkField')
@@ -595,19 +598,18 @@
          { required: item.required, message: '请输入' + item.label + '!' }
        ]
        span = 24
        className = 'text-area'
        if (this.record.type === 'select' || this.record.type === 'link') {
          extra = <span className="add-resource-empty" onClick={this.handleEmpty}>全部</span>
        }
        if (item.placeholder) {
          className = 'show-public-var'
          extra = <><span className="resource-public-var">{item.placeholder}</span>{extra}</>
        }
        content = <CodeMirror />
      } else if (item.type === 'options') {
        span = 24
        className = 'text-area'
        let type = this.record.type
        
@@ -654,7 +656,6 @@
        }
      } else if (item.type === 'fields') {
        span = 24
        className = 'text-area'
        rules = [
          { required: item.required, message: '请添加' + item.label + '!' }
@@ -667,7 +668,7 @@
        ]
        content = <Checkbox.Group style={{width: '105%'}} options={item.options} onChange={(values) => this.optionChange(item.key, values)}/>
      } else if (item.type === 'multiselect') { // 多选
      } else if (item.type === 'multiselect') {
        content = <Select
          showSearch
          mode="multiple"
@@ -677,8 +678,8 @@
            <Select.Option id={i} key={i} value={option.value}>{option.text}</Select.Option>
          )}
        </Select>
      } else if (item.type === 'cascader') { // 多选
        content = <Cascader options={item.options} placeholder="" />
      } else if (item.type === 'cascader') {
        content = <Cascader options={item.options} />
      } else if (item.type === 'color') {
        className = 'color-form-item'
        rules = [
src/templates/sharecomponent/searchcomponent/searchform/index.scss
@@ -4,7 +4,7 @@
    padding-left: 6px!important;
    padding-bottom: 20px;
  }
  .ant-form-item.text-area {
  .ant-col-24 {
    // margin-bottom: 0px;
    .ant-form-item-control-wrapper {
      width: 84%;
@@ -45,10 +45,15 @@
    cursor: pointer;
    font-size: 14px;
  }
  .show-public-var {
    margin-top: 20px;
  }
  .resource-public-var {
    position: absolute;
    left: 0px;
    top: -22px;
    font-size: 14px;
    top: -45px;
    right: 40px;
    font-size: 13px;
    color: rgba(0, 0, 0, 0.65);
  }
}
src/templates/zshare/codemirror/index.jsx
@@ -169,8 +169,7 @@
        return
      }
      let _href = window.location.href.split('#')[0]
      localStorage.setItem(_href + 'sql_char', JSON.stringify([res.origin, res.value]))
      localStorage.setItem(window.GLOB.sysSign + 'sql_char', JSON.stringify([res.origin, res.value]))
      _sql = _sql.replace(reg, res.value)
src/templates/zshare/customscript/index.jsx
@@ -333,7 +333,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, lang, 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;
                <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'排序、分页以及搜索条件变量,请按照@xxx@格式使用。'}>orderBy{setting.laypage === 'true' ? ', pageSize, pageIndex': ''}{usefulFields ? ', ' + usefulFields : ''}</Tooltip>
                {urlFields ?<Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'url变量,请按照@xxx@格式使用。'}>, <span style={{color: '#13c2c2'}}>{urlFields}</span></Tooltip> : ''}
src/templates/zshare/editTable/index.jsx
@@ -419,7 +419,7 @@
    }
    try {
      let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
      let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
      if (srcid) {
        msg.$srcId = srcid
      }
src/templates/zshare/formconfig.jsx
@@ -261,7 +261,7 @@
      label: '数据源',
      initVal: card.dataSource || '',
      tooltip: '数据权限替换符 $@ -> /* 或 \'\'、 @$ -> */ 或 \'\'',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@BID@、@Appkey@、@UserID@、@SessionUid@、@LoginUID@、@lang@。',
      required: true
    },
    {
@@ -444,7 +444,7 @@
        text: '本地'
      }, {
        value: 'sso',
        text: '系统'
        text: '单点'
      }]
    },
    {
@@ -1012,12 +1012,20 @@
  let options = card.options || []
  if (['select', 'radio', 'link'].includes(card.type) && card.setAll === 'true') { // 兼容
    options.unshift({
    let cell = {
      key: 'empty',
      Value: '',
      Text: card.emptyText || '空',
      ParentID: ''
    })
    }
    if (card.linkSubField) {
      card.linkSubField.forEach(m => {
        cell[m] = ''
      })
    }
    options.unshift(cell)
  }
  let initval = card.initval || ''
@@ -1199,7 +1207,7 @@
      label: '数据源',
      initVal: card.dataSource || '',
      tooltip: '数据权限替换符 $@ -> /* 或 \'\'、 @$ -> */ 或 \'\'',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@ID@、@BID@。',
      placeholder: '系统变量:mk_departmentcode、mk_organization、mk_user_type。公共值:@ID@、@BID@、@Appkey@、@UserID@、@SessionUid@、@LoginUID@、@lang@。',
      required: true,
      readonly: false
    },
@@ -1869,7 +1877,7 @@
        text: '本地'
      }, {
        value: 'sso',
        text: '系统'
        text: '单点'
      }]
    },
    {
src/templates/zshare/modalform/index.jsx
@@ -764,6 +764,7 @@
          extra = <span className="add-resource-empty" onClick={this.handleEmpty}>空</span>
        }
        if (item.placeholder) {
          className = 'show-public-var'
          extra = <><span className="resource-public-var">{item.placeholder}</span>{extra}</>
        }
@@ -1095,22 +1096,17 @@
          window.GLOB.formId = card.uuid
          if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(values.type) && values.resourceType === '1' && values.dataSource) {
          if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(values.type) && values.resourceType === '1' && values.database !== 'sso' && values.dataSource) {
            let _option = Utils.getSelectQueryOptions(values)
            let sql = `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${_option.sql}`
    
            // LoginUID|SessionUid|UserID|Appkey 已替换
            // LoginUID|SessionUid|UserID|Appkey|lang 已替换
            sql = sql.replace(/@\$|\$@/ig, '')
            let rduri = ''
            if (window.GLOB.mainSystemApi && values.database === 'sso') {
              rduri = window.GLOB.mainSystemApi
            }
            
            resolve({values, loading: true, promise: () => new Promise((resolve, reject) => {
              Api.sDebug(sql, rduri).then(result => {
              Api.sDebug(sql).then(result => {
                if (result.status || result.ErrCode === '-2') {
                  resolve()
                } else {
src/templates/zshare/modalform/index.scss
@@ -46,10 +46,15 @@
    cursor: pointer;
    font-size: 14px;
  }
  .show-public-var {
    margin-top: 20px;
  }
  .resource-public-var {
    position: absolute;
    left: 0px;
    top: -25px;
    font-size: 14px;
    top: -45px;
    right: 40px;
    font-size: 13px;
    color: rgba(0, 0, 0, 0.65);
  }
}
src/templates/zshare/pasteform/index.jsx
@@ -41,7 +41,7 @@
            _config = JSON.parse(window.decodeURIComponent(window.atob(_config)))
            if (typeof(_config) === 'object' && _config.$srcId) {
              let srcid = localStorage.getItem(window.location.href.split('#')[0] + 'srcId')
              let srcid = localStorage.getItem(window.GLOB.sysSign + 'srcId')
              if (srcid && _config.$srcId !== srcid) {
                notification.warning({
                  top: 92,
src/templates/zshare/verifycard/callbackcustomscript/index.jsx
@@ -227,7 +227,7 @@
          </Col> : null}
          {!type ? <Col span={24} className="sqlfield">
            <Form.Item label="可用字段">
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'公共值,请按照@xxx@格式使用。'}><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename, datam</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="表单变量,系统会定义变量并赋值。">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
src/templates/zshare/verifycard/customform/index.jsx
@@ -130,7 +130,7 @@
        <Row gutter={24}>
          <Col span={21} 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, lang, 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, mk_deleted</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {formfields ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="表单变量,系统会定义变量并赋值。">, <span style={{color: '#8E44AD'}}>{formfields}</span></Tooltip> : ''}
src/templates/zshare/verifycard/customscript/index.jsx
@@ -359,7 +359,7 @@
          </Col> : null}
          {!_type ? <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="公共值,请按照@xxx@格式使用。"><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, time_id, typename, datam</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="公共值,请按照@xxx@格式使用。"><span style={{color: '#1890ff'}}>BID, ID, LoginUID, SessionUid, UserID, Appkey, lang, time_id, typename, datam</span></Tooltip>,&nbsp;
              {window.GLOB.process && workFlow === 'true' ? <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="工作流变量,请按照@xxx@格式使用,works_flow_sign 为分支启用高级设置时的标记值。"><span style={{color: '#26C281'}}>works_flow_code, works_flow_name, works_flow_param, works_flow_detail_id, status, statusname, work_group, work_grade, start_type, check_type, notice_type, check_userids, notice_userids, works_flow_sign, </span></Tooltip> : null}
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="系统变量,系统会定义变量并赋值。"><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address, mk_deleted</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title="系统变量,系统会定义变量并在单号生成或创建凭证时使用。"><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
src/utils/utils-custom.js
@@ -558,6 +558,9 @@
          })
        }
      } else if (item.type === 'form') {
        if (item.wrap.datatype === 'public' && item.wrap.publicId) {
          item.wrap.publicId = md5(commonId + item.wrap.publicId)
        }
        item.subcards = item.subcards.map(cell => {
          cell.uuid = this.getuuid()
  
@@ -626,7 +629,7 @@
        })
      }
      if (item.setting && item.setting.supModule && item.setting.supModule[0] !== 'empty') {
      if (item.setting && item.setting.supModule && item.setting.supModule[0] !== 'empty' && item.setting.supModule[0] !== 'preview') {
        item.setting.supModule = item.setting.supModule.map(c => {
          return md5(commonId + c)
        })
@@ -1105,6 +1108,8 @@
        value = item.initval || `${item.minValue || '-999999999'},${item.maxValue || '999999999'}`
      } else if (item.type === 'multiselect' || (item.type === 'checkcard' && item.multiple === 'true')) {
        type = 'multi'
      } else {
        value = item.initval || '0'
      }
      newsearches.push({
@@ -1794,23 +1799,31 @@
      if (!cell.modal || cell.modal.fields.length === 0) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中表单尚未添加`})
      }
    } else if (cell.OpenType === 'excelIn' && (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0)) {
      errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
    } else if (cell.OpenType === 'excelIn') {
      if (!cell.verify || !cell.verify.sheet || !cell.verify.columns || cell.verify.columns.length === 0) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中导入列未设置!`})
      }
    } else if (cell.OpenType === 'excelOut') {
      if (!cell.verify || !cell.verify.columns || cell.verify.columns.length === 0) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列未设置!`})
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom' && card.$c_ds && columns.length > 0) {
        let cols = []
        cell.verify.columns.forEach(col => {
          if (col.output === 'false' || col.Column === '$Index') return
          if (!columns.includes(col.Column)) {
            cols.push(col.Column)
      } else if (cell.intertype === 'system' && cell.verify.dataType !== 'custom') {
        if (!card.setting || card.setting.interType !== 'system') {
          errors.push({ level: 0, detail: `按钮“${cell.label}”需自定义导出数据源!`})
        } else if (card.type === 'balcony' || card.subtype === 'propcard') {
          errors.push({ level: 0, detail: `按钮“${cell.label}”需自定义导出数据源!`})
        } else if (card.$c_ds && columns.length > 0) {
          let cols = []
          cell.verify.columns.forEach(col => {
            if (col.output === 'false' || col.Column === '$Index') return
            if (!columns.includes(col.Column)) {
              cols.push(col.Column)
            }
          })
          if (cols.length) {
            errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列(${cols.join('、')})在字段集中不存在!`})
          }
        })
        if (cols.length) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”中导出列(${cols.join('、')})在字段集中不存在!`})
        }
      }
      }
    }
    if (['pop', 'prompt', 'exec'].includes(cell.OpenType) && cell.verify && !cell.output) {
@@ -1818,6 +1831,32 @@
        errors.push({ level: 0, detail: `按钮“${cell.label}”未设置返回值短信发送无效!`})
      } else if (cell.verify.emailEnable === 'true') {
        errors.push({ level: 0, detail: `按钮“${cell.label}”未设置返回值邮件发送无效!`})
      }
    }
    if (['exec', 'prompt', 'pop', 'form', 'formSubmit'].includes(cell.OpenType)) {
      if (cell.OpenType === 'form' && cell.formType === 'count_line') return
      if (cell.intertype === 'system') {
        if (cell.Ot === 'notRequired' && cell.verify && cell.verify.voucher && cell.verify.voucher.enabled) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”使用了创建凭证函数,需要选择行!`})
        }
      } else if (cell.intertype === 'custom' || cell.intertype === 'outer') {
        if (cell.callbackType === 'script' && (!cell.verify || !cell.verify.cbScripts || !cell.verify.cbScripts.filter(item => item.status !== 'false').length === 0)) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”使用了自定义脚本回调,回调脚本不可为空!`})
        } else if (cell.procMode === 'system' && cell.Ot === 'notRequired' && cell.verify && cell.verify.voucher && cell.verify.voucher.enabled) {
          errors.push({ level: 0, detail: `按钮“${cell.label}”使用了创建凭证函数,需要选择行!`})
        }
      }
    } else if (cell.OpenType === 'funcbutton' && cell.funcType === 'print') {
      if (!cell.verify || !cell.verify.printMode) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”请完善验证信息!`})
      } else if (cell.intertype === 'system' && cell.verify.dataType === 'custom' && (!cell.verify.setting || cell.verify.columns.length === 0)) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”使用了自定义打印数据,请设置数据源!`})
      }
    } else if (cell.OpenType === 'innerpage' || cell.OpenType === 'outerpage') {
      if (!cell.pageTemplate) {
        errors.push({ level: 0, detail: `按钮“${cell.label}”页面类型设置错误!`})
      }
    }
  }
@@ -2004,6 +2043,13 @@
      duration: 5
    })
    return false
  } else if (/\send\s+begin\s/ig.test(sql)) {
    notification.warning({
      top: 92,
      message: `end 后不可紧跟 begin。`,
      duration: 5
    })
    return false
  } else if (type === 'customscript' && /\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig.test(sql)) {
    let list = sql.match(/\son\s+[a-z0-9_]+\.[a-z0-9_]+\s*=\s*[a-z0-9_]+\.[a-z0-9_]+/ig)
    let errors = []
@@ -2064,4 +2110,725 @@
  }
  return true
}
/**
 * @description 获取语言转换信息
 */
export function getLangTrans (config) {
  let langList = sessionStorage.getItem('langList')
  let appType = sessionStorage.getItem('appType')
  if (appType === 'mob' || appType === 'pc') {
    langList = sessionStorage.getItem('applangList')
  }
  if (!langList) return
  let defLang = ''
  try {
    langList = JSON.parse(langList)
    defLang = langList[0]
  } catch (e) {
    defLang = ''
  }
  if (!defLang) return ''
  let sql = []
  let btn = []
  let ops = []
  let text = []
  let menu = []
  let filterElement = (card) => {
    if (card.datatype === 'static' && card.eleType === 'text' && !/@.+@/g.test(card.value)) {
      sql.push(card.value)
    }
    if (card.prefix) {
      sql.push(card.prefix)
    }
    if (card.postfix) {
      sql.push(card.postfix)
    }
  }
  let filterSql = (sl) => {
    if (!sl) return
    let cutreg = /[\u4E00-\u9FA5。!,、]+/ig
    let tbs = sl.match(cutreg)
    if (!tbs) return
    text.push(...tbs)
  }
  let filterBtn = (btn) => {
    if (!btn.verify) return
    btn.verify.customverifys && btn.verify.customverifys.forEach(script => {
      filterSql(script.sql)
    })
    btn.verify.scripts && btn.verify.scripts.forEach(script => {
      filterSql(script.sql)
    })
    btn.verify.cbScripts && btn.verify.cbScripts.forEach(script => {
      filterSql(script.sql)
    })
    if (btn.OpenType === 'funcbutton') {
      if (btn.intertype === 'system' && btn.verify.dataType === 'custom' && btn.verify.setting) {
        filterSql(btn.verify.setting.dataresource)
      }
    } else if (btn.OpenType === 'excelOut') {
      filterSql(btn.verify.dataresource)
    }
  }
  let filterForm = (n) => {
    sql.push(n.label)
    if (n.resourceType === '1') {
      filterSql(n.dataSource)
    } else if (n.options) {
      n.options.forEach(o => {
        ops.push(o.Text)
      })
    }
  }
  let traversal = (components) => {
    if (!components) return
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          sql.push(tab.label)
          traversal(tab.components)
        })
      } else if (item.type === 'group') {
        traversal(item.components)
      } else {
        if (item.setting && (!item.wrap || !item.wrap.datatype || item.wrap.datatype === 'dynamic')) {
          if (item.setting.interType === 'system') {
            filterSql(item.setting.dataresource)
            item.scripts && item.scripts.forEach(script => {
              filterSql(script.sql)
            })
          }
        }
        if (item.columns) {
          item.columns.forEach(cell => {
            sql.push(cell.label)
          })
        }
        if (item.search) {
          if (item.type === 'topbar') {
            if (item.search.fields) {
              item.search.fields.forEach(cell => {
                filterForm(cell)
              })
            }
            if (item.search.groups) {
              item.search.groups.forEach(group => {
                if (group.fields) {
                  group.fields.forEach(cell => {
                    filterForm(cell)
                  })
                }
              })
            }
          } else {
            item.search.forEach(cell => {
              filterForm(cell)
            })
          }
        }
        if (item.action) {
          item.action.forEach(cell => {
            btn.push(cell.label)
            filterBtn(cell)
            if (cell.OpenType === 'popview' && cell.config) {
              traversal(cell.config.components)
            } else if (cell.OpenType === 'pop') {
              if (cell.modal && cell.modal.fields.length) {
                cell.modal.fields.forEach(n => {
                  filterForm(n)
                })
              }
            }
          })
        }
        if (item.type === 'navbar') {
          if (item.menus) {
            item.menus.forEach(first => {
              menu.push(first.name)
              if (first.sublist) {
                first.sublist.forEach(sec => {
                  menu.push(sec.name)
                  if (sec.sublist) {
                    sec.sublist.forEach(thd => {
                      menu.push(thd.name)
                    })
                  }
                })
              }
            })
          }
        } else if (item.type === 'menubar') {
          item.subMenus.forEach(cell => {
            if (cell.setting.name) {
              menu.push(cell.setting.name)
            }
          })
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType === 'button') {
                btn.push(cell.label)
                filterBtn(cell)
                if (cell.OpenType === 'popview' && cell.config) {
                  traversal(cell.config.components)
                } else if (cell.OpenType === 'pop') {
                  if (cell.modal && cell.modal.fields.length) {
                    cell.modal.fields.forEach(n => {
                      filterForm(n)
                    })
                  }
                }
              } else {
                filterElement(cell)
              }
            })
            card.backElements && card.backElements.forEach(cell => {
              if (cell.eleType === 'button') {
                btn.push(cell.label)
                filterBtn(cell)
                if (cell.OpenType === 'popview' && cell.config) {
                  traversal(cell.config.components)
                } else if (cell.OpenType === 'pop') {
                  if (cell.modal && cell.modal.fields.length) {
                    cell.modal.fields.forEach(n => {
                      filterForm(n)
                    })
                  }
                }
              } else {
                filterElement(cell)
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType === 'button') {
              btn.push(cell.label)
              filterBtn(cell)
              if (cell.OpenType === 'popview' && cell.config) {
                traversal(cell.config.components)
              } else if (cell.OpenType === 'pop') {
                if (cell.modal && cell.modal.fields.length) {
                  cell.modal.fields.forEach(n => {
                    filterForm(n)
                  })
                }
              }
            } else {
              filterElement(cell)
            }
          })
        } else if (item.type === 'table') {
          let loopCol = (cols) => {
            cols.forEach(col => {
              sql.push(col.label)
              if (col.prefix) {
                sql.push(col.prefix)
              }
              if (col.postfix) {
                sql.push(col.postfix)
              }
              if (col.type === 'colspan') {
                loopCol(col.subcols)
              } else if (col.type === 'custom') {
                col.elements.forEach(cell => {
                  if (cell.eleType === 'button') {
                    btn.push(cell.label)
                    filterBtn(cell)
                    if (cell.OpenType === 'popview' && cell.config) {
                      traversal(cell.config.components)
                    } else if (cell.OpenType === 'pop') {
                      if (cell.modal && cell.modal.fields.length) {
                        cell.modal.fields.forEach(n => {
                          filterForm(n)
                        })
                      }
                    }
                  } else {
                    filterElement(cell)
                  }
                })
              }
            })
          }
          loopCol(item.cols)
        } else if (item.type === 'form') {
          item.subcards.forEach(cell => {
            filterBtn(cell.subButton)
            cell.fields.forEach(n => {
              filterForm(n)
            })
          })
        }
      }
    })
  }
  if (config.interfaces) {
    config.interfaces.forEach(item => {
      if (item.setting.interType === 'system') {
        filterSql(item.setting.dataresource)
        item.scripts && item.scripts.forEach(script => {
          filterSql(script.sql)
        })
      }
    })
  }
  traversal(config.components)
  if (config.MenuName) {
    menu.push(config.MenuName)
  }
  if (config.fstMenuId && config.parentId && config.fstMenuId !== 'BillPrintTemp') {
    let menulist = sessionStorage.getItem('fstMenuList')
    try {
      menulist = JSON.parse(menulist)
    } catch(e) {
      menulist = []
    }
    menulist.forEach(item => {
      if (item.MenuID !== config.fstMenuId) return
      menu.push(item.MenuName)
      item.children.forEach(cell => {
        if (cell.MenuID !== config.parentId) return
        menu.push(cell.MenuName)
      })
    })
  }
  sql = sql.filter(Boolean)
  btn = btn.filter(Boolean)
  ops = ops.filter(Boolean)
  text = text.filter(Boolean)
  menu = menu.filter(Boolean)
  sql = Array.from(new Set(sql))
  btn = Array.from(new Set(btn))
  ops = Array.from(new Set(ops))
  text = Array.from(new Set(text))
  menu = Array.from(new Set(menu))
  sql = sql.map(l => `'${l}','title'`)
  btn = btn.map(l => `'${l}','button'`)
  ops = ops.map(l => `'${l}','list'`)
  text = text.map(l => `'${l}','text'`)
  menu = menu.map(l => `'${l}','menu'`)
  let list = [...menu, ...btn, ...sql, ...ops, ...text]
  let result = []
  langList.forEach(lan => {
    if (lan === defLang) return
    list.forEach(n => {
      result.push(`'${lan}',${n}`)
    })
  })
  config.trans = true
  return result.join(';')
}
/**
 * @description 语言转换
 */
export function setLangTrans (config, btnDict, titDict, lisDict, menuDict, regs, tail) {
  let filterElement = (card) => {
    if (card.datatype === 'static' && card.eleType === 'text' && !/@.+@/g.test(card.value)) {
      if (card.value && titDict[card.value]) {
        card.value = titDict[card.value]
      }
    }
    if (card.prefix && titDict[card.prefix]) {
      card.prefix = titDict[card.prefix]
    }
    if (card.postfix && titDict[card.postfix]) {
      card.postfix = titDict[card.postfix]
    }
  }
  let filterSql = (sl) => {
    if (!sl) return
    regs.forEach(item => {
      sl = sl.replace(item.reg, item.value)
    })
    return sl
  }
  let filterBtn = (btn) => {
    if (btn.label && btnDict[btn.label]) {
      btn.label = btnDict[btn.label]
    }
    if (btn.OpenType === 'tab' && btn.linkmenu) {
      if (btn.linkmenu[0] === 'multiMenu') {
        btn.multiMenus.forEach(menu => {
          menu.menuId = menu.menuId.map(c => {
            if (c.length <= 24) {
              return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
            } else {
              return c.slice(0, 24) + tail
            }
          })
          menu.MenuID = menu.menuId[menu.menuId.length - 1]
        })
      } else {
        btn.linkmenu = btn.linkmenu.map(c => {
          if (c.length <= 24) {
            return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
          } else {
            return c.slice(0, 24) + tail
          }
        })
        btn.MenuID = btn.linkmenu[btn.linkmenu.length - 1]
      }
    } else {
      if (btn.refreshTab && btn.refreshTab.length > 0) {
        btn.refreshTab = btn.refreshTab.map(c => {
          if (c.length <= 24) {
            return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
          } else {
            return c.slice(0, 24) + tail
          }
        })
      }
      if (btn.openmenu && Array.isArray(btn.openmenu) && btn.openmenu.length > 0) {
        btn.openmenu = btn.openmenu.map(c => {
          if (c.length <= 24) {
            return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
          } else {
            return c.slice(0, 24) + tail
          }
        })
        btn.MenuID = btn.openmenu[btn.openmenu.length - 1]
      } else if (btn.openmenu && typeof(btn.openmenu) === 'string' && btn.openmenu !== 'goback') {
        btn.openmenu = btn.openmenu.slice(0, 24) + tail
      }
      if (btn.pageTemplate === 'linkpage' && btn.linkmenu && typeof(btn.linkmenu) === 'string') {
        btn.linkmenu = btn.linkmenu.slice(0, 24) + tail
      }
    }
    if (!btn.verify) return
    btn.verify.customverifys && btn.verify.customverifys.forEach(script => {
      script.sql = filterSql(script.sql)
    })
    btn.verify.scripts && btn.verify.scripts.forEach(script => {
      script.sql = filterSql(script.sql)
    })
    btn.verify.cbScripts && btn.verify.cbScripts.forEach(script => {
      script.sql = filterSql(script.sql)
    })
    if (btn.OpenType === 'funcbutton') {
      if (btn.intertype === 'system' && btn.verify.dataType === 'custom' && btn.verify.setting) {
        btn.verify.setting.dataresource = filterSql(btn.verify.setting.dataresource)
      }
    } else if (btn.OpenType === 'excelOut' && btn.verify.dataresource) {
      btn.verify.dataresource = filterSql(btn.verify.dataresource)
    }
  }
  let filterForm = (n) => {
    if (n.label && titDict[n.label]) {
      n.label = titDict[n.label]
    }
    if (n.resourceType === '1') {
      n.dataSource = filterSql(n.dataSource)
    } else if (n.options) {
      n.options.forEach(o => {
        if (o.Text && lisDict[o.Text]) {
          o.Text = lisDict[o.Text]
        }
      })
    }
  }
  let resetMenu = (wrap) => {
    if (!wrap.menu) return
    if (typeof(wrap.menu) === 'string') {
      wrap.menu = wrap.menu.slice(0, 24) + tail
      if (wrap.MenuID) {
        wrap.MenuID = wrap.menu
      }
    } else {
      wrap.menu = wrap.menu.map(c => {
        if (c.length <= 24) {
          return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
        } else {
          return c.slice(0, 24) + tail
        }
      })
      if (wrap.MenuID) {
        wrap.MenuID = wrap.menu[wrap.menu.length - 1]
      }
    }
  }
  let resetMenus = (wrap) => {
    if (!wrap.menus) return
    wrap.menus.forEach(m => {
      if (typeof(m.menu) === 'string') {
        m.menu = m.menu.slice(0, 24) + tail
      } else {
        m.menu = m.menu.map(c => {
          if (c.length <= 24) {
            return md5(window.GLOB.appkey + c + sessionStorage.getItem('lang')).toLowerCase()
          } else {
            return c.slice(0, 24) + tail
          }
        })
        if (m.MenuID) {
          m.MenuID = m.menu[m.menu.length - 1]
        }
      }
    })
  }
  let traversal = (components) => {
    if (!components) return
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          if (tab.label && titDict[tab.label]) {
            tab.label = titDict[tab.label]
          }
          traversal(tab.components)
        })
      } else if (item.type === 'group') {
        traversal(item.components)
      } else {
        if (item.wrap && (item.wrap.click === 'menu' || item.wrap.click === 'menus')) {
          if (item.wrap.click === 'menu') {
            resetMenu(item.wrap)
          } else if (item.wrap.click === 'menus') {
            resetMenus(item.wrap)
          }
        } else if (item.plot && (item.plot.click === 'menu' || item.plot.click === 'menus')) {
          if (item.plot.click === 'menu') {
            resetMenu(item.plot)
          } else if (item.plot.click === 'menus') {
            resetMenus(item.plot)
          }
        }
        if (item.setting && (!item.wrap || !item.wrap.datatype || item.wrap.datatype === 'dynamic')) {
          if (item.setting.interType === 'system') {
            item.setting.dataresource = filterSql(item.setting.dataresource)
            item.scripts && item.scripts.forEach(script => {
              script.sql = filterSql(script.sql)
            })
          }
        }
        if (item.columns) {
          item.columns.forEach(cell => {
            if (cell.label && titDict[cell.label]) {
              cell.label = titDict[cell.label]
            }
          })
        }
        if (item.search) {
          if (item.type === 'topbar') {
            if (item.search.fields) {
              item.search.fields.forEach(cell => {
                filterForm(cell)
              })
            }
            if (item.search.groups) {
              item.search.groups.forEach(group => {
                if (group.fields) {
                  group.fields.forEach(cell => {
                    filterForm(cell)
                  })
                }
              })
            }
          } else {
            item.search.forEach(cell => {
              filterForm(cell)
            })
          }
        }
        if (item.action) {
          item.action.forEach(cell => {
            filterBtn(cell)
            if (cell.OpenType === 'popview' && cell.config) {
              traversal(cell.config.components)
            } else if (cell.OpenType === 'pop') {
              if (cell.modal && cell.modal.fields.length) {
                cell.modal.fields.forEach(n => {
                  filterForm(n)
                })
              }
            }
          })
        }
        if (item.type === 'navbar') {
          item.uuid = item.uuid.slice(0, 24) + tail
        } else if (item.type === 'login') {
          item.wrap.linkmenu = item.wrap.linkmenu.slice(0, 24) + tail
        } else if (item.type === 'menubar') {
          item.subMenus = item.subMenus.map(cell => {
            if (cell.setting.name && menuDict[cell.setting.name]) {
              cell.setting.name = menuDict[cell.setting.name]
            }
            if (cell.setting.type === 'linkmenu') {
              cell.setting.linkMenuId = cell.setting.linkMenuId.slice(0, 24) + tail
            }
            return cell
          })
        } else if (item.type === 'topbar') {
          if (item.wrap.menus) {
            resetMenus(item.wrap)
          }
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            if (card.setting.click === 'menus') {
              resetMenus(card)
            } else if (card.setting.click === 'menu') {
              resetMenu(card.setting)
            }
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType === 'button') {
                filterBtn(cell)
                if (cell.OpenType === 'popview' && cell.config) {
                  traversal(cell.config.components)
                } else if (cell.OpenType === 'pop') {
                  if (cell.modal && cell.modal.fields.length) {
                    cell.modal.fields.forEach(n => {
                      filterForm(n)
                    })
                  }
                }
              } else {
                filterElement(cell)
              }
            })
            card.backElements && card.backElements.forEach(cell => {
              if (cell.eleType === 'button') {
                filterBtn(cell)
                if (cell.OpenType === 'popview' && cell.config) {
                  traversal(cell.config.components)
                } else if (cell.OpenType === 'pop') {
                  if (cell.modal && cell.modal.fields.length) {
                    cell.modal.fields.forEach(n => {
                      filterForm(n)
                    })
                  }
                }
              } else {
                filterElement(cell)
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType === 'button') {
              filterBtn(cell)
              if (cell.OpenType === 'popview' && cell.config) {
                traversal(cell.config.components)
              } else if (cell.OpenType === 'pop') {
                if (cell.modal && cell.modal.fields.length) {
                  cell.modal.fields.forEach(n => {
                    filterForm(n)
                  })
                }
              }
            } else {
              filterElement(cell)
            }
          })
        } else if (item.type === 'table') {
          let loopCol = (cols) => {
            cols.forEach(col => {
              if (col.label && titDict[col.label]) {
                col.label = titDict[col.label]
              }
              if (col.prefix && titDict[col.prefix]) {
                col.prefix = titDict[col.prefix]
              }
              if (col.postfix && titDict[col.postfix]) {
                col.postfix = titDict[col.postfix]
              }
              if (col.type === 'colspan') {
                loopCol(col.subcols)
              } else if (col.type === 'custom') {
                col.elements.forEach(cell => {
                  if (cell.eleType === 'button') {
                    filterBtn(cell)
                    if (cell.OpenType === 'popview' && cell.config) {
                      traversal(cell.config.components)
                    } else if (cell.OpenType === 'pop') {
                      if (cell.modal && cell.modal.fields.length) {
                        cell.modal.fields.forEach(n => {
                          filterForm(n)
                        })
                      }
                    }
                  } else {
                    filterElement(cell)
                  }
                })
              }
            })
          }
          loopCol(item.cols)
        } else if (item.type === 'form') {
          item.subcards.forEach(cell => {
            filterBtn(cell.subButton)
            cell.fields.forEach(n => {
              filterForm(n)
            })
          })
        }
      }
    })
  }
  if (config.interfaces) {
    config.interfaces.forEach(item => {
      if (item.setting.interType === 'system') {
        item.setting.dataresource = filterSql(item.setting.dataresource)
        item.scripts && item.scripts.forEach(script => {
          script.sql = filterSql(script.sql)
        })
      }
    })
  }
  traversal(config.components)
}
src/utils/utils-datamanage.js
@@ -151,6 +151,7 @@
      { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      { reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      { reg: /@typename@/ig, value: `'admin'`},
    )
@@ -322,6 +323,10 @@
      param.s_version_up = 'true'
    }
    if (setting.database === 'sso' && window.GLOB.mainSystemApi) {
      param.rduri = window.GLOB.mainSystemApi
    }
    return param
  }
@@ -379,6 +384,7 @@
      { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      { reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      { reg: /@typename@/ig, value: `'admin'`},
    )
@@ -578,6 +584,7 @@
    { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
    { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
    { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
    { reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
    { reg: /@typename@/ig, value: `'admin'`},
  ]
src/utils/utils.js
@@ -916,6 +916,7 @@
    sql = sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
    sql = sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
    sql = sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
    sql = sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
    return {
      sql: sql,
@@ -1094,6 +1095,7 @@
      {reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      {reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      {reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      {reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      {reg: /@typename@/ig, value: `'admin'`},
      {reg: /\$@/ig, value: isDM ? '/*' : ''},
      {reg: /@\$/ig, value: isDM ? '*/' : ''},
@@ -1425,6 +1427,7 @@
      {reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      {reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      {reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      {reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      {reg: /@typename@/ig, value: `'admin'`},
      {reg: /\$@/ig, value: isDM ? '/*' : ''},
      {reg: /@\$/ig, value: isDM ? '*/' : ''},
@@ -2563,15 +2566,29 @@
      begin
          select @retmsg='X' from s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and userid=@userid@
          if @retmsg !=''
          if @retmsg !=''
          begin
              select @ErrorCode='E', @retmsg='当前单据已审核,请刷新后重试'
            goto aaa
            goto aaa
          end
          if @dataM@ !=''
          begin
            set @retmsg =''
            select @retmsg='X' from s_my_works_flow_role where works_flow_id=@ID@ and works_flow_code=@works_flow_code@ and deleted=0
            if @retmsg != ''
            begin
                goto goto_mk
            end
          end
          select @retmsg='页面数据已更新,或没有当前单据的审批权限'
            goto aaa 
      end
      end
      goto_mk:
      set @retmsg=''
      update s_my_works_flow set status=@status@,statusname=@statusname@,works_flow_param=@works_flow_param@,works_flow_detail_id=@works_flow_detail_id@,modifydate=getdate(),upid=@time_id@,modifyuserid=@userid@,modifyuser=@username,modifystaff=@fullname${verify.flowRemark ? ',remark=@' + verify.flowRemark : ''}
@@ -2670,6 +2687,7 @@
  _sql = _sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
  _sql = _sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
  _sql = _sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
  _sql = _sql.replace(/@lang@/ig, `'${sessionStorage.getItem('lang')}'`)
  _sql = _sql.replace(/@typename@/ig, `'admin'`)
  if (window.GLOB.externalDatabase !== null) {
src/views/appcheck/index.jsx
@@ -1,16 +1,14 @@
import React, {Component} from 'react'
import { Spin, notification, Table, ConfigProvider, Typography, Row, Col, Tooltip } from 'antd'
import { Spin, notification, Table, Typography, Row, Col, Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import Api from '@/api'
import { langs } from '@/store/options.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { Paragraph } = Typography
const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const Header = asyncComponent(() => import('./header'))
const skinStyle = {
@@ -139,116 +137,114 @@
    return (
      <div className="mk-app-check">
        <ConfigProvider locale={_locale}>
          <Header view="manage" />
          {loading ?
            <div className="loading-mask">
              <Spin size="large" />
            </div> : null
          }
          <div className="view-wrap">
            <div className="left-view">
              <div className="app-table">
                <Table
                  rowKey="ID"
                  columns={columns}
                  dataSource={applist}
                  pagination={false}
                  rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
                  onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
                />
              </div>
            </div>
            <div className="right-view">
              {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
              {selectApp && selectApp.sublist.map((item, index) => {
                let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
                let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
                let binding = ''
                if (item.user_binding) {
                  if (item.user_binding.indexOf('uname_pwd') > -1) {
                    binding = '用户名'
                  }
                  if (item.user_binding.indexOf('sms_vcode') > -1) {
                    binding = binding ? binding + ',手机号' : '手机号'
                  }
                }
                return (
                  <div className="sub-app" key={index} style={{borderColor: color}}>
                    <Row>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">应用类型:</div>
                          <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">语言:</div>
                          <div className="content" style={{textDecoration: 'underline'}}>{item.lang === 'en-US' ? '英文' : '中文'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">权限管理:</div>
                          <div className="content">{item.role_type === 'false' ? '不启用' : '启用'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">皮肤:</div>
                          <div className="content" style={{color: color}}>{css}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          {binding ? <div className="label">
                            <Tooltip placement="topLeft" title="微信公众号登录时,系统用户与微信用户的绑定方式。">
                              <QuestionCircleOutlined className="mk-form-tip" />
                              用户绑定:
                            </Tooltip>
                          </div> : null}
                          <div className="content">{binding}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">标题:</div>
                          <div className="content">{item.title || '无'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">网站头像:</div>
                          <div className="content">{item.favicon ? <img style={{width: '18px', height: '18px'}} src={item.favicon} alt="" /> : '无'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">版权:</div>
                          <div className="content">{item.copyright || '无'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">LOGO:</div>
                          <div className="content">{item.logo ? <img style={{height: '18px'}} src={item.logo} alt="" /> : '无'}</div>
                        </div>
                      </Col>
                    </Row>
                    <div className="action">
                      <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${window.GLOB.baseurl}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
                    </div>
                  </div>
                )
              })}
        <Header view="manage" />
        {loading ?
          <div className="loading-mask">
            <Spin size="large" />
          </div> : null
        }
        <div className="view-wrap">
          <div className="left-view">
            <div className="app-table">
              <Table
                rowKey="ID"
                columns={columns}
                dataSource={applist}
                pagination={false}
                rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
                onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
              />
            </div>
          </div>
        </ConfigProvider>
          <div className="right-view">
            {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
            {selectApp && selectApp.sublist.map((item, index) => {
              let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
              let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
              let binding = ''
              if (item.user_binding) {
                if (item.user_binding.indexOf('uname_pwd') > -1) {
                  binding = '用户名'
                }
                if (item.user_binding.indexOf('sms_vcode') > -1) {
                  binding = binding ? binding + ',手机号' : '手机号'
                }
              }
              return (
                <div className="sub-app" key={index} style={{borderColor: color}}>
                  <Row>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">应用类型:</div>
                        <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">语言:</div>
                        <div className="content" style={{textDecoration: 'underline'}}>{langs[item.lang]}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">权限管理:</div>
                        <div className="content">{item.role_type === 'false' ? '不启用' : '启用'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">皮肤:</div>
                        <div className="content" style={{color: color}}>{css}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        {binding ? <div className="label">
                          <Tooltip placement="topLeft" title="微信公众号登录时,系统用户与微信用户的绑定方式。">
                            <QuestionCircleOutlined className="mk-form-tip" />
                            用户绑定:
                          </Tooltip>
                        </div> : null}
                        <div className="content">{binding}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">标题:</div>
                        <div className="content">{item.title || '无'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">网站头像:</div>
                        <div className="content">{item.favicon ? <img style={{width: '18px', height: '18px'}} src={item.favicon} alt="" /> : '无'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">版权:</div>
                        <div className="content">{item.copyright || '无'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">LOGO:</div>
                        <div className="content">{item.logo ? <img style={{height: '18px'}} src={item.logo} alt="" /> : '无'}</div>
                      </div>
                    </Col>
                  </Row>
                  <div className="action">
                    <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${window.GLOB.baseurl}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
                  </div>
                </div>
              )
            })}
          </div>
        </div>
      </div>
    )
  }
src/views/appmanage/index.jsx
@@ -1,14 +1,13 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
import { Spin, notification, Input, Button, Table, Modal, ConfigProvider, Typography, Row, Col, Tooltip } from 'antd'
import { Spin, notification, Input, Button, Table, Modal, Typography, Row, Col, Tooltip } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import { langs } from '@/store/options.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
@@ -16,12 +15,12 @@
const { Paragraph } = Typography
const { Search } = Input
const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const Header = asyncComponent(() => import('./header'))
const MutilForm = asyncComponent(() => import('./mutilform'))
const TransForm = asyncComponent(() => import('./transform'))
const ScriptForm = asyncComponent(() => import('./scriptform'))
const SubMutilForm = asyncComponent(() => import('./submutilform'))
const TransMenu = asyncComponent(() => import('./transmenu'))
const skinStyle = {
  bg_black_style_blue: {name: '蓝色', color: '#1890ff'},
@@ -517,8 +516,7 @@
        })
        if (!selectApp && applist[0]) {
          let _href = window.location.href.split('#')[0] + 'app_record'
          let record = localStorage.getItem(_href)
          let record = localStorage.getItem(window.GLOB.sysSign + 'app_record')
          record = record ? JSON.parse(record) : null
          if (record && record.dates) {
@@ -537,7 +535,7 @@
            })
            if (reset) {
              localStorage.setItem(_href, JSON.stringify(record))
              localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify(record))
            }
          }
        }
@@ -715,17 +713,16 @@
  jumpApp = (item) => {
    const { selectApp } = this.state
    let _href = window.location.href.split('#')[0] + 'app_record'
    let record = localStorage.getItem(_href)
    let record = localStorage.getItem(window.GLOB.sysSign + 'app_record')
    record = record ? JSON.parse(record) : null
    if (!record || !record.dates) {
      localStorage.setItem(_href, JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {[selectApp.ID]: new Date().getTime()}}))
      localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {[selectApp.ID]: new Date().getTime()}}))
    } else {
      if (record.preId === selectApp.ID || record.activeId === selectApp.ID) {
        localStorage.setItem(_href, JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {...record.dates, [selectApp.ID]: new Date().getTime()}}))
        localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({preId: selectApp.ID, activeId: selectApp.ID, dates: {...record.dates, [selectApp.ID]: new Date().getTime()}}))
      } else {
        localStorage.setItem(_href, JSON.stringify({...record, preId: selectApp.ID}))
        localStorage.setItem(window.GLOB.sysSign + 'app_record', JSON.stringify({...record, preId: selectApp.ID}))
      }
    }
@@ -733,7 +730,23 @@
    if (item.typename === 'pc') {
      route = 'pcdesign'
    }
    let param = {...item, kei_no: selectApp.kei_no, remark: selectApp.remark, type: 'app'}
    let applangList = []
    if (item.lang === 'zh-CN') {
      selectApp.sublist.forEach(cell => {
        if (cell.typename === item.typename && cell.lang !== 'zh-CN') {
          applangList.push(cell.lang)
        }
      })
    }
    if (applangList.length) {
      applangList.unshift('zh-CN')
      applangList = JSON.stringify(applangList)
    } else {
      applangList = ''
    }
    let param = {...item, kei_no: selectApp.kei_no, remark: selectApp.remark, applangList, type: 'app'}
    window.open(window.location.href.replace(/#.+/ig, `#/${route}/${window.btoa(window.encodeURIComponent(JSON.stringify(param)))}`))
  }
@@ -741,7 +754,22 @@
  jumpMenu = (item) => {
    const { selectApp } = this.state
    window.open(window.location.href.replace(/#.+/ig, `#/role/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, type: 'app'})))}`))
    let applangList = []
    if (item.lang === 'zh-CN') {
      selectApp.sublist.forEach(cell => {
        if (cell.typename === item.typename && cell.lang !== 'zh-CN') {
          applangList.push(cell.lang)
        }
      })
    }
    if (applangList.length) {
      applangList.unshift('zh-CN')
      applangList = JSON.stringify(applangList)
    } else {
      applangList = ''
    }
    window.open(window.location.href.replace(/#.+/ig, `#/role/${window.btoa(window.encodeURIComponent(JSON.stringify({...item, kei_no: selectApp.kei_no, remark: selectApp.remark, applangList, type: 'app'})))}`))
  }
  onSelectChange = selectedRowKeys => {
@@ -876,10 +904,10 @@
        ID = selectApp.ID
      } else {
        let lowerKei = res.kei_no.toLowerCase()
        if (lowerKei === 'mob') {
        if (['mob', 'pad', 'pc', 'admin'].includes(lowerKei)) {
          notification.warning({
            top: 92,
            message: '应用编码不允许使用mob!',
            message: '应用编码不允许使用mob、pad、pc、admin!',
            duration: 3
          })
          return
@@ -1055,221 +1083,220 @@
    return (
      <div className="mk-app-manage">
        <ConfigProvider locale={_locale}>
          <Header view="manage" />
          {loading ?
            <div className="loading-mask">
              <Spin size="large" />
            </div> : null
          }
          <div className="view-wrap">
            <div className="left-view">
              <div className="app-table">
                <div className="app-action">
                  <Button className="mk-green" onClick={() => this.setState({ visible: 'plus' })}>添加应用</Button>
                </div>
                <Table
                  rowKey="ID"
                  columns={columns}
                  dataSource={applist}
                  pagination={false}
                  rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
                  onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
                />
        <Header view="manage" />
        {loading ?
          <div className="loading-mask">
            <Spin size="large" />
          </div> : null
        }
        <div className="view-wrap">
          <div className="left-view">
            <div className="app-table">
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ visible: 'plus' })}>添加应用</Button>
              </div>
              <div className={'trans-table' + (this.state.transTotal <= 10 ? ' no-footer' : '')}>
                <div className="app-action">
                  <Button className="mk-green" onClick={() => this.setState({ transVisible: 'plus' })}>添加传输号</Button>
                  <Search placeholder="综合搜索" onSearch={value => this.tranSearch(value)} enterButton />
                </div>
                <Table
                  rowKey="ID"
                  columns={transcolumns}
                  dataSource={translist}
                  pagination={{
                    current: this.state.transIndex,
                    pageSize: 10,
                    total: this.state.transTotal || 0,
                    showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                  }}
                  rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }}
                  onRow={(record) => ({ onClick: () => {
                    if (this.forbid) {
                      this.forbid = false
                      return
                    }
                    this.onTransSelect(record)
                  }})}
                  onChange={this.changeTable}
                />
              <Table
                rowKey="ID"
                columns={columns}
                dataSource={applist}
                pagination={false}
                rowSelection={{ type: 'radio', selectedRowKeys: selectApp ? [selectApp.ID] : [], onChange: this.onSelectChange }}
                onRow={(record) => ({ onClick: () => this.setState({ selectApp: record })})}
              />
            </div>
            <div className={'trans-table' + (this.state.transTotal <= 10 ? ' no-footer' : '')}>
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ transVisible: 'plus' })}>添加传输号</Button>
                <Search placeholder="综合搜索" onSearch={value => this.tranSearch(value)} enterButton />
              </div>
              {selectTran ? <div className="script-table">
                <div className="app-action">
                  <Button className="mk-green" onClick={() => this.setState({ scriptVisible: true })}>添加脚本</Button>
                  <Button className="mk-danger" onClick={this.deleteScripts} style={{marginLeft: '15px'}}>删除</Button>
                  <Search placeholder="综合搜索" defaultValue={this.state.scriptSearchKey} onSearch={value => this.scriptSearch(value)} enterButton />
                </div>
                <Table
                  rowKey="ID"
                  columns={scriptcolumns}
                  dataSource={scriptlist}
                  pagination={{
                    current: this.state.scriptIndex,
                    pageSize: 10,
                    total: this.state.scriptTotal || 0,
                    showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                  }}
                  rowSelection={{ type: 'checkbox', selectedRowKeys: selectScriptKeys, onChange: this.onScriptChange }}
                  onRow={(record) => ({ onClick: () => this.onScriptSelect(record)})}
                  onChange={this.changeScriptTable}
                />
              </div> : null}
              <Table
                rowKey="ID"
                columns={transcolumns}
                dataSource={translist}
                pagination={{
                  current: this.state.transIndex,
                  pageSize: 10,
                  total: this.state.transTotal || 0,
                  showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                }}
                rowSelection={{ type: 'radio', selectedRowKeys: selectTran ? [selectTran.ID] : [], onChange: this.onTransChange }}
                onRow={(record) => ({ onClick: () => {
                  if (this.forbid) {
                    this.forbid = false
                    return
                  }
                  this.onTransSelect(record)
                }})}
                onChange={this.changeTable}
              />
            </div>
            <div className="right-view">
              {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
              {selectApp && selectApp.sublist.map((item, index) => {
                let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
                let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
                let binding = ''
                if (item.user_binding === 'true') {
                  binding = '用户绑定'
                }
                if (item.share === 'true') {
                  binding = binding ? binding + '、分享' : '分享'
                }
                return (
                  <div className="sub-app" key={index} style={{borderColor: color}}>
                    <Row>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">应用类型:</div>
                          <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">语言:</div>
                          <div className="content" style={{textDecoration: 'underline'}}>{item.lang === 'en-US' ? '英文' : '中文'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">权限管理:</div>
                          <div className="content">{item.role_type === 'false' ? '不启用' : '启用'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          {/* <div className="label">皮肤:</div>
                          <div className="content" style={{color: color}}>{css}</div> */}
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">皮肤:</div>
                          <div className="content" style={{color: color}}>{css}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          {/* {binding ? <div className="label">
                            <Tooltip placement="topLeft" title="微信公众号登录时,系统用户与微信用户的绑定方式。">
                              <QuestionCircleOutlined className="mk-form-tip" />
                              用户绑定:
                            </Tooltip>
                          </div> : null} */}
                          {binding ? <div className="label">
                            <Tooltip placement="topLeft" title="微信公众号或小程序中,绑定系统用户、自定义分享等功能。">
                              <QuestionCircleOutlined className="mk-form-tip" />
                              扩展功能:
                            </Tooltip>
                          </div> : null}
                          <div className="content">{binding}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">标题:</div>
                          <div className="content">{item.title || '无'}</div>
                        </div>
                      </Col>
                      <Col span={12}>
                        <div className="app-item">
                          <div className="label">网站头像:</div>
                          <div className="content">{item.favicon ? <img style={{width: '18px', height: '18px', borderRadius: '4px'}} src={item.favicon} alt="" /> : '无'}</div>
                        </div>
                      </Col>
                    </Row>
                    <div className="action">
                      <Button type="link" onClick={() => this.jumpMenu(item)} style={{color: 'rgba(30, 228, 224, 1)'}}>菜单&权限</Button>
                      <Button type="link" onClick={() => this.setState({ selectSubApp: item, subVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button>
                      <Button type="link" onClick={() => this.deleteSubApp(item)} style={{color: '#ff4d4f'}}>删除</Button>
                      <Button type="link" onClick={() => this.jumpApp(item)}>编辑应用</Button>
                      <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${window.GLOB.baseurl}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
                    </div>
                  </div>
                )
              })}
            </div>
            {selectTran ? <div className="script-table">
              <div className="app-action">
                <Button className="mk-green" onClick={() => this.setState({ scriptVisible: true })}>添加脚本</Button>
                <Button className="mk-danger" onClick={this.deleteScripts} style={{marginLeft: '15px'}}>删除</Button>
                <Search placeholder="综合搜索" defaultValue={this.state.scriptSearchKey} onSearch={value => this.scriptSearch(value)} enterButton />
              </div>
              <Table
                rowKey="ID"
                columns={scriptcolumns}
                dataSource={scriptlist}
                pagination={{
                  current: this.state.scriptIndex,
                  pageSize: 10,
                  total: this.state.scriptTotal || 0,
                  showTotal: (total, range) => `${range[0]}-${range[1]} 共 ${total} 条`
                }}
                rowSelection={{ type: 'checkbox', selectedRowKeys: selectScriptKeys, onChange: this.onScriptChange }}
                onRow={(record) => ({ onClick: () => this.onScriptSelect(record)})}
                onChange={this.changeScriptTable}
              />
            </div> : null}
          </div>
          <Modal
            title={'编辑应用'}
            width={'600px'}
            maskClosable={false}
            visible={visible !== false}
            onCancel={() => this.setState({visible: false, confirmloading: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitCard}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <MutilForm type={visible} card={visible === 'edit' ? selectApp : ''} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
          </Modal>
          <Modal
            title={transVisible === 'plus' ? '添加传输号' : '编辑传输号'}
            width={'600px'}
            maskClosable={false}
            visible={transVisible !== false}
            onCancel={() => this.setState({transVisible: false, confirmloading: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitTrans}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <TransForm type={transVisible} card={transVisible === 'edit' ? this.state.editTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} />
          </Modal>
          <Modal
            title={'添加脚本'}
            width={900}
            maskClosable={false}
            visible={scriptVisible}
            onCancel={() => this.setState({scriptVisible: false, confirmloading: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitScript}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <ScriptForm applist={applist} wrappedComponentRef={(inst) => this.scriptRef = inst} inputSubmit={this.submitScript} />
          </Modal>
          <Modal
            title={subVisible === 'plus' ? '添加子应用' : '编辑子应用'}
            width={'850px'}
            maskClosable={false}
            visible={subVisible !== false}
            onCancel={() => this.setState({subVisible: false, confirmloading: false})}
            confirmLoading={this.state.confirmloading}
            onOk={this.submitSubCard}
            cancelText="取消"
            okText="确定"
            destroyOnClose
          >
            <SubMutilForm type={subVisible} card={subVisible === 'edit' ? selectSubApp : ''} wrappedComponentRef={(inst) => this.submobcardRef = inst} inputSubmit={this.submitSubCard} />
          </Modal>
        </ConfigProvider>
          <div className="right-view">
            {selectApp ? <div className="app-title">{selectApp.remark}</div> : null}
            {selectApp && selectApp.sublist.map((item, index) => {
              let css = skinStyle[item.css] ? skinStyle[item.css].name : ''
              let color = skinStyle[item.css] ? skinStyle[item.css].color : '#e8e8e8'
              let binding = ''
              if (item.user_binding === 'true') {
                binding = '用户绑定'
              }
              if (item.share === 'true') {
                binding = binding ? binding + '、分享' : '分享'
              }
              return (
                <div className="sub-app" key={index} style={{borderColor: color}}>
                  <Row>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">应用类型:</div>
                        <div className="content" style={{fontSize: '18px', fontWeight: 600}}>{item.typename}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">语言:</div>
                        <div className="content" style={{textDecoration: 'underline'}}>{langs[item.lang]}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">权限管理:</div>
                        <div className="content">{item.role_type === 'false' ? '不启用' : '启用'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        {/* <div className="label">皮肤:</div>
                        <div className="content" style={{color: color}}>{css}</div> */}
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">皮肤:</div>
                        <div className="content" style={{color: color}}>{css}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        {/* {binding ? <div className="label">
                          <Tooltip placement="topLeft" title="微信公众号登录时,系统用户与微信用户的绑定方式。">
                            <QuestionCircleOutlined className="mk-form-tip" />
                            用户绑定:
                          </Tooltip>
                        </div> : null} */}
                        {binding ? <div className="label">
                          <Tooltip placement="topLeft" title="微信公众号或小程序中,绑定系统用户、自定义分享等功能。">
                            <QuestionCircleOutlined className="mk-form-tip" />
                            扩展功能:
                          </Tooltip>
                        </div> : null}
                        <div className="content">{binding}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">标题:</div>
                        <div className="content">{item.title || '无'}</div>
                      </div>
                    </Col>
                    <Col span={12}>
                      <div className="app-item">
                        <div className="label">网站头像:</div>
                        <div className="content">{item.favicon ? <img style={{width: '18px', height: '18px', borderRadius: '4px'}} src={item.favicon} alt="" /> : '无'}</div>
                      </div>
                    </Col>
                  </Row>
                  <div className="action">
                    {item.lang !== 'zh-CN' ? <TransMenu app={item} supApp={selectApp} /> : null}
                    <Button type="link" onClick={() => this.jumpMenu(item)} style={{color: 'rgba(30, 228, 224, 1)'}}>菜单&权限</Button>
                    <Button type="link" onClick={() => this.setState({ selectSubApp: item, subVisible: 'edit' })} style={{color: '#8E44AD'}}>修改</Button>
                    <Button type="link" onClick={() => this.deleteSubApp(item)} style={{color: '#ff4d4f'}}>删除</Button>
                    <Button type="link" onClick={() => this.jumpApp(item)}>编辑应用</Button>
                    <Paragraph style={{display: 'inline-block', margin: 0}} copyable={{ text: `${window.GLOB.baseurl}${item.typename === 'pad' ? 'mob' : item.typename}/index.html#/index/${this.state.selectApp.kei_no}/${item.typename !== 'pc' ? item.typename + '/' : ''}${item.lang}` }}></Paragraph>
                  </div>
                </div>
              )
            })}
          </div>
        </div>
        <Modal
          title={'编辑应用'}
          width={'600px'}
          maskClosable={false}
          visible={visible !== false}
          onCancel={() => this.setState({visible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitCard}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <MutilForm type={visible} card={visible === 'edit' ? selectApp : ''} wrappedComponentRef={(inst) => this.mobcardRef = inst} inputSubmit={this.submitCard} />
        </Modal>
        <Modal
          title={transVisible === 'plus' ? '添加传输号' : '编辑传输号'}
          width={'600px'}
          maskClosable={false}
          visible={transVisible !== false}
          onCancel={() => this.setState({transVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitTrans}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <TransForm type={transVisible} card={transVisible === 'edit' ? this.state.editTran : ''} wrappedComponentRef={(inst) => this.transRef = inst} inputSubmit={this.submitTrans} />
        </Modal>
        <Modal
          title={'添加脚本'}
          width={900}
          maskClosable={false}
          visible={scriptVisible}
          onCancel={() => this.setState({scriptVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitScript}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <ScriptForm applist={applist} wrappedComponentRef={(inst) => this.scriptRef = inst} inputSubmit={this.submitScript} />
        </Modal>
        <Modal
          title={subVisible === 'plus' ? '添加子应用' : '编辑子应用'}
          width={'850px'}
          maskClosable={false}
          visible={subVisible !== false}
          onCancel={() => this.setState({subVisible: false, confirmloading: false})}
          confirmLoading={this.state.confirmloading}
          onOk={this.submitSubCard}
          cancelText="取消"
          okText="确定"
          destroyOnClose
        >
          <SubMutilForm type={subVisible} card={subVisible === 'edit' ? selectSubApp : ''} wrappedComponentRef={(inst) => this.submobcardRef = inst} inputSubmit={this.submitSubCard} />
        </Modal>
      </div>
    )
  }
src/views/appmanage/index.scss
@@ -101,6 +101,14 @@
          .ant-typography-copy {
            color: #26C281;
          }
          .ant-btn {
            padding: 0 5px;
            margin: 0 10px;
          }
          .anticon-swap {
            color: #1890ff;
            padding: 5px 10px;
          }
        }
      }
    }
src/views/appmanage/submutilform/index.jsx
@@ -3,6 +3,7 @@
import { Form, Row, Col, Select, Radio, Input, Tooltip, InputNumber, Checkbox } from 'antd'
import { QuestionCircleOutlined } from '@ant-design/icons'
import { langs } from '@/store/options.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
@@ -16,13 +17,21 @@
    inputSubmit: PropTypes.func  // input回车提交
  }
  state = {typename: 'mob', adapters: [], exts: []}
  state = {
    typename: 'mob',
    adapters: [],
    exts: []
  }
  UNSAFE_componentWillMount() {
    const { card } = this.props
    let adapters = []
    let exts = []
    let typename = 'mob'
    let _langs = []
    Object.keys(langs).forEach(key => {
      _langs.push({value: key, label: langs[key]})
    })
    if (card) {
      typename = card.typename || 'mob'
@@ -38,7 +47,7 @@
      }
    }
    this.setState({typename, adapters, exts})
    this.setState({typename, adapters, exts, langs: _langs})
  }
  /**
@@ -80,7 +89,7 @@
  render() {
    const { card, type } = this.props
    const { getFieldDecorator } = this.props.form
    const { typename, adapters, exts } = this.state
    const { typename, adapters, exts, langs } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
@@ -113,10 +122,9 @@
              {getFieldDecorator('lang', {
                initialValue: card ? card.lang || 'zh-CN' : 'zh-CN'
              })(
                <Radio.Group disabled={type === 'edit'}>
                  <Radio value="zh-CN">中文</Radio>
                  <Radio value="en-US">英文</Radio>
                </Radio.Group>
                <Select disabled={type === 'edit'}>
                  {langs.map(item => <Select.Option key={item.value} value={item.value}>{item.label}</Select.Option>)}
                </Select>
              )}
            </Form.Item>
          </Col>
src/views/appmanage/transmenu/index.jsx
New file
@@ -0,0 +1,519 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { Modal, notification, Spin, Select } from 'antd'
import { SwapOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import MenuUtils, { setLangTrans } from '@/utils/utils-custom.js'
import './index.scss'
const { confirm } = Modal
class TransMenu extends Component {
  state = {
    visible: false,
    loading: false,
    saveing: false,
    dicts: [],
    menus: [],
    values: '',
    kei_no: '',
    zhApp: null
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  trigger = () => {
    const { supApp, app } = this.props
    let zhApp = supApp.sublist.filter(item => item.typename === app.typename && item.lang === 'zh-CN')[0]
    this.setState({
      loading: true,
      visible: true,
      saveing: false,
      values: '',
      kei_no: supApp.kei_no,
      zhApp
    })
    this.getDicts()
    this.getMenus(zhApp, supApp.kei_no)
  }
  getDicts = () => {
    // let sql = `select id,lang,lang_name,mother_tongue,translation,use_type,case when use_type='menu' then '菜单' when  use_type='button' then '按钮'  when  use_type='title' then '标题'   when  use_type='list' then '选项' else '文本' end as use_type_text from s_app_lang_translation where appkey=@appkey@ and deleted=0 and translation != ''`
    let sql = `select mother_tongue as reg,translation as value,use_type as type,case when use_type='menu' then '菜单' when  use_type='button' then '按钮'  when  use_type='title' then '标题'   when  use_type='list' then '选项' else '文本' end as use_type_text from s_app_lang_translation where appkey=@appkey@ and deleted=0 and translation != '' and lang='${sessionStorage.getItem('lang') || ''}'`
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: Utils.formatOptions(sql, 'x'),
      obj_name: 'data',
      arr_field: 'reg,value,type',
      exec_type: 'x'
    }
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp)
    Api.getCloudConfig(param).then(result => {
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        return
      }
      this.setState({dicts: result.data || []})
    })
  }
  getMenus = (zhApp, kei_no) => {
    if (this.state.menus.length > 0) {
      this.setState({loading: false})
      return
    }
    let param = {
      func: 's_get_app_menus',
      TypeCharOne: kei_no,
      typename: zhApp.typename,
      LText: `select '${window.GLOB.appkey}'`,
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
      lang: 'zh-CN'
    }
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.getCloudConfig(param).then(result => {
      if (result.status) {
        let menus = []
        result.menus.forEach(item => {
          if (zhApp.userbind === item.MenuID || zhApp.instantMessage === item.MenuID) return
          menus.push(item)
        })
        this.setState({menus: menus, loading: false})
      } else {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  submit = () => {
    const { values } = this.state
    if (!values) {
      notification.warning({
        top: 92,
        message: '请选择菜单!',
        duration: 5
      })
      return
    }
    this.setState({saveing: true})
    this.transThdMenu()
  }
  transThdMenu = () => {
    const { app } = this.props
    const { zhApp, dicts, values, kei_no } = this.state
    let _param = {
      func: 'sPC_Get_LongParam',
      TypeCharOne: kei_no,
      typename: zhApp.typename,
      MenuID: values,
      lang: 'zh-CN'
    }
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      let config = null
      if (res.LongParam) {
        try {
          config = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
        } catch (e) {
          console.warn('Parse Failure')
          config = ''
        }
      }
      if (!config) {
        notification.warning({
          top: 92,
          message: '未获取到菜单配置信息',
          duration: 5
        })
        this.setState({saveing: false})
      }
      let btnDict = {}
      let titDict = {}
      let lisDict = {}
      let menuDict = {}
      let regs = []
      dicts.forEach(item => {
        if (item.type === 'button') {
          btnDict[item.reg] = item.value
        } else if (item.type === 'title') {
          titDict[item.reg] = item.value
        } else if (item.type === 'list') {
          lisDict[item.reg] = item.value
        } else if (item.type === 'text') {
          regs.push({reg: new RegExp(item.reg, 'g'), value: item.value, sort: item.reg.length})
        } else if (item.type === 'menu') {
          menuDict[item.reg] = item.value
        }
      })
      regs.sort((a, b) => b.sort - a.sort)
      let tail = md5(window.GLOB.appkey + kei_no + zhApp.typename + app.lang).toLowerCase()
      tail = tail.slice(-8)
      let menus_rolelist = ''
      if (config.type === 'navbar') {
        config.menus.forEach(item => {
          if (item.linkMenuId) {
            item.linkMenuId = item.linkMenuId.slice(0, 24) + tail
          } else {
            item.MenuID = item.MenuID.slice(0, 24) + tail
          }
          if (item.name && menuDict[item.name]) {
            item.name = menuDict[item.name]
          }
          if (item.sublist) {
            item.sublist.forEach(sec => {
              if (sec.linkMenuId) {
                sec.linkMenuId = sec.linkMenuId.slice(0, 24) + tail
              } else {
                sec.MenuID = sec.MenuID.slice(0, 24) + tail
              }
              if (sec.name && menuDict[sec.name]) {
                sec.name = menuDict[sec.name]
              }
              if (sec.sublist) {
                sec.sublist.forEach(thd => {
                  if (thd.linkMenuId) {
                    thd.linkMenuId = thd.linkMenuId.slice(0, 24) + tail
                  } else {
                    thd.MenuID = thd.MenuID.slice(0, 24) + tail
                  }
                  if (thd.name && menuDict[thd.name]) {
                    thd.name = menuDict[thd.name]
                  }
                })
              }
            })
          }
        })
        if (config.columns) {
          config.columns.forEach(cell => {
            if (cell.label && titDict[cell.label]) {
              cell.label = titDict[cell.label]
            }
          })
        }
        config.MenuNo = 'navbar_' + app.lang
        if (config.name === menuDict[config.name]) {
          config.name = menuDict[config.name]
        } else {
          config.name = config.name + '_' + app.lang
        }
        menus_rolelist = {
          type: 'navbar',
          version: '1.0',
          key: config.uuid,
          title: config.name,
          children: []
        }
        if (config.wrap.permission === 'true') {
          menus_rolelist.children = config.menus.map(fst => {
            if (fst.property === 'classify' && fst.sublist.length > 0) {
              return {
                key: fst.MenuID,
                title: fst.name,
                children: fst.sublist.map(scd => {
                  if (scd.property === 'classify' && scd.sublist.length > 0) {
                    return {
                      key: scd.MenuID,
                      title: scd.name,
                      children: scd.sublist.map(thd => {
                        return { key: thd.MenuID, title: thd.name }
                      })
                    }
                  } else {
                    return { key: scd.MenuID, title: scd.name }
                  }
                })
              }
            } else {
              return { key: fst.MenuID, title: fst.name }
            }
          })
        } else {
          menus_rolelist.pass = true
        }
        menus_rolelist = window.btoa(window.encodeURIComponent(JSON.stringify(menus_rolelist)))
      } else {
        setLangTrans(config, btnDict, titDict, lisDict, menuDict, regs, tail)
        if (config.components) {
          let commonId = Utils.getuuid()
          if (config.interfaces && config.interfaces.length > 0) {
            config.interfaces = config.interfaces.map(inter => {
              inter.uuid = md5(commonId + inter.uuid)
              return inter
            })
          }
          config.components = MenuUtils.resetConfig(config.components, commonId, false)
          config.tables = config.tables || []
          config.style = config.style || {}
        }
        config.enabled = false
        config.Template = 'webPage'
        if (config.MenuNo) {
          config.MenuNo = config.MenuNo + '_' + app.lang
        }
        if (config.MenuName === menuDict[config.MenuName]) {
          config.MenuName = menuDict[config.MenuName]
        } else {
          config.MenuName = config.MenuName + '_' + app.lang
        }
      }
      config.uuid = values.slice(0, 24) + tail
      config.MenuID = config.uuid
      config.open_edition = ''
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: 'mk_app',
        SndID: 'mk_app',
        ParentID: 'mk_app',
        MenuID: config.uuid,
        MenuNo: config.MenuNo,
        EasyCode: '',
        TypeCharOne: kei_no,
        Typename: app.typename,
        Template: config.Template || config.type,
        MenuName: config.MenuName || config.name || '',
        PageParam: JSON.stringify({Template: config.Template || config.type}),
        lang: app.lang
      }
      if (menus_rolelist) {
        param.menus_rolelist = menus_rolelist
      }
      Api.getCloudConfig({
        func: 'sPC_Get_LongParam',
        TypeCharOne: kei_no,
        typename: app.typename,
        MenuID: config.MenuID,
        lang: app.lang
      }).then(res => {
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({saveing: false})
          return
        }
        config.open_edition = res.open_edition || ''
        param.open_edition = config.open_edition
        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
        if (res.LongParam) {
          const that = this
          confirm({
            title: '菜单已存在,确定重新生成吗?',
            content: '',
            onOk() {
              that.setMenu(param, config)
            },
            onCancel() {}
          })
        } else {
          this.setMenu(param, config)
        }
      })
    })
  }
  setMenu = (param, config) => {
    const { app } = this.props
    const { kei_no } = this.state
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    Api.getCloudConfig(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      if (config.type === 'navbar') {
        Api.getCloudConfig({
          func: 's_get_keyids',
          bid: app.ID
        }).then(res => {
          if (!res.status) {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
            this.setState({saveing: false})
            return
          }
          let appViewList = res.data || []
          appViewList = appViewList.filter(item => item.keys_id !== config.uuid)
          appViewList.unshift({
            appkey: window.GLOB.appkey || '',
            bid: app.ID,
            kei_no: kei_no || '',
            keys_id: config.uuid,
            keys_type: 'navbar',
            remark: config.name
          })
          let param = {
            func: 's_kei_link_keyids_addupt',
            BID: app.ID,
            exec_type: 'x',
            LText: ''
          }
          param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
          param.LText = param.LText.join(' union all ')
          param.LText = Utils.formatOptions(param.LText, 'x')
          param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
          param.secretkey = Utils.encrypt('', param.timestamp)
          Api.getCloudConfig(param).then(result => {
            if (!result.status) {
              notification.warning({
                top: 92,
                message: result.message,
                duration: 5
              })
              this.setState({saveing: false})
              return
            }
            notification.success({
              top: 92,
              message: '添加成功。',
              duration: 5
            })
            this.setState({
              loading: false,
              visible: false
            })
          })
        })
      } else {
        notification.success({
          top: 92,
          message: '添加成功。',
          duration: 5
        })
        this.setState({
          loading: false,
          visible: false
        })
      }
    })
  }
  cancel = () => {
    this.setState({
      loading: false,
      visible: false
    })
  }
  render () {
    const { supApp, app } = this.props
    const { visible, loading, saveing, menus } = this.state
    if (supApp.sublist.findIndex(item => item.typename === app.typename && item.lang === 'zh-CN') === -1) return null
    return (
      <>
        <SwapOutlined onClick={this.trigger}/>
        <Modal
          wrapClassName="sync-menu-modal"
          title="菜单转换"
          visible={visible}
          width={600}
          closable={false}
          maskClosable={false}
          onOk={this.submit}
          onCancel={this.cancel}
          confirmLoading={saveing}
          destroyOnClose
        >
          {loading ? <Spin /> : <div>
            <Select
              showSearch
              placeholder="请选择菜单"
              dropdownMatchSelectWidth={false}
              onChange={(val) => this.setState({values: val})}
              filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            >
              {menus.map((item, i) => (<Select.Option key={i} value={item.MenuID}>{`${item.MenuName}(${item.MenuNo})`}</Select.Option>))}
            </Select>
          </div>}
        </Modal>
      </>
    )
  }
}
export default TransMenu
src/views/appmanage/transmenu/index.scss
New file
@@ -0,0 +1,16 @@
.sync-menu-modal {
  .ant-modal-body {
    position: relative;
    padding: 24px 50px;
    min-height: 250px;
    max-height: calc(100vh - 210px);
    .ant-select {
      width: 300px;
    }
    .ant-spin {
      position: absolute;
      left: calc(50% - 10px);
      top: 75px;
    }
  }
}
src/views/basedesign/index.jsx
@@ -1,7 +1,5 @@
import React, {Component} from 'react'
import { notification, Spin, ConfigProvider } from 'antd'
import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import { notification, Spin } from 'antd'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
@@ -10,7 +8,6 @@
import '@/assets/css/design.scss'
import './index.scss'
const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const Header = asyncComponent(() => import('@/menu/header'))
const ComTableConfig = asyncLoadComponent(() => import('@/templates/comtableconfig'))
const TreePageConfig = asyncLoadComponent(() => import('@/templates/treepageconfig'))
@@ -189,58 +186,56 @@
    return (
      <div className="mk-base-design-wrap">
        <ConfigProvider locale={_locale}>
          <Header/>
          {this.state.tabview === 'CommonTable' ?
            <ComTableConfig
              menu={editMenu}
              reloadmenu={() => {localStorage.setItem('menuUpdate', new Date().getTime())}}
              handleView={this.handleView}
            /> : null
          }
          {this.state.tabview === 'SubTable' ?
            <SubTable
              menu={editMenu}
              editTab={this.state.editTab}
              editSubTab={this.state.editSubTab}
              tabConfig={this.state.tabConfig}
              btnTab={btnTab}
              btnTabConfig={this.state.btnTabConfig}
              config={subConfig}
              handleView={this.handleView}
            /> : null
          }
          {this.state.tabview === 'Modal' ?
            <ModalConfig
              menu={editMenu}
              editTab={this.state.editTab}
              tabConfig={this.state.tabConfig}
              editSubTab={this.state.editSubTab}
              subTabConfig={this.state.subTabConfig}
              btnTab={btnTab}
              btnTabConfig={this.state.btnTabConfig}
              editAction={this.state.editAction}
              subConfig={subConfig}
              handleView={this.handleView}
            /> : null
          }
          {this.state.tabview === 'TreePage' ?
            <TreePageConfig
              menu={editMenu}
              reloadmenu={() => {localStorage.setItem('menuUpdate', new Date().getTime())}}
              handleView={this.handleView}
            /> : null
          }
          {this.state.tabview === 'FormTab' ?
            <UpdateFormTab
              menu={editMenu}
              btnTab={btnTab}
              config={subConfig}
              handleView={this.handleView}
            /> : null
          }
          {loading ? <Spin className="loading-view" size="large"/> : null}
        </ConfigProvider>
        <Header/>
        {this.state.tabview === 'CommonTable' ?
          <ComTableConfig
            menu={editMenu}
            reloadmenu={() => {localStorage.setItem('menuUpdate', new Date().getTime())}}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'SubTable' ?
          <SubTable
            menu={editMenu}
            editTab={this.state.editTab}
            editSubTab={this.state.editSubTab}
            tabConfig={this.state.tabConfig}
            btnTab={btnTab}
            btnTabConfig={this.state.btnTabConfig}
            config={subConfig}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'Modal' ?
          <ModalConfig
            menu={editMenu}
            editTab={this.state.editTab}
            tabConfig={this.state.tabConfig}
            editSubTab={this.state.editSubTab}
            subTabConfig={this.state.subTabConfig}
            btnTab={btnTab}
            btnTabConfig={this.state.btnTabConfig}
            editAction={this.state.editAction}
            subConfig={subConfig}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'TreePage' ?
          <TreePageConfig
            menu={editMenu}
            reloadmenu={() => {localStorage.setItem('menuUpdate', new Date().getTime())}}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'FormTab' ?
          <UpdateFormTab
            menu={editMenu}
            btnTab={btnTab}
            config={subConfig}
            handleView={this.handleView}
          /> : null
        }
        {loading ? <Spin className="loading-view" size="large"/> : null}
      </div>
    )
  }
src/views/billprint/index.jsx
@@ -813,6 +813,7 @@
      { reg: /@SessionUid@/ig, value: `'${localStorage.getItem('SessionUid') || ''}'`},
      { reg: /@UserID@/ig, value: `'${sessionStorage.getItem('UserID') || ''}'`},
      { reg: /@Appkey@/ig, value: `'${window.GLOB.appkey || ''}'`},
      { reg: /@lang@/ig, value: `'${sessionStorage.getItem('lang')}'`},
      { reg: /@typename@/ig, value: `'admin'`},
    ]
src/views/design/header/index.jsx
@@ -16,6 +16,8 @@
const VersionsUp = asyncComponent(() => import('./versions'))
const ThawMenu = asyncComponent(() => import('@/components/thawmenu'))
const MenuForm = asyncComponent(() => import('./editfirstmenu/menuform'))
const TransMenu = asyncComponent(() => import('./transmenu'))
const { confirm } = Modal
class Header extends Component {
@@ -24,6 +26,7 @@
    userName: sessionStorage.getItem('CloudUserName'),
    avatar: Utils.getrealurl(sessionStorage.getItem('CloudAvatar')),
    logo: sessionStorage.getItem('CloudLogo') || MainLogo,
    subLang: sessionStorage.getItem('subLangList') !== null,
    visible: false,
    loading: false
  }
@@ -37,6 +40,7 @@
      onOk() {
        sessionStorage.clear()
        _this.props.history.replace('/login')
        window.location.reload()
      },
      onCancel() {}
    })
@@ -409,7 +413,7 @@
  render () {
    const { mainMenu, editLevel } = this.props
    const { menulist, visible, loading, logo } = this.state
    const { menulist, visible, loading, logo, subLang } = this.state
    return (
      <header className={'sys-header-container ant-menu-dark ' + (['level2', 'level3'].includes(editLevel) ? 'mask' : '')} id="main-header-container">
@@ -493,6 +497,12 @@
              编辑
            </Button>
          </div> : null}
          {window.GLOB.systemType !== 'production' && subLang ? <div className="entrance">
            <div className="icon"><PlusOutlined /></div>
            <div className="title">菜单转换</div>
            <div className="detail">可选择母语系统的菜单,快速转换到当前语言。打印模板请在HS下复制后,在此处选择指定模板进行语言转换。</div>
            <TransMenu reload={this.reload} menulist={menulist}/>
          </div> : null}
        </div>
        {/* 编辑菜单 */}
        {editLevel === 'level1' ? <EditMenu menulist={this.state.menulist} reload={this.reload} exitEdit={this.exitEdit}/> : null}
src/views/design/header/transmenu/index.jsx
New file
@@ -0,0 +1,885 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { Modal, Radio, notification, Button, Spin, Select, Cascader } from 'antd'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import MenuUtils, { setLangTrans } from '@/utils/utils-custom.js'
import './index.scss'
const { confirm } = Modal
class TransMenu extends Component {
  state = {
    visible: false,
    loading: false,
    saveing: false,
    lang: '',
    type: '',
    dicts: [],
    menus: [],
    billMenus: [],
    tabMenus: [],
    values: '',
    images: '',
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  trigger = () => {
    let langs = sessionStorage.getItem('subLangList')
    langs = JSON.parse(langs)
    this.setState({
      lang: langs[0],
      loading: true,
      visible: true,
      saveing: false,
      type: 'menu',
      images: '',
      values: ''
    })
    this.getDicts()
    this.getMenus(langs[0])
  }
  getDicts = () => {
    // let sql = `select id,lang,lang_name,mother_tongue,translation,use_type,case when use_type='menu' then '菜单' when  use_type='button' then '按钮'  when  use_type='title' then '标题'   when  use_type='list' then '选项' else '文本' end as use_type_text from s_app_lang_translation where appkey=@appkey@ and deleted=0 and translation != ''`
    let sql = `select mother_tongue as reg,translation as value,use_type as type,case when use_type='menu' then '菜单' when  use_type='button' then '按钮'  when  use_type='title' then '标题'   when  use_type='list' then '选项' else '文本' end as use_type_text from s_app_lang_translation where appkey=@appkey@ and deleted=0 and translation != '' and lang='${sessionStorage.getItem('lang') || ''}'`
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: Utils.formatOptions(sql, 'x'),
      obj_name: 'data',
      arr_field: 'reg,value,type',
      exec_type: 'x'
    }
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp)
    Api.getCloudConfig(param).then(result => {
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        return
      }
      this.setState({dicts: result.data || []})
    })
  }
  getMenus = (lang) => {
    if (this.state.menus.length > 0) {
      this.setState({loading: false})
      return
    }
    let _param = {
      func: 's_get_pc_menus',
      systemType: window.GLOB.sysType,
      pro_sys: '',
      lang: lang,
      debug: 'Y'
    }
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      let menus = []
      res.fst_menu && res.fst_menu.forEach(fst => {
        let fstItem = {
          value: fst.MenuID,
          label: fst.MenuName,
          children: []
        }
        fst.snd_menu && fst.snd_menu.forEach(snd => {
          let sndItem = {
            value: snd.MenuID,
            label: snd.MenuName,
            children: []
          }
          snd.trd_menu && snd.trd_menu.forEach(trd => {
            let trdItem = {
              value: trd.MenuID,
              label: trd.MenuName,
              MenuNo: trd.MenuNo,
            }
            if (!trd.PageParam) return
            let PageParam = null
            try {
              PageParam = JSON.parse(trd.PageParam)
            } catch (e) {
              PageParam = null
            }
            if (!PageParam || !['BaseTable', 'CustomPage'].includes(PageParam.Template)) return
            trdItem.PageParam = PageParam
            sndItem.children.push(trdItem)
          })
          if (sndItem.children.length === 0) return
          fstItem.children.push(sndItem)
        })
        if (fstItem.children.length === 0) return
        menus.push(fstItem)
      })
      menus.push({
        value: 'home_page_id',
        label: '首页',
      })
      this.setState({menus: menus, loading: false})
    })
  }
  submit = () => {
    const { values, type } = this.state
    if (!values) {
      notification.warning({
        top: 92,
        message: type === 'menu' ? '请选择菜单!' : '请选择模板!',
        duration: 5
      })
      return
    }
    if (type === 'bill') {
      this.billSubmit()
      return
    } else if (type === 'tab') {
      this.tabSubmit()
      return
    }
    if (values.length !== 3 && values[0] !== 'home_page_id') {
      notification.warning({
        top: 92,
        message: '请选择菜单!',
        duration: 5
      })
      return
    }
    this.setState({saveing: true})
    if (values[0] === 'home_page_id') {
      this.transThdMenu({
        value: 'home_page_id',
        MenuID: 'home_page_id',
        label: '首页'
      })
    } else {
      this.transFirstMenu(values[0], values[1], values[2])
    }
  }
  transFirstMenu = (firstId, secId, thdId) => {
    const { menulist } = this.props
    const { menus, dicts } = this.state
    let tail = md5(window.GLOB.appkey + sessionStorage.getItem('lang')).toLowerCase()
    tail = tail.slice(-8)
    let oriFirstMenu = menus.filter(item => item.value === firstId)[0]
    let oriSecMenu = oriFirstMenu.children.filter(item => item.value === secId)[0]
    let oriThdMenu = oriSecMenu.children.filter(item => item.value === thdId)[0]
    oriThdMenu = fromJS(oriThdMenu).toJS()
    let curFirstId = firstId
    if (curFirstId.length <= 24) {
      curFirstId = md5(window.GLOB.appkey + curFirstId + sessionStorage.getItem('lang')).toLowerCase()
    } else {
      curFirstId = curFirstId.slice(0, 24) + tail
    }
    let curSectId = secId
    if (curSectId.length <= 24) {
      curSectId = md5(window.GLOB.appkey + curSectId + sessionStorage.getItem('lang')).toLowerCase()
    } else {
      curSectId = curSectId.slice(0, 24) + tail
    }
    let curThdId = thdId
    if (curThdId.length <= 24) {
      curThdId = md5(window.GLOB.appkey + curThdId + sessionStorage.getItem('lang')).toLowerCase()
    } else {
      curThdId = curThdId.slice(0, 24) + tail
    }
    let firstName = oriFirstMenu.label
    let secName = oriSecMenu.label
    dicts.forEach(item => {
      if (item.type !== 'menu') return
      if (item.reg === firstName) {
        firstName = item.value
      }
      if (item.reg === secName) {
        secName = item.value
      }
      if (item.reg === oriThdMenu.label) {
        oriThdMenu.label = item.value
      }
    })
    let firstParam = {
      func: 'sPC_MainMenu_Add',
      MenuID: curFirstId,
      MenuName: firstName,
      PageParam: JSON.stringify({
        OpenType: 'menu',
        linkUrl: ''
      })
    }
    let secParam = {
      func: 'sPC_SndMenu_Add',
      ParentID: curFirstId,
      MenuID: curSectId,
      MenuName: secName,
      PageParam: JSON.stringify({
        Icon: ''
      })
    }
    oriThdMenu.fstMenuId = curFirstId
    oriThdMenu.parentId = curSectId
    oriThdMenu.MenuID = curThdId
    if (menulist.findIndex(item => item.MenuID === firstParam.MenuID) === -1) {
      Api.getCloudConfig(firstParam).then(res => {
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({saveing: false})
          return
        }
        this.transSecondMenu(secParam, oriThdMenu, true)
      })
    } else {
      this.transSecondMenu(secParam, oriThdMenu)
    }
  }
  transSecondMenu = (secParam, oriThdMenu, reload) => {
    const { menulist } = this.props
    let creat = true
    menulist.forEach(item => {
      if (item.children.findIndex(cell => cell.MenuID === secParam.MenuID) > -1) {
        creat = false
      }
    })
    if (creat) {
      Api.getCloudConfig(secParam).then(res => {
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({saveing: false})
          return
        }
        this.transThdMenu(oriThdMenu, true)
      })
    } else {
      this.transThdMenu(oriThdMenu, reload)
    }
  }
  transThdMenu = (menu, reload) => {
    const { menulist } = this.props
    const { lang, dicts } = this.state
    let _param = {
      func: 'sPC_Get_LongParam',
      MenuID: menu.value,
      lang: lang
    }
    let creat = true
    if (menu.MenuID === 'home_page_id') {
      creat = false
    } else {
      menulist.forEach(item => {
        item.children.forEach(cell => {
          if (cell.children.findIndex(n => n.MenuID === menu.MenuID) > -1) {
            creat = false
          }
        })
      })
    }
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      let config = null
      if (res.LongParam) {
        try {
          config = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
        } catch (e) {
          console.warn('Parse Failure')
          config = ''
        }
      }
      if (!config) {
        notification.warning({
          top: 92,
          message: '未获取到菜单配置信息',
          duration: 5
        })
        this.setState({saveing: false})
        if (reload) {
          this.props.reload()
        }
        return
      }
      let btnDict = {}
      let titDict = {}
      let lisDict = {}
      let regs = []
      dicts.forEach(item => {
        if (item.type === 'button') {
          btnDict[item.reg] = item.value
        } else if (item.type === 'title') {
          titDict[item.reg] = item.value
        } else if (item.type === 'list') {
          lisDict[item.reg] = item.value
        } else if (item.type === 'text') {
          regs.push({reg: new RegExp(item.reg, 'g'), value: item.value, sort: item.reg.length})
        }
      })
      regs.sort((a, b) => b.sort - a.sort)
      let tail = md5(window.GLOB.appkey + sessionStorage.getItem('lang')).toLowerCase()
      tail = tail.slice(-8)
      setLangTrans(config, btnDict, titDict, lisDict, {}, regs, tail)
      if (config.components) {
        let commonId = Utils.getuuid()
        if (config.interfaces && config.interfaces.length > 0) {
          config.interfaces = config.interfaces.map(inter => {
            inter.uuid = md5(commonId + inter.uuid)
            return inter
          })
        }
        config.components = MenuUtils.resetConfig(config.components, commonId, false)
        config.tables = config.tables || []
        config.style = config.style || {}
      }
      config.enabled = false
      config.MenuName = menu.label
      config.fstMenuId = menu.fstMenuId || ''
      config.parentId = menu.parentId || ''
      config.uuid = menu.MenuID || ''
      config.open_edition = ''
      if (config.MenuNo) {
        config.MenuNo = config.MenuNo + '_' + sessionStorage.getItem('lang')
      }
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: config.fstMenuId,
        SndID: config.parentId,
        ParentID: config.parentId,
        MenuID: config.uuid,
        MenuNo: config.MenuNo || '',
        EasyCode: config.easyCode || '',
        Template: config.Template,
        MenuName: config.MenuName || '',
        PageParam: JSON.stringify({Template: config.Template, OpenType: config.OpenType || 'newtab'})
      }
      if (creat) {
        param.open_edition = config.open_edition
        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
        this.setMenu(param, true)
      } else {
        Api.getCloudConfig({
          func: 'sPC_Get_LongParam',
          MenuID: menu.MenuID
        }).then(res => {
          if (!res.status) {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
            this.setState({saveing: false})
            return
          }
          config.open_edition = res.open_edition || ''
          param.open_edition = config.open_edition
          param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
          if (res.LongParam) {
            const that = this
            confirm({
              title: '菜单已存在,确定重新生成吗?',
              content: '',
              onOk() {
                that.setMenu(param, true)
              },
              onCancel() {}
            })
          } else {
            this.setMenu(param, true)
          }
        })
      }
    })
  }
  setMenu = (param, reload) => {
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt('', param.timestamp)
    Api.getCloudConfig(param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      notification.success({
        top: 92,
        message: '添加成功。',
        duration: 5
      })
      this.setState({
        loading: false,
        visible: false
      })
      if (reload) {
        this.props.reload()
      }
    })
  }
  cancel = () => {
    this.setState({
      loading: false,
      visible: false
    })
  }
  onChange = (e) => {
    this.setState({
      type: e.target.value,
      images: '',
      values: ''
    })
    if (e.target.value === 'bill') {
      this.getBillMenus()
    } else if (e.target.value === 'tab') {
      this.getTabMenus()
    }
  }
  getBillMenus = () => {
    const { billMenus } = this.state
    if (billMenus.length) return
    let _param = {
      func: 's_get_sPrintTemplate_web',
      OrderCol: 'ID desc',
      lang_s: sessionStorage.getItem('lang'),
      dataM: 'Y',
      PageIndex: 1,
      PageSize: 1000
    }
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      this.setState({billMenus: res.data || []})
    })
  }
  getTabMenus = () => {
    const { tabMenus } = this.state
    if (tabMenus.length) return
    let _param = {
      func: 's_get_sPrintTemplate',
      OrderCol: 'ID desc',
      lang_s: sessionStorage.getItem('lang'),
      dataM: 'Y',
      PageIndex: 1,
      PageSize: 1000
    }
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        return
      }
      this.setState({tabMenus: res.data || []})
    })
  }
  billSubmit = () => {
    const { dicts, values, billMenus } = this.state
    let _param = {
      func: 'sPC_Get_LongParam',
      MenuID: values
    }
    this.setState({saveing: true})
    let temp = billMenus.filter(item => item.ID === values)[0]
    Api.getCloudConfig(_param).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      let config = null
      if (res.LongParam) {
        try {
          config = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
        } catch (e) {
          console.warn('Parse Failure')
          config = ''
        }
      }
      if (!config) {
        notification.warning({
          top: 92,
          message: '未获取到模板配置信息',
          duration: 5
        })
        this.setState({saveing: false})
        return
      }
      let btnDict = {}
      let titDict = {}
      let lisDict = {}
      let regs = []
      dicts.forEach(item => {
        if (item.type === 'button') {
          btnDict[item.reg] = item.value
        } else if (item.type === 'title') {
          titDict[item.reg] = item.value
        } else if (item.type === 'list') {
          lisDict[item.reg] = item.value
        } else if (item.type === 'text') {
          regs.push({reg: new RegExp(item.reg, 'g'), value: item.value, sort: item.reg.length})
        }
      })
      regs.sort((a, b) => b.sort - a.sort)
      let tail = md5(window.GLOB.appkey + sessionStorage.getItem('lang')).toLowerCase()
      tail = tail.slice(-8)
      setLangTrans(config, btnDict, titDict, lisDict, {}, regs, tail)
      if (config.components) {
        let commonId = Utils.getuuid()
        if (config.interfaces && config.interfaces.length > 0) {
          config.interfaces = config.interfaces.map(inter => {
            inter.uuid = md5(commonId + inter.uuid)
            return inter
          })
        }
        config.components = MenuUtils.resetConfig(config.components, commonId, false)
        config.tables = config.tables || []
        config.style = config.style || {}
      }
      config.enabled = false
      config.MenuNo = temp.PrintTempNO || ''
      config.MenuName = temp.PrintTempName || ''
      config.fstMenuId = 'BillPrintTemp'
      config.parentId = 'BillPrintTemp'
      config.uuid = values
      config.MenuID = config.uuid
      config.open_edition = res.open_edition || ''
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: config.fstMenuId,
        SndID: config.parentId,
        ParentID: config.parentId,
        MenuID: config.uuid,
        MenuNo: config.MenuNo || '',
        EasyCode: config.easyCode || '',
        Template: config.Template,
        MenuName: config.MenuName || '',
        open_edition: config.open_edition,
        PageParam: JSON.stringify({Template: config.Template, OpenType: config.OpenType || 'newtab'})
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt('', param.timestamp)
      Api.getCloudConfig(param).then(res => {
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({saveing: false})
          return
        }
        notification.success({
          top: 92,
          message: '转换成功。',
          duration: 5
        })
        this.setState({
          saveing: false,
          visible: false
        })
      })
    })
  }
  tabSubmit = () => {
    const { values, dicts, tabMenus } = this.state
    let param = {
      func: 's_PrintTemplateMGetData',
      Type: 'Y',
      ID: values
    }
    this.setState({saveing: true})
    let temp = tabMenus.filter(item => item.ID === values)[0]
    Api.getCloudConfig(param).then(result => {
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        this.setState({saveing: false})
      } else if (!result.ConfigParam) {
        notification.warning({
          top: 92,
          message: '未获取到打印模板信息!',
          duration: 5
        })
        this.setState({saveing: false})
      } else {
        let config = ''
        try {
          config = JSON.parse(window.decodeURIComponent(window.atob(result.ConfigParam)))
        } catch (e) {
          config = ''
        }
        if (!config) {
          notification.warning({
            top: 92,
            message: '未获取到打印模板信息!',
            duration: 5
          })
          this.setState({saveing: false})
          return
        }
        let titDict = {}
        dicts.forEach(item => {
          if (item.type === 'title') {
            titDict[item.reg] = item.value
          }
        })
        config.elements.forEach(item => {
          if (item.type === 'text' && item.value && titDict[item.value]) {
            item.value = titDict[item.value]
          }
        })
        config.name = temp.PrintTempName || ''
        config.remark = temp.Remark || ''
        config.PrintTempNO = temp.PrintTempNO || ''
        let _param = {
          func: 's_PrintTemplateMSub',
          ID: values,
          ConfigParam: window.btoa(window.encodeURIComponent(JSON.stringify(config))),
          Images: temp.Images || '',
          PrintTempName: config.name,
          Remark: config.remark,
          PrintTempNO: config.PrintTempNO
        }
        Api.getCloudConfig(_param).then(result => {
          if (!result.status) {
            notification.warning({
              top: 92,
              message: result.message,
              duration: 5
            })
            this.setState({saveing: false})
            return
          }
          notification.success({
            top: 92,
            message: '转换成功。',
            duration: 5
          })
          this.setState({
            saveing: false,
            visible: false
          })
        })
      }
    })
  }
  render () {
    const { visible, loading, saveing, menus, type, billMenus, tabMenus, images } = this.state
    return (
      <>
        <Button type="primary" onClick={this.trigger}>
          转换
        </Button>
        <Modal
          wrapClassName="sync-menu-modal"
          title="菜单转换"
          visible={visible}
          width={600}
          closable={false}
          maskClosable={false}
          onOk={this.submit}
          onCancel={this.cancel}
          confirmLoading={saveing}
          destroyOnClose
        >
          {loading ? <Spin /> : <div>
            <Radio.Group defaultValue="menu" onChange={this.onChange}>
              <Radio.Button value="menu">菜单</Radio.Button>
              <Radio.Button value="bill">单据打印模板</Radio.Button>
              <Radio.Button value="tab">标签打印模板</Radio.Button>
            </Radio.Group>
            {type === 'menu' ? <Cascader popupClassName="sync-cascader" onChange={(val) => this.setState({values: val})} options={menus} expandTrigger="hover" placeholder="请选择菜单"/> : null}
            {type === 'bill' ? <Select
              showSearch
              placeholder="请选择单据模板"
              dropdownMatchSelectWidth={false}
              onChange={(val, option) => this.setState({values: val, images: option.props.images || ''})}
              filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            >
              {billMenus.map((item, i) => (<Select.Option key={i} images={item.Images || ''} value={item.ID}>{`${item.PrintTempName}(${item.PrintTempNO})`}</Select.Option>))}
            </Select> : null}
            {type === 'tab' ? <Select
              showSearch
              placeholder="请选择标签模板"
              dropdownMatchSelectWidth={false}
              onChange={(val, option) => this.setState({values: val, images: option.props.images || ''})}
              filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
            >
              {tabMenus.map((item, i) => (<Select.Option key={i} images={item.Images || ''} value={item.ID}>{`${item.PrintTempName}(${item.PrintTempNO})`}</Select.Option>))}
            </Select> : null}
            {images ? <img src={images} alt=""/> : null}
          </div>}
        </Modal>
      </>
    )
  }
}
export default TransMenu
src/views/design/header/transmenu/index.scss
New file
@@ -0,0 +1,36 @@
.sync-menu-modal {
  .ant-modal-body {
    position: relative;
    padding: 24px 50px;
    min-height: 250px;
    max-height: calc(100vh - 210px);
    .ant-cascader-picker, .ant-select {
      width: 300px;
    }
    .ant-radio-group {
      display: block;
      margin-bottom: 20px;
      .ant-radio-button-wrapper {
        width: 150px;
        text-align: center;
      }
    }
    img {
      max-width: 300px;
      max-height: 150px;
      display: block;
      margin: 10px;
    }
    .ant-spin {
      position: absolute;
      left: calc(50% - 10px);
      top: 75px;
    }
  }
}
.sync-cascader {
  .ant-cascader-menu {
    height: 200px;
    min-width: 120px;
  }
}
src/views/design/sidemenu/editthdmenu/index.jsx
@@ -214,8 +214,8 @@
        MenuName: res.MenuName,
        PageParam: JSON.stringify(PageParam),
        LongParam: '',
        LText: '',
        LTexttb: ''
        // LText: '',
        // LTexttb: ''
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
src/views/design/sidemenu/index.jsx
@@ -249,8 +249,8 @@
        MenuName: res.MenuName,
        PageParam: JSON.stringify(PageParam),
        LongParam: '',
        LText: '',
        LTexttb: ''
        // LText: '',
        // LTexttb: ''
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
src/views/design/sidemenu/thdmenuplus/index.jsx
@@ -174,8 +174,8 @@
        MenuName: values.MenuName,
        PageParam: JSON.stringify(PageParam),
        LongParam: '',
        LText: '',
        LTexttb: '',
        // LText: '',
        // LTexttb: '',
        Sort: sysMenu.menuSort
      }
src/views/imdesign/index.jsx
@@ -2,13 +2,11 @@
import { withRouter } from 'react-router'
import { is, fromJS } from 'immutable'
import moment from 'moment'
import { ConfigProvider, notification, Modal, Collapse, Button, Spin } from 'antd'
import { notification, Modal, Collapse, Button, Spin } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined, LeftOutlined, UserOutlined, EllipsisOutlined } from '@ant-design/icons'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import antdEnUS from 'antd/es/locale/en_US'
import antdZhCN from 'antd/es/locale/zh_CN'
// import MKEmitter from '@/utils/events.js'
import asyncComponent from '@/utils/asyncComponent'
import getWrapForm from './options'
@@ -32,7 +30,6 @@
class ImDesign extends Component {
  state = {
    localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
    loading: true,
    MenuId: '',
    MenuName: '',
@@ -49,10 +46,12 @@
    try {
      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
      if (param.lang) {
        sessionStorage.setItem('lang', param.lang)
      }
      if (param.type === 'app') {
        sessionStorage.setItem('appId', param.ID || '')
        sessionStorage.setItem('appName', param.remark || '')
        sessionStorage.setItem('lang', param.lang || 'zh-CN')
        sessionStorage.setItem('kei_no', param.kei_no || '')
        sessionStorage.setItem('typename', param.typename || 'mob')
        sessionStorage.setItem('adapter', param.adapter || '')
@@ -60,9 +59,6 @@
        sessionStorage.setItem('userbind', param.userbind || '')
        sessionStorage.setItem('instantMessage', param.instantMessage || '')
        this.setState({
          localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS,
        })
        this.getAppMessage(param.MenuID)
      } else if (param.type === 'view') {
        window.GLOB.winWidth = 420
@@ -149,7 +145,8 @@
    let param = {
      MenuID: config.wrap.linkmenu,
      copyMenuId: '',
      type: 'view'
      type: 'view',
      lang: sessionStorage.getItem('lang')
    }
    param = window.btoa(window.encodeURIComponent(JSON.stringify(param)))
@@ -177,7 +174,7 @@
      }
      sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
      this.props.history.replace('/imdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID, type: 'view'}))))
      this.props.history.replace('/imdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID, type: 'view', lang: sessionStorage.getItem('lang')}))))
      window.location.reload()
    })
  }
@@ -361,8 +358,8 @@
        PageParam: JSON.stringify({Template: 'imPage'}),
        open_edition: config.open_edition,
        menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify({type: 'im', key: config.uuid, title: config.MenuName, children: []}))),
        LText: '',
        LTexttb: ''
        // LText: '',
        // LTexttb: ''
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -421,96 +418,94 @@
  }
  render () {
    const { localedict, loading, settingshow, controlshow, MenuId, config, menuloading } = this.state
    const { loading, settingshow, controlshow, MenuId, config, menuloading } = this.state
    return (
      <ConfigProvider locale={localedict}>
        <div className="mk-mob-view" id="mk-mob-design-view">
          <Header/>
          {loading ? <Spin className="view-spin" size="large" /> : null}
          <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="basedata" bordered={false}>
                {/* 基本信息 */}
                <Panel header="基本信息" forceRender key="basedata">
                  {/* 菜单信息 */}
                  {config ? <MenuForm
                    config={config}
                    MenuId={MenuId}
                    updateConfig={this.updateConfig}
                  /> : null}
                </Panel>
                <Panel header="页面样式" key="background">
                  {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                </Panel>
              </Collapse>
            </div>
      <div className="mk-mob-view" id="mk-mob-design-view">
        <Header/>
        {loading ? <Spin className="view-spin" size="large" /> : null}
        <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={'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>
              <NormalForm title="即时通信设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
                <Button type="default" style={{borderColor: 'rgb(64, 169, 255)', color: 'rgb(64, 169, 255)'}}>设置</Button>
              </NormalForm>
              <Button type="default" className="mk-border-purple" onClick={this.backView}>后退</Button>
              <CreateView resetmenu={this.getAppMenus} />
              <Transfer MenuID={MenuId} />
              <Button type="default" onClick={this.closeView}>关闭</Button>
            </div>
          <div className="pc-setting-tools">
            <Collapse accordion defaultActiveKey="basedata" bordered={false}>
              {/* 基本信息 */}
              <Panel header="基本信息" forceRender key="basedata">
                {/* 菜单信息 */}
                {config ? <MenuForm
                  config={config}
                  MenuId={MenuId}
                  updateConfig={this.updateConfig}
                /> : null}
              </Panel>
              <Panel header="页面样式" key="background">
                {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
              </Panel>
            </Collapse>
          </div>
          <div className={'menu-body menu-view'}>
            <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
              <div className="instant-message" style={config ? config.style : null}>
                <div className="header">
                  <LeftOutlined/>
                  <span className="title">朋友</span>
                  {config && config.wrap.linkmenu ? <EllipsisOutlined onDoubleClick={this.changeEditMenu}/> : null}
                </div>
                <div className="mk-content-wrap">
                  <div className="line-wrap">
                    <div className="time-line">12:34</div>
                    <div className="line-msg">
                      <div className="portrait">
                        <div className="img"><UserOutlined /></div>
                      </div>
                      <div className="msg">
                        <div className="title">朋友</div>
                        <div className="words">您好</div>
                      </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>
            <NormalForm title="即时通信设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
              <Button type="default" style={{borderColor: 'rgb(64, 169, 255)', color: 'rgb(64, 169, 255)'}}>设置</Button>
            </NormalForm>
            <Button type="default" className="mk-border-purple" onClick={this.backView}>后退</Button>
            <CreateView resetmenu={this.getAppMenus} />
            <Transfer MenuID={MenuId} />
            <Button type="default" onClick={this.closeView}>关闭</Button>
          </div>
        </div>
        <div className={'menu-body menu-view'}>
          <div className="mob-shell" style={{width: window.GLOB.shellWidth, height: window.GLOB.shellHeight}}>
            <div className="instant-message" style={config ? config.style : null}>
              <div className="header">
                <LeftOutlined/>
                <span className="title">朋友</span>
                {config && config.wrap.linkmenu ? <EllipsisOutlined onDoubleClick={this.changeEditMenu}/> : null}
              </div>
              <div className="mk-content-wrap">
                <div className="line-wrap">
                  <div className="time-line">12:34</div>
                  <div className="line-msg">
                    <div className="portrait">
                      <div className="img"><UserOutlined /></div>
                    </div>
                  </div>
                  <div className="line-wrap">
                    <div className="time-line">12:45</div>
                    <div className="line-msg right">
                      <div className="msg">
                        <div className="words">
                          您好
                        </div>
                      </div>
                      <div className="portrait">
                        <div className="img"><UserOutlined /></div>
                      </div>
                    <div className="msg">
                      <div className="title">朋友</div>
                      <div className="words">您好</div>
                    </div>
                  </div>
                </div>
                <div className="send-wrap">
                  <div className="adm-input"></div>
                  <div className="send"><Button>发送</Button></div>
                <div className="line-wrap">
                  <div className="time-line">12:45</div>
                  <div className="line-msg right">
                    <div className="msg">
                      <div className="words">
                        您好
                      </div>
                    </div>
                    <div className="portrait">
                      <div className="img"><UserOutlined /></div>
                    </div>
                  </div>
                </div>
              </div>
              <div className="send-wrap">
                <div className="adm-input"></div>
                <div className="send"><Button>发送</Button></div>
              </div>
            </div>
          </div>
          <StyleController />
        </div>
      </ConfigProvider>
        <StyleController />
      </div>
    )
  }
}
src/views/interface/index.jsx
@@ -1,7 +1,4 @@
import React, {Component} from 'react'
import { ConfigProvider } from 'antd'
import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import Header from './header'
import History from './history'
@@ -9,17 +6,13 @@
import './index.scss'
const _locale = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
class Interface extends Component {
  render () {
    return (
      <div className="interface-view">
        <ConfigProvider locale={_locale}>
          <Header key="header"/>
          <History key="history"/>
          <WorkSpace key="workspace"/>
        </ConfigProvider>
        <Header key="header"/>
        <History key="history"/>
        <WorkSpace key="workspace"/>
      </div>
    )
  }
src/views/login/index.jsx
@@ -7,8 +7,6 @@
import Utils from '@/utils/utils.js' 
import MKEmitter from '@/utils/events.js'
import { styles } from '@/store/options.js'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncLoadComponent from '@/utils/asyncLoadComponent'
import './index.scss'
@@ -16,14 +14,9 @@
const LoginForm = asyncLoadComponent(() => import('./loginform'))
const Resetpwd = asyncLoadComponent(() => import('@/components/resetPassword'))
const LoginCloudForm = asyncComponent(() => import('./logincloudform'))
const iszhCN = sessionStorage.getItem('lang') !== 'en-US'
const _href = window.location.href.split('#')[0]
class Login extends Component {
  state = {
    selectedlang: iszhCN ? 'zh-CN' : 'en-US',
    dict: iszhCN ? zhCN : enUS,
    isDisabled: false,
    auth: false,
    authError: '',
@@ -37,7 +30,6 @@
    langList: [],
    syncApp: false,
    loginWays: null,
    touristLogin: false,
    syncing: false,
  }
@@ -95,13 +87,10 @@
        window.GLOB.externalDatabase = `[${res.paas_externalDatabase}]..`
      }
      localStorage.setItem(_href + 'lang', param.lang || 'zh-CN')
      sessionStorage.setItem('lang', param.lang || 'zh-CN')
      sessionStorage.removeItem('visitorUserID')
      sessionStorage.removeItem('visitorLoginUID')
      
      let users = localStorage.getItem(_href + 'users')
      let users = localStorage.getItem(window.GLOB.sysSign + 'users')
      
      if (users) {
        try {
@@ -122,9 +111,9 @@
      users.unshift({username: param.username, password: param.remember ? param.password : ''})
      localStorage.setItem(_href + 'users', window.btoa(window.encodeURIComponent(JSON.stringify(users))))
      localStorage.setItem(window.GLOB.sysSign + 'users', window.btoa(window.encodeURIComponent(JSON.stringify(users))))
      let level = localStorage.getItem(_href + 'pwdlevel')
      let level = localStorage.getItem(window.GLOB.sysSign + 'pwdlevel')
      if (level && process.env.NODE_ENV === 'production') {
        let visible = false
@@ -213,9 +202,6 @@
        sessionStorage.setItem('externalDatabase', res.paas_externalDatabase)
        window.GLOB.externalDatabase = `[${res.paas_externalDatabase}]..`
      }
      localStorage.setItem(_href + 'lang', param.lang || 'zh-CN')
      sessionStorage.setItem('lang', param.lang || 'zh-CN')
      sessionStorage.removeItem('visitorUserID')
      sessionStorage.removeItem('visitorLoginUID')
@@ -310,6 +296,9 @@
    // md5("/ws/location/v1/ip?callback=callbackFunction&key=key&output=jsonp secret key")
    // md5("/ws/location/v1/ip?callback=callbackFunction&key=BA7BZ-4QB65-LFCIA-QPDA6-4G6O7-MJB4Q&output=jsonpuThL4ZM3XOj642ksEQh76tyHFjh4")
    sessionStorage.removeItem('subLangList')
    sessionStorage.removeItem('langList')
    setTimeout(() => {
      Api.delCacheConfig()
    }, 50)
@@ -322,14 +311,14 @@
      }
    }
    const _addressUrl = _href + 'queryAddress'
    const _addressUrl = window.location.href.split('#')[0] + 'queryAddress'
    if (localStorage.getItem(_addressUrl) === 'true') {
      this.queryAddress()
    }
    const timeStamp = new Date().getTime()
    const _authUrl = _href + 'AuthCode'
    const _authUrl = window.location.href.split('#')[0] + 'AuthCode'
    let authCode = localStorage.getItem(_authUrl)
    let _s = md5('mksoft' + moment().format('YYYYMMDD'))
@@ -376,7 +365,7 @@
          lictime = Math.floor(new Date(lictime).getTime() / 86400000)
          let curtime = Math.floor(new Date().getTime() / 86400000)
          let licday = lictime - curtime
          let _mindUrl = _href + 'notMind'
          let _mindUrl = window.location.href.split('#')[0] + 'notMind'
          if (licday < 0 || isNaN(licday)) {
            Modal.warning({
@@ -466,12 +455,12 @@
            localStorage.setItem(_authUrl, box)
            if (res.e_files === 'true') {
              localStorage.setItem(_href + 'files', md5(_href + 'files'))
              localStorage.setItem(_href + 'filesDate', res.e_files_end_date)
              localStorage.setItem(window.GLOB.sysSign + 'files', md5(window.GLOB.sysSign + 'files'))
              localStorage.setItem(window.GLOB.sysSign + 'filesDate', res.e_files_end_date)
              window.GLOB.storeFiles = true
              window.GLOB.storeDate = Math.ceil((new Date(res.e_files_end_date).getTime() - new Date().getTime()) / 86400000)
            } else {
              localStorage.removeItem(_href + 'files')
              localStorage.removeItem(window.GLOB.sysSign + 'files')
              window.GLOB.storeFiles = false
            }
    
@@ -487,7 +476,7 @@
            }
          } else {
            localStorage.removeItem(_authUrl)
            localStorage.removeItem(_href + 'files')
            localStorage.removeItem(window.GLOB.sysSign + 'files')
            window.GLOB.storeFiles = false
            this.setState({
@@ -561,10 +550,6 @@
        sessionStorage.setItem('visitorUserID', result.UserID || '')
        sessionStorage.setItem('visitorLoginUID', result.LoginUID || '')
        if (result.UserID && result.LoginUID) {
          this.setState({touristLogin: true})
        }
        // 获取系统信息
        let _param = {
          func: 's_Get_style',
@@ -582,7 +567,7 @@
          if (!res) return
          
          if (res.status) {
            if (window.GLOB.sysType === 'local' && window.GLOB.systemType !== 'production') {
            if (res.member_type && window.GLOB.sysType === 'local' && window.GLOB.systemType !== 'production') {
              if (md5(('mk' + appkey + res.sys_datetime + res.member_type + res.registry_date).toLowerCase()) !== res.secret_key) {
                Modal.warning({
                  title: '密钥错误,请联系管理员!',
@@ -606,14 +591,13 @@
              res.menu_type = 'shutter'
            }
            let _url = _href + 'system'
            let systemMsg = {
              favicon: res.titlelogo || '',
              platTitle: res.titleName || '',
              platName: res.SysName || '',
              bgImage: res.Banner || '',
              loginlogo: res.loginlogo || '',
              copyRight: res.CopyRightYear && res.CopyRightOrg ? `Copyright©${res.CopyRightYear}    所有相关版权归    ${res.CopyRightOrg}` : '',
              copyRight: res.CopyRightYear && res.CopyRightOrg ? `Copyright©${res.CopyRightYear}    ${window.GLOB.dict['copyrights_by'] || '所有相关版权归'}    ${res.CopyRightOrg}` : '',
              ICP: res.ICP || '',
              mainlogo: res.indexlogo || '',
              doclogo: res.doclogo || '',
@@ -642,12 +626,12 @@
              level = ''
            }
            localStorage.setItem(_href + 'pwdlevel', level)
            localStorage.setItem(window.GLOB.sysSign + 'pwdlevel', level)
            if (res.srcid) {
              localStorage.setItem(_href + 'srcId', res.srcid)
              localStorage.setItem(window.GLOB.sysSign + 'srcId', res.srcid)
            } else {
              localStorage.removeItem(_href + 'srcId')
              localStorage.removeItem(window.GLOB.sysSign + 'srcId')
            }
            sessionStorage.setItem('home_background', res.index_background_color || '')
@@ -662,21 +646,41 @@
            document.title = systemMsg.platTitle
            try {
              localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify(systemMsg))))
              localStorage.setItem(window.GLOB.sysSign + 'system', window.btoa(window.encodeURIComponent(JSON.stringify(systemMsg))))
            } catch (e) {
              localStorage.removeItem(_url)
              localStorage.removeItem(window.GLOB.sysSign + 'system')
            }
            let _loginurl = _href + 'loginways'
            if (res.lang_translation_js && res.lang_data && res.lang_data[0] && (res.lang_data.length > 1 || res.lang_data[0].Lang !== 'zh-CN')) {
              let lang = sessionStorage.getItem('lang')
              let js_trans = res.lang_translation_js.map(item => {
                if (['not_empty', 'not_zero', 'max_limit', 'less_limit'].includes(item.msn_code)) {
                  item.translation = ' ' + item.translation
                }
                if (['input_tip', 'select_tip', 'max_limit', 'less_limit'].includes(item.msn_code)) {
                  item.translation = item.translation + ' '
                }
                if (lang === item.lang) {
                  window.GLOB.dict[item.msn_code] = item.translation
                }
                return {
                  lang: item.lang,
                  key: item.msn_code,
                  val: item.translation
                }
              })
              localStorage.setItem(window.GLOB.sysSign + 'js_trans', JSON.stringify(js_trans))
            }
            let _loginurl = window.GLOB.sysSign + 'loginways'
            let login_ways = []
            let login_types = []
            if (res.login_ways && res.login_ways.length > 0) {
              res.login_ways.forEach(item => {
                // 短信验证码登录,必须设置短信Id
                if (item.way_no === 'sms_vcode' && !item.sms_id) return
                if (login_types.includes(item.way_no)) return
                login_types.push(item.way_no)
                if (!['sms_vcode', 'uname_pwd', 'app_scan', 'weixin_scan'].includes(item.way_no)) return
                login_ways.push({
                  type: item.way_no,
@@ -698,6 +702,30 @@
              localStorage.setItem(_loginurl, window.btoa(window.encodeURIComponent(JSON.stringify(login_ways))))
            } catch (e) {
              localStorage.removeItem(_loginurl)
            }
            if (res.lang_data && res.lang_data.length > 1 && window.GLOB.systemType !== 'production') {
              let list = res.lang_data.map(item => item.Lang)
              let lang = 'zh-CN'
              if (window.GLOB.defLang && list.includes(window.GLOB.defLang)) {
                lang = window.GLOB.defLang
              }
              if (list.includes(lang)) {
                list = [lang, ...list.filter(item => item !== lang)]
                if (lang === sessionStorage.getItem('lang')) {
                  sessionStorage.setItem('langList', JSON.stringify(list))
                } else {
                  sessionStorage.setItem('subLangList', JSON.stringify(list))
                }
              }
            }
            if (res.lang_data.length === 1 && res.lang_data[0].Lang !== sessionStorage.getItem('lang')) {
              localStorage.setItem(window.location.href.split('#')[0] + 'lang', res.lang_data[0].Lang)
              sessionStorage.setItem('lang', res.lang_data[0].Lang)
              window.location.reload()
              return
            }
            
            this.setState({
@@ -760,7 +788,7 @@
      }
    })
    
    let loginWays = localStorage.getItem(_href + 'loginways')
    let loginWays = localStorage.getItem(window.GLOB.sysSign + 'loginways')
    if (loginWays) {
      try {
        loginWays = JSON.parse(window.decodeURIComponent(window.atob(loginWays)))
@@ -870,7 +898,7 @@
  }
  render () {
    const { lineColor, bgImage, loginlogo, copyRight, webSite, ICP, loginWays, touristLogin } = this.state
    const { lineColor, bgImage, loginlogo, copyRight, webSite, ICP, loginWays } = this.state
    return (
      <div className="login-container" id="mk-login-view" style={bgImage ? {backgroundImage: 'url(' + bgImage + ')'} : {}}>
@@ -880,12 +908,9 @@
        </div>
        <div className="login-middle" style={lineColor ? {borderColor: lineColor} : {}}>
          {loginWays ? <LoginForm
            dict={this.state.dict}
            auth={this.state.auth}
            authError={this.state.authError}
            touristLogin={touristLogin}
            loginWays={loginWays}
            lang={this.state.selectedlang}
            langList={this.state.langList}
            isDisabled={this.state.isDisabled}
            handleSubmit={() => this.handleSubmit()}
@@ -903,9 +928,7 @@
        </div>
        {/* 编辑状态登录 */}
        <Modal
          title={this.state.dict['login.sync.cloud']}
          okText={this.state.dict['login.ok']}
          cancelText={this.state.dict['login.cancel']}
          title="同步云端应用"
          visible={this.state.syncApp}
          onOk={this.syncSubmit}
          maskClosable={false}
src/views/login/logincloudform.jsx
@@ -2,17 +2,11 @@
import PropTypes from 'prop-types'
import { Form, Input } from 'antd'
import { UserOutlined, LockOutlined } from '@ant-design/icons'
import zhCN from '@/locales/zh-CN/login.js'
import enUS from '@/locales/en-US/login.js'
import './index.scss'
class HeaderLoginForm extends Component {
  static propTpyes = {
    handleSubmit: PropTypes.func
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
  }
  handleConfirm = () => {
@@ -60,12 +54,12 @@
      <Form style={{margin: '0px 10px'}}>
        <Form.Item>
          {getFieldDecorator('cloudusername', {
            rules: [{ required: true, message: this.state.dict['login.username.empty'] }],
            rules: [{ required: true, message: '请输入用户名' }],
            initialValue: '',
          })(
            <Input
              prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
              placeholder={this.state.dict['login.username']}
              placeholder="用户名"
              autoComplete="off"
              onPressEnter={(e) => {this.handleSubmit(e, 'cloudpassword')}}
            />
@@ -77,10 +71,10 @@
            rules: [
              {
                required: true,
                message: this.state.dict['login.password.empty'],
                message: '请输入密码',
              }
            ]
          })(<Input.Password onPressEnter={(e) => {this.handleSubmit(e, 'cloudusername')}} placeholder={this.state.dict['login.password']} prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
          })(<Input.Password onPressEnter={(e) => {this.handleSubmit(e, 'cloudusername')}} placeholder="密码" prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
        </Form.Item>
      </Form>
    )
src/views/login/loginform.jsx
@@ -21,11 +21,8 @@
    isDisabled: PropTypes.bool,
    handleSubmit: PropTypes.func,
    authLogin: PropTypes.func,
    dict: PropTypes.object,
    auth: PropTypes.bool,
    authError: PropTypes.string,
    touristLogin: PropTypes.bool,
    lang: PropTypes.string,
    langList: PropTypes.array,
    loginWays: PropTypes.array
  }
@@ -42,7 +39,10 @@
    verdisabled: false,
    hasScan: false,
    timeout: false,
    users: []
    wayLabels: {},
    dict: window.GLOB.dict,
    users: [],
    lang: sessionStorage.getItem('lang')
  }
  timer = null
@@ -51,9 +51,14 @@
  UNSAFE_componentWillMount () {
    const { loginWays } = this.props
    let remember = true
    let _url = window.location.href.split('#')[0]
    if (localStorage.getItem(window.location.href.split('#')[0] + 'users')) { // 过渡
      localStorage.setItem(window.GLOB.sysSign + 'users', localStorage.getItem(window.location.href.split('#')[0] + 'users'))
      localStorage.setItem(window.GLOB.sysSign + 'remember', localStorage.getItem(window.location.href.split('#')[0] + 'remember'))
      localStorage.removeItem(window.location.href.split('#')[0] + 'users')
    }
    
    if (localStorage.getItem(_url + 'remember') === 'false') {
    if (localStorage.getItem(window.GLOB.sysSign + 'remember') === 'false') {
      remember = false
    }
    if (!window.GLOB.keepKey) {
@@ -63,28 +68,28 @@
    let smsId = ''
    let hasScan = false
    let _loginWays = []
    let wayLabels = {app_scan: 'APP扫码', weixin_scan: '微信扫码', uname_pwd: '账号登录', sms_vcode: '短信登录'}
    loginWays.forEach(item => {
      item.label = window.GLOB.dict[item.type] || wayLabels[item.type]
      wayLabels[item.type] = item.label
      if (item.type === 'sms_vcode') {
        item.label = '短信登录'
        smsId = item.smsId
        _loginWays.push(item)
      } else if (item.type === 'uname_pwd') {
        item.label = '账号登录'
        _loginWays.push(item)
      } else if (item.type === 'app_scan') {
        item.label = 'APP扫码'
        _loginWays.push(item)
        hasScan = true
      } else if (item.type === 'weixin_scan') {
        item.label = '微信扫码'
        _loginWays.push(item)
        hasScan = true
      }
    })
    let activeKey = _loginWays[0].type
    let users = localStorage.getItem(_url + 'users')
    let users = localStorage.getItem(window.GLOB.sysSign + 'users')
    let _user = null
    
    if (users) {
@@ -111,6 +116,7 @@
      scanId: activeKey === 'app_scan' || activeKey === 'weixin_scan' ? Utils.getuuid() : '',
      timeout: false,
      remember,
      wayLabels,
      hasScan
    })
@@ -180,22 +186,20 @@
  }
  changelang = (val) => {
    const _href = window.location.href.split('#')[0]
    localStorage.setItem(_href + 'lang', val)
    localStorage.setItem(window.location.href.split('#')[0] + 'lang', val)
    sessionStorage.setItem('lang', val)
    window.location.reload()
  }
  handleSubmit = e => {
    const { activeKey } = this.state
    const { activeKey, dict } = this.state
    // 登录参数检验
    e && e.preventDefault()
    if (!this.props.auth) {
      warning({
        title: this.props.authError || this.props.dict['login.auth.tip'],
        okText: this.props.dict['login.ok'],
        cancelText: this.props.dict['login.cancel'],
        title: this.props.authError || dict['auth_tip'] || '系统未授权,请联系管理员。',
        okText: dict['got_it'] || '知道了',
        onOk() {},
        onCancel() {}
      })
@@ -275,16 +279,16 @@
  }
  getvercode = () => {
    const { smsId } = this.state
    const { smsId, dict } = this.state
    let _phone = this.props.form.getFieldValue('phone')
    if (!_phone) {
      message.warning('请输入手机号!')
      message.warning(dict['phone_no_required'] || '请输入手机号!')
      return
    } else if (!/^1[3456789]\d{9}$/.test(_phone)) {
      message.warning('手机号格式错误,请重填!')
      message.warning(dict['phone_error'] || '手机号格式错误,请重填!')
      return
    } else if (!this.props.touristLogin) {
      message.warning('未获取验证码设置,请稍后或刷新重试!')
    } else if (!sessionStorage.getItem('visitorUserID') || !sessionStorage.getItem('visitorLoginUID')) {
      message.warning(dict['vercode_error'] || '未获取验证码设置,请稍后或刷新重试!')
      return
    }
@@ -392,9 +396,8 @@
  rememberChange = (e) => {
    let val = e.target.checked
    let _url = window.location.href.split('#')[0]
    localStorage.setItem(_url + 'remember', val)
    localStorage.setItem(window.GLOB.sysSign + 'remember', val)
  }
  complete = (val) => {
@@ -422,9 +425,7 @@
    
    this.setState({users: _users})
    let _url = window.location.href.split('#')[0]
    localStorage.setItem(_url + 'users', window.btoa(window.encodeURIComponent(JSON.stringify(_users))))
    localStorage.setItem(window.GLOB.sysSign + 'users', window.btoa(window.encodeURIComponent(JSON.stringify(_users))))
  }
  /**
@@ -440,8 +441,7 @@
  render() {
    const { langList } = this.props
    const { getFieldDecorator } = this.props.form
    const { activeKey, verdisabled, delay, loginWays, remember, scanId, timeout, hasScan, users } = this.state
    const wayLabels = {app_scan: 'APP扫码', weixin_scan: '微信扫码', uname_pwd: '账号登录', sms_vcode: '短信登录'}
    const { activeKey, verdisabled, delay, loginWays, remember, scanId, timeout, hasScan, users, wayLabels, dict, lang } = this.state
    return (
      <Form className="login-form" id="login-form" onSubmit={this.handleSubmit}>
@@ -450,7 +450,7 @@
        {activeKey === 'uname_pwd' ? <div className="form-item-wrap">
          <Form.Item>
            {getFieldDecorator('username', {
              rules: [{ required: true, message: this.props.dict['login.username.empty'] }],
              rules: [{ required: true, message: dict['username_required'] || '请输入用户名' }],
              initialValue: this.state.username || '',
            })(
              <AutoComplete
@@ -467,7 +467,7 @@
              >
                <Input
                  prefix={<UserOutlined style={{ color: 'rgba(0,0,0,.25)' }} />}
                  placeholder={this.props.dict['login.username']}
                  placeholder={dict['username'] || '用户名'}
                  autoComplete="off"
                />
              </AutoComplete>
@@ -479,20 +479,20 @@
              rules: [
                {
                  required: true,
                  message: this.props.dict['login.password.empty'],
                  message: dict['password_required'] || '请输入密码',
                }
              ]
            })(<Input.Password placeholder={this.props.dict['login.password']} prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
            })(<Input.Password placeholder={dict['password'] || '密码'} prefix={<LockOutlined style={{ color: 'rgba(0,0,0,.25)' }} />} />)}
          </Form.Item>
          {window.GLOB.keepKey ? <Form.Item className="minline">
            {getFieldDecorator('remember', {
              valuePropName: 'checked',
              initialValue: remember,
            })(<Checkbox onChange={this.rememberChange}>{this.props.dict['login.remember']}</Checkbox>)}
            })(<Checkbox onChange={this.rememberChange}>{dict['remember_me'] || '记住密码'}</Checkbox>)}
          </Form.Item> : <div style={{height: '30px', float: 'left'}}></div>}
          {langList && langList.length > 0 ? <Form.Item className="minline right">
            {getFieldDecorator('lang', {
              initialValue: this.props.lang,
              initialValue: lang,
            })(
              <Select
                onChange={(value) => {this.changelang(value)}}
@@ -506,7 +506,7 @@
          </Form.Item> : null}
          <Form.Item className="btn-login">
            <Button type="primary" htmlType="submit" className="login-form-button" disabled={this.props.isDisabled} loading={this.props.isDisabled}>
              {this.props.dict['login.submit']}
              {dict['log_in'] || '登录'}
            </Button>
          </Form.Item>
          {window.GLOB.sysType === 'cloud' && options.cdomain.indexOf('mk9h') > -1 ? <Form.Item className="register-line">
@@ -517,11 +517,11 @@
        {activeKey === 'sms_vcode' ? <div className="form-item-wrap">
          <Form.Item>
            {getFieldDecorator('phone', {
              rules: [{ required: true, message: this.props.dict['login.phone.empty'] }],
              rules: [{ required: true, message: dict['phone_no_required'] || '请输入手机号' }],
              initialValue: '',
            })(
              <Input
                placeholder={this.props.dict['login.phone']}
                placeholder={dict['phone_no'] || '手机号'}
                autoComplete="off"
              />
            )}
@@ -532,24 +532,24 @@
              rules: [
                {
                  required: true,
                  message: this.props.dict['login.vercode.empty'],
                  message: dict['vercode_required'] || '请输入验证码',
                }
              ]
            })(
              <Input
                addonAfter={
                  <Button type="link" className="vercode" size="small" disabled={verdisabled} onClick={this.getvercode}>
                    {delay ? `${delay}s后重新获取` : '获取验证码'}
                    {delay ? `${delay}s` : dict['query_vercode'] || '获取验证码'}
                  </Button>
                }
                placeholder={this.props.dict['login.vercode']}
                placeholder={dict['vercode'] || '验证码'}
                autoComplete="off"
              />
            )}
          </Form.Item>
          {langList && langList.length > 0 ? <Form.Item className="minline right">
            {getFieldDecorator('lang', {
              initialValue: this.props.lang,
              initialValue: lang,
            })(
              <Select
                onChange={(value) => {this.changelang(value)}}
@@ -563,7 +563,7 @@
          </Form.Item> : null}
          <Form.Item className="btn-login">
            <Button type="primary" htmlType="submit" className="login-form-button" disabled={this.props.isDisabled} loading={this.props.isDisabled}>
              {this.props.dict['login.submit']}
              {dict['log_in'] || '登录'}
            </Button>
          </Form.Item>
          {window.GLOB.sysType === 'cloud' && options.cdomain.indexOf('mk9h') > -1 ? <Form.Item className="register-line">
@@ -577,10 +577,10 @@
              {scanId ? <QrCode card={{qrWidth: 500, color: '#000000'}} value={`https://cloud.mk9h.cn/mob/mknotice.html?originurl=${window.btoa(window.GLOB.baseurl + 'mob/index.html#/wx/' + scanId)}`}/> : null}
              {timeout ? <div className="qrcode-out">
                <RedoOutlined onClick={this.reCode} />
                二维码已失效。
                {dict['code_expired'] || '二维码已失效。'}
              </div> : null}
            </div>
            <img src={wxicon} alt=""/>请使用微信扫一扫登录
            <img src={wxicon} alt=""/>{dict['wechat_scan'] || '请使用微信扫一扫登录'}
          </div>
        </div> : null}
        {activeKey === 'app_scan' ? <div className="form-item-wrap">
@@ -589,10 +589,10 @@
              {scanId ? <QrCode card={{qrWidth: 500, color: '#000000'}} value={`mkpcscan,${window.GLOB.appkey},${scanId}`}/> : null}
              {timeout ? <div className="qrcode-out">
                <RedoOutlined onClick={this.reCode} />
                二维码已失效。
                {dict['code_expired'] || '二维码已失效。'}
              </div> : null}
            </div>
            请使用客户端扫一扫登录
            {dict['client_scan'] || '请使用客户端扫一扫登录'}
          </div>
        </div> : null}
        <div className={'login-ways ' + (activeKey === 'app_scan' || activeKey === 'weixin_scan' ? 'center' : '')}>
src/views/main/index.jsx
@@ -1,7 +1,4 @@
import React, {Component} from 'react'
import { ConfigProvider } from 'antd'
// import enUS from 'antd/es/locale/en_US'
import zhCN from 'antd/es/locale/zh_CN'
import asyncComponent from '@/utils/asyncComponent'
import Header from '@/components/header'
@@ -76,14 +73,12 @@
    return (
      <div className="mk-main-view">
        <ConfigProvider locale={zhCN}>
          <Header key="header"/>
          {navBar === 'shutter' ? <Sidemenu key="sidemenu"/> : null}
          {navBar === 'shutter' || navBar === 'menu_board_navigation' ?
            <Tabview key="tabview"/> :
            <Breadview key="breadview"/>}
          {window.GLOB.systemType === 'production' ? <QueryLog /> : null}
        </ConfigProvider>
        <Header key="header"/>
        {navBar === 'shutter' ? <Sidemenu key="sidemenu"/> : null}
        {navBar === 'shutter' || navBar === 'menu_board_navigation' ?
          <Tabview key="tabview"/> :
          <Breadview key="breadview"/>}
        {window.GLOB.systemType === 'production' ? <QueryLog /> : null}
        <ImgScale />
      </div>
    )
src/views/menudesign/index.jsx
@@ -4,16 +4,16 @@
import { is, fromJS } from 'immutable'
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { ConfigProvider, notification, Modal, Collapse, Card, Switch, Button, Typography, Spin } from 'antd'
import { notification, Modal, Collapse, Card, Switch, Button, Typography, Spin } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'
import html2canvas from 'html2canvas'
import md5 from 'md5'
import Api from '@/api'
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import { langs } from '@/store/options'
import MKEmitter from '@/utils/events.js'
import { getTables, getFuncsAndInters } from '@/utils/utils-custom.js'
import { getTables, getFuncsAndInters, getLangTrans } from '@/utils/utils-custom.js'
import asyncComponent from '@/utils/asyncComponent'
import '@/assets/css/design.scss'
@@ -22,7 +22,6 @@
const { Panel } = Collapse
const { confirm } = Modal
const { Paragraph } = Typography
const _locale = antdZhCN
const MenuForm = asyncComponent(() => import('./menuform'))
const HomeForm = asyncComponent(() => import('./homeform'))
@@ -67,6 +66,7 @@
    eyeopen: false,
    view: '',
    popConfig: null,
    langName: '',
    needUpdate: false
  }
@@ -98,12 +98,17 @@
      sessionStorage.setItem('MenuType', param.MenuType || 'custom')
      if (param.MenuType === 'billPrint' && param.lang) {
        sessionStorage.setItem('lang', param.lang)
      }
      this.setState({
        MenuType: param.MenuType,
        MenuId: param.MenuId || param.MenuID,
        ParentId: param.ParentId || '',
        MenuName: param.MenuName || '',
        MenuNo: param.MenuNo || '',
        langName: sessionStorage.getItem('lang') !== 'zh-CN' && langs[sessionStorage.getItem('lang')] ? `(${langs[sessionStorage.getItem('lang')]})` : ''
      }, () => {
        this.getMenuParam()
      })
@@ -772,6 +777,18 @@
        duration: 5
      })
      return
    } else if (this.checklog()) {
      if (sessionStorage.getItem('langList') && !config.trans) {
      } else {
        notification.success({
          top: 92,
          message: '当前配置未修改,无需保存。',
          duration: 5
        })
        MKEmitter.emit('completeSave')
        return
      }
    }
    this.setState({
@@ -834,6 +851,7 @@
      let interfaces = getFuncsAndInters(config)
      let urlFields = config.urlFields ? config.urlFields.join(',') : ''
      let langSql = getLangTrans(config)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
@@ -847,12 +865,16 @@
        MenuName: config.MenuName || '',
        PageParam: JSON.stringify({Template: 'CustomPage', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces, urlFields}),
        open_edition: config.open_edition,
        LText: '',
        LTexttb: '',
        // LText: '',
        // LTexttb: '',
        debug_md5: key,
        debug_url: url,
        debug_list: window.btoa(tbs),
        LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(config)))
      }
      if (langSql) {
        param.lang_translation = window.btoa(window.encodeURIComponent(langSql))
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -1185,11 +1207,11 @@
  }
  render () {
    const { view, comloading, MenuType, MenuId, config, settingshow, ParentId, menuloading, eyeopen, needUpdate } = this.state
    const { view, comloading, MenuType, MenuId, config, settingshow, ParentId, menuloading, eyeopen, needUpdate, langName } = this.state
    return (
      <ConfigProvider locale={_locale}>
        <Header menuName={config ? config.MenuName : ''}/>
      <>
        <Header menuName={config ? config.MenuName + langName : ''}/>
        <DndProvider backend={HTML5Backend}>
          {view !== 'popview' ? <div className={'pc-menu-view ' + (MenuType || '')}>
            <div className="menu-body">
@@ -1265,7 +1287,7 @@
        <ModalController />
        <StyleController />
        <StyleCombController />
      </ConfigProvider>
      </>
    )
  }
}
src/views/mkiframe/index.jsx
@@ -1,6 +1,5 @@
import React, {Component} from 'react'
import { Spin, notification, ConfigProvider } from 'antd'
import zhCN from 'antd/es/locale/zh_CN'
import { Spin, notification } from 'antd'
import Api from '@/api'
import asyncComponent from '@/utils/asyncLoadComponent'
@@ -267,11 +266,9 @@
    return (
      <div className="main-iframe">
        <ConfigProvider locale={zhCN}>
          {loading ? <Spin size="large" /> : null}
          {!loading && type === 'CustomPage' ? <CustomPage MenuID={MenuId} param={{$BID: BID}} changeTemp={this.changeTemp}/> : null}
          {!loading && type === 'BaseTable' ? <BaseTable MenuID={MenuId} param={{$BID: BID}} changeTemp={this.changeTemp}/> : null}
        </ConfigProvider>
        {loading ? <Spin size="large" /> : null}
        {!loading && type === 'CustomPage' ? <CustomPage MenuID={MenuId} param={{$BID: BID}} changeTemp={this.changeTemp}/> : null}
        {!loading && type === 'BaseTable' ? <BaseTable MenuID={MenuId} param={{$BID: BID}} changeTemp={this.changeTemp}/> : null}
        <ImgScale />
      </div>
    )
src/views/mobdesign/index.jsx
@@ -3,16 +3,15 @@
import { withRouter } from 'react-router'
import { is, fromJS } from 'immutable'
import HTML5Backend from 'react-dnd-html5-backend'
import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin, Typography } from 'antd'
import { notification, Modal, Collapse, Switch, Button, message, Spin, Typography } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined, HomeOutlined, LoginOutlined, ArrowLeftOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import MKEmitter from '@/utils/events.js'
import MenuUtils, { getTables, getFuncsAndInters } from '@/utils/utils-custom.js'
import MenuUtils, { getTables, getFuncsAndInters, getLangTrans } from '@/utils/utils-custom.js'
import asyncComponent from '@/utils/asyncComponent'
import '@/assets/css/design.scss'
@@ -99,11 +98,14 @@
    try {
      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
      if (param.lang) {
        sessionStorage.setItem('lang', param.lang)
      }
      if (param.type === 'app') {
        sessionStorage.setItem('appId', param.ID || '')
        sessionStorage.setItem('appName', param.remark || '')
        sessionStorage.setItem('lang', param.lang || 'zh-CN')
        sessionStorage.setItem('kei_no', param.kei_no || '')
        sessionStorage.setItem('typename', param.typename || 'mob')
        sessionStorage.setItem('adapter', param.adapter || '')
@@ -111,6 +113,12 @@
        sessionStorage.setItem('direction', param.direction || 'vertical')
        sessionStorage.setItem('userbind', param.userbind || '')
        sessionStorage.setItem('instantMessage', param.instantMessage || '')
        if (param.applangList) {
          sessionStorage.setItem('applangList', param.applangList)
        } else {
          sessionStorage.removeItem('applangList')
        }
        this.getAppMessage(param.MenuID)
      } else if (param.type === 'view') {
@@ -390,7 +398,8 @@
      MenuID: menu.MenuID,
      copyMenuId: menu.copyMenuId || '',
      clearMenu: menu.clearMenu !== 'false',
      type: 'view'
      type: 'view',
      lang: sessionStorage.getItem('lang')
    }
    param.MenuNo = menu.MenuNo || ''
@@ -463,12 +472,12 @@
            })
          } else {
            sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
            this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
            this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view', lang: sessionStorage.getItem('lang')}))))
          }
        })
      } else {
        sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
        this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view'}))))
        this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view', lang: sessionStorage.getItem('lang')}))))
      }
    })
  }
@@ -1406,6 +1415,18 @@
        activeKey: 'basedata'
      })
      return
    } else if (this.checklog()) {
      if (sessionStorage.getItem('applangList') && !config.trans) {
      } else {
        notification.success({
          top: 92,
          message: '当前配置未修改,无需保存。',
          duration: 5
        })
        MKEmitter.emit('completeSave')
        return
      }
    }
    this.setState({
@@ -1509,6 +1530,7 @@
      let interfaces = getFuncsAndInters(config)
      roleParam.interfaces = interfaces
      let langSql = getLangTrans(config)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
@@ -1525,12 +1547,16 @@
        PageParam: JSON.stringify({Template: 'webPage', interfaces}),
        open_edition: config.open_edition,
        menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roleParam))),
        LText: '',
        LTexttb: '',
        // LText: '',
        // LTexttb: '',
        menus_used_list,
        debug_md5: key,
        debug_url: url,
        debug_list: window.btoa(tbs)
      }
      if (langSql) {
        param.lang_translation = window.btoa(window.encodeURIComponent(langSql))
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -1594,8 +1620,8 @@
              PageParam: JSON.stringify({Template: NavBar.type}),
              open_edition: _item ? (_item.open_edition || '') : '',
              menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
              LText: '',
              LTexttb: ''
              // LText: '',
              // LTexttb: ''
            }
            _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(NavBar)))
@@ -2048,92 +2074,90 @@
    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/>
          {loading ? <Spin className="view-spin" size="large" /> : null}
          <DndProvider backend={HTML5Backend}>
            {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}
              </div>
              <div className="pc-setting-tools">
                <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
                  {/* 基本信息 */}
                  <Panel header="基本信息" forceRender className="basedata" key="basedata">
                    {config ? <>
                      <MenuForm
                        config={config}
                        MenuId={MenuId}
                        adapters={adapters}
                        updateConfig={(con) => {
                          this.updateConfig(con)
                          if (con.direction !== config.direction) {
                            this.changeView(con.direction)
                          }
                        }}
                      />
                      <UrlFieldComponent config={config} updateConfig={this.updateConfig}/>
                      {/* 表名添加 */}
                      <TableComponent config={config} updatetable={this.updateConfig}/>
                      <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>菜单ID</Paragraph>
                      <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>
                      <NormalCss config={config} updateConfig={this.updateConfig}/>
                    </> : null}
                  </Panel>
                  {/* 组件添加 */}
                  <Panel header="组件" className="component" key="component">
                    <SourceWrap />
                  </Panel>
                  <Panel header="元素" key="element">
                    <Modulecell />
                  </Panel>
                  <Panel header="页面样式" key="background">
                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                  </Panel>
                </Collapse>
              </div>
      <div className={'mk-mob-view ' + viewType} id="mk-mob-design-view">
        <Header/>
        {loading ? <Spin className="view-spin" size="large" /> : null}
        <DndProvider backend={HTML5Backend}>
          {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}
            </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" className={needUpdate ? 'update-tip' : ''} onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
                {config ? <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} /> : null}
                <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
                {config ? <Debug config={config}/> : null}
                <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
                <CreateView resetmenu={this.getAppMenus} />
                <PasteController insert={this.insert} />
                <TableNodes config={config} />
                <ViewNodes config={config} MenuId={MenuId}/>
                <SysInterface config={config} updateConfig={this.updateConfig}/>
                <PictureController/>
                <Quotecomponent config={config} updateConfig={this.updateConfig}/>
                <StyleCombControlButton menu={config} />
                <Button className="mk-border-green set-home" onClick={this.setHomeView}><HomeOutlined /> 设为首页</Button>
                <Button className="mk-border-purple set-login" onClick={this.setLoginView}><LoginOutlined /> 设为登录页</Button>
                <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                <Transfer MenuID={MenuId} />
                {config ? <Versions MenuId={MenuId} Template="webPage" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
                <Button type="default" onClick={this.closeView}>关闭</Button>
              </div>
            <div className="pc-setting-tools">
              <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
                {/* 基本信息 */}
                <Panel header="基本信息" forceRender className="basedata" key="basedata">
                  {config ? <>
                    <MenuForm
                      config={config}
                      MenuId={MenuId}
                      adapters={adapters}
                      updateConfig={(con) => {
                        this.updateConfig(con)
                        if (con.direction !== config.direction) {
                          this.changeView(con.direction)
                        }
                      }}
                    />
                    <UrlFieldComponent config={config} updateConfig={this.updateConfig}/>
                    {/* 表名添加 */}
                    <TableComponent config={config} updatetable={this.updateConfig}/>
                    <Paragraph style={{padding: '15px 0px 0px 18px'}} copyable={{ text: MenuId }}>菜单ID</Paragraph>
                    <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>
                    <NormalCss config={config} updateConfig={this.updateConfig}/>
                  </> : null}
                </Panel>
                {/* 组件添加 */}
                <Panel header="组件" className="component" key="component">
                  <SourceWrap />
                </Panel>
                <Panel header="元素" key="element">
                  <Modulecell />
                </Panel>
                <Panel header="页面样式" key="background">
                  {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                </Panel>
              </Collapse>
            </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></> : <PopView btn={this.state.popConfig} save={this.submitPopConfig} cancel={this.closePop}/>}
          </DndProvider>
          <StyleController />
          <StyleCombController />
          <ModalController />
          <SearchController />
        </div>
      </ConfigProvider>
          </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" className={needUpdate ? 'update-tip' : ''} onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
              {config ? <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} /> : null}
              <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
              {config ? <Debug config={config}/> : null}
              <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
              <CreateView resetmenu={this.getAppMenus} />
              <PasteController insert={this.insert} />
              <TableNodes config={config} />
              <ViewNodes config={config} MenuId={MenuId}/>
              <SysInterface config={config} updateConfig={this.updateConfig}/>
              <PictureController/>
              <Quotecomponent config={config} updateConfig={this.updateConfig}/>
              <StyleCombControlButton menu={config} />
              <Button className="mk-border-green set-home" onClick={this.setHomeView}><HomeOutlined /> 设为首页</Button>
              <Button className="mk-border-purple set-login" onClick={this.setLoginView}><LoginOutlined /> 设为登录页</Button>
              <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
              <Transfer MenuID={MenuId} />
              {config ? <Versions MenuId={MenuId} Template="webPage" checklog={this.checklog} updateConfig={this.updateLogConfig}/> : null}
              <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></> : <PopView btn={this.state.popConfig} save={this.submitPopConfig} cancel={this.closePop}/>}
        </DndProvider>
        <StyleController />
        <StyleCombController />
        <ModalController />
        <SearchController />
      </div>
    )
  }
}
src/views/pcdesign/index.jsx
@@ -3,15 +3,14 @@
import { withRouter } from 'react-router'
import { is, fromJS } from 'immutable'
import HTML5Backend from 'react-dnd-html5-backend'
import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin, Typography } from 'antd'
import { notification, Modal, Collapse, Switch, Button, message, Spin, Typography } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined, HomeOutlined, LoginOutlined, ArrowLeftOutlined, EyeOutlined, EyeInvisibleOutlined } from '@ant-design/icons'
import moment from 'moment'
import md5 from 'md5'
import Api from '@/api'
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import { getTables, getFuncsAndInters } from '@/utils/utils-custom.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import { getTables, getFuncsAndInters, getLangTrans } from '@/utils/utils-custom.js'
import MKEmitter from '@/utils/events.js'
import MenuUtils from '@/utils/utils-custom.js'
import asyncComponent from '@/utils/asyncComponent'
@@ -100,12 +99,21 @@
    try {
      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
      if (param.lang) {
        sessionStorage.setItem('lang', param.lang)
      }
      if (param.type === 'app') {
        sessionStorage.setItem('appId', param.ID || '')
        sessionStorage.setItem('appName', param.remark || '')
        sessionStorage.setItem('lang', param.lang || 'zh-CN')
        sessionStorage.setItem('kei_no', param.kei_no || '')
        sessionStorage.setItem('sysBgColor', param.sysBgColor || '#ffffff')
        if (param.applangList) {
          sessionStorage.setItem('applangList', param.applangList)
        } else {
          sessionStorage.removeItem('applangList')
        }
        this.getAppMessage(param.MenuID)
      } else if (param.type === 'view') {
@@ -240,7 +248,8 @@
      MenuID: menu.MenuID,
      copyMenuId: menu.copyMenuId || '',
      clearMenu: menu.clearMenu !== 'false',
      type: 'view'
      type: 'view',
      lang: sessionStorage.getItem('lang')
    }
    // param.MenuNo = menu.MenuNo || ''
@@ -316,12 +325,12 @@
            })
          } else {
            sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
            this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'}))))
            this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view', lang: sessionStorage.getItem('lang')}))))
          }
        })
      } else {
        sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
        this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view'}))))
        this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view', lang: sessionStorage.getItem('lang')}))))
      }
    })
  }
@@ -1140,6 +1149,18 @@
    if (!this.checkBase()) {
      return
    } else if (this.checklog()) {
      if (sessionStorage.getItem('applangList') && !config.trans) {
      } else {
        notification.success({
          top: 92,
          message: '当前配置未修改,无需保存。',
          duration: 5
        })
        MKEmitter.emit('completeSave')
        return
      }
    }
    this.setState({
@@ -1208,6 +1229,7 @@
      let interfaces = getFuncsAndInters(config)
      roleParam.interfaces = interfaces
      let langSql = getLangTrans(config)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
@@ -1224,12 +1246,16 @@
        PageParam: JSON.stringify({Template: 'webPage', interfaces}),
        menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roleParam))),
        open_edition: config.open_edition,
        LText: '',
        LTexttb: '',
        // LText: '',
        // LTexttb: '',
        menus_used_list,
        debug_md5: key,
        debug_url: url,
        debug_list: window.btoa(tbs)
      }
      if (langSql) {
        param.lang_translation = window.btoa(window.encodeURIComponent(langSql))
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -1310,8 +1336,8 @@
              PageParam: JSON.stringify({Template: NavBar.type}),
              menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
              open_edition: NavBar.open_edition,
              LText: '',
              LTexttb: ''
              // LText: '',
              // LTexttb: ''
            }
            _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(NavBar)))
@@ -1696,7 +1722,7 @@
    const { view, loading, comloading, activeKey, settingshow, controlshow, MenuId, config, menuloading, eyeopen, needUpdate } = this.state
    return (
      <ConfigProvider locale={antdZhCN}>
      <>
        <DndProvider backend={HTML5Backend}>
          {view !== 'popview' ? <div className={'mk-pc-view '} id="mk-pc-design-view">
            {loading ? <Spin className="view-spin" size="large" /> : null}
@@ -1773,7 +1799,7 @@
        <StyleController />
        <StyleCombController />
        <ModalController />
      </ConfigProvider>
      </>
    )
  }
}
src/views/printTemplate/index.jsx
@@ -20,6 +20,7 @@
  qrurl,
  imgurl
} from './option.js'
import { langs } from '@/store/options'
import Utils from '@/utils/utils.js'
import printCtrl from './print.js'
import Api from '@/api'
@@ -35,7 +36,9 @@
class PrintTemplate extends Component {
  state = {
    config: null,
    oriConfig: null,
    ID: null,
    langName: '',
    editItemId: '',
    editItemType: '',
    fields: [],
@@ -67,16 +70,24 @@
  }
  UNSAFE_componentWillMount () {
    let _param = window.atob(this.props.match.params.param)
    let _params = {}
    _param.split('&').forEach(cell => {
      let _cell = cell.split('=')
      _params[_cell[0]] = _cell[1]
    })
    try {
      let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
    this.setState({
      ID: _params.ID
    })
      if (param.lang) {
        sessionStorage.setItem('lang', param.lang)
      }
      this.setState({
        langName: sessionStorage.getItem('lang') !== 'zh-CN' && langs[sessionStorage.getItem('lang')] ? `(${langs[sessionStorage.getItem('lang')]})` : '',
        ID: param.ID
      })
    } catch (e) {
      notification.warning({
        top: 92,
        message: '模板信息解析错误!',
        duration: 5
      })
    }
  }
  componentDidMount () {
@@ -88,7 +99,7 @@
      let cy = position.cy
      let _selectItem = null
      let _config = JSON.parse(JSON.stringify(this.state.config))
      let _config = fromJS(this.state.config).toJS()
      _config.elements.forEach(element => {
        let x = +element.left
@@ -156,8 +167,8 @@
        return
      }
      let _selectItem = JSON.parse(JSON.stringify(this.state.config.elements.filter(ele => ele.uuid === this.state.editItemId)[0]))
      let _preItem = JSON.parse(JSON.stringify(_selectItem))
      let _selectItem = fromJS(this.state.config.elements.filter(ele => ele.uuid === this.state.editItemId)[0]).toJS()
      let _preItem = fromJS(_selectItem).toJS()
      let position = this.getclickpoint(e)
      let cx = position.cx
@@ -214,7 +225,7 @@
              let result = this.resetItem(_selectItem)
              if (!is(fromJS(result), fromJS(_preItem))) {
                _preItem = JSON.parse(JSON.stringify(result))
                _preItem = fromJS(result).toJS()
                this.FormRef.resetForm(result)
                config.elements = config.elements.map(item => {
@@ -261,7 +272,7 @@
              let result = this.resetItem(fromJS(_selectItem).toJS())
              if (!is(fromJS(result), fromJS(_preItem))) {
                _preItem = JSON.parse(JSON.stringify(result))
                _preItem = fromJS(result).toJS()
                this.FormRef.resetForm(result)
                config.elements = config.elements.map(item => {
@@ -407,6 +418,7 @@
      this.handleResize()
      this.setState({
        config: _config,
        oriConfig: fromJS(_config).toJS(),
        editItemId: _config.uuid,
        editItemType: _config.type,
        formlist: getpageform(_config)
@@ -779,9 +791,16 @@
  }
  submitConfig = () => {
    const { config } = this.state
    const { config, oriConfig } = this.state
    if (config.height / config.width > 10 || config.width / config.height > 10) {
    if (is(fromJS(config), fromJS(oriConfig))) {
      notification.success({
        top: 92,
        message: '当前模板未修改,无需保存。',
        duration: 5
      })
      return
    } else if (config.height / config.width > 10 || config.width / config.height > 10) {
      notification.warning({
        top: 92,
        message: '纸张纵横比不可超过10!',
@@ -878,6 +897,7 @@
        })
      }
      this.setState({
        oriConfig: fromJS(config).toJS(),
        saveloading: false
      })
    })
@@ -950,13 +970,13 @@
  }
  render () {
    const { debug } = this.state
    const { debug, langName } = this.state
    
    return (
      <div className="print-template">
        <DndProvider backend={HTML5Backend}>
          <header className="print-header-container ant-menu-dark">
            模板制作
            模板制作{langName}
            <div>快捷键:Delete(删除元素)、ctrl + q(复制元素)</div>
          </header>
          <aside className="tools">
src/views/rolemanage/index.jsx
@@ -1,9 +1,8 @@
import React, {Component} from 'react'
import { fromJS } from 'immutable'
import { Spin, notification, Button, Table, Modal, ConfigProvider, Tree, Input, Empty } from 'antd'
import { Spin, notification, Button, Table, Modal, Tree, Input, Empty } from 'antd'
import moment from 'moment'
import md5 from 'md5'
import zhCN from 'antd/es/locale/zh_CN'
import { ApiOutlined } from '@ant-design/icons'
import Api from '@/api'
@@ -83,6 +82,10 @@
  UNSAFE_componentWillMount() {
    document.body.className = ''
    let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param)))
    if (param.lang) {
      sessionStorage.setItem('lang', param.lang)
    }
    this.setState({app: param}, () => {
      this.getTreeList()
@@ -916,61 +919,59 @@
    return (
      <div className="mk-role-manage">
        <ConfigProvider locale={zhCN}>
          <Header app={app} />
          {loading ?
            <div className="loading-mask">
              <Spin size="large" />
            </div> : null
          }
          <div className="view-wrap">
            <div className="left-view">
              <div className="app-table">
                <div className="app-action">
                  <Button className="mk-green" onClick={this.triggerThaw}>解冻菜单</Button>
                  <Search placeholder="综合搜索" onSearch={value => this.setState({ searchkey: value })} enterButton />
                </div>
                <Table
                  rowKey="MenuID"
                  columns={columns}
                  dataSource={_menulist}
                  pagination={false}
                  onChange={this.changeTable}
                />
              </div>
            </div>
            <div className="right-view">
        <Header app={app} />
        {loading ?
          <div className="loading-mask">
            <Spin size="large" />
          </div> : null
        }
        <div className="view-wrap">
          <div className="left-view">
            <div className="app-table">
              <div className="app-action">
                <Button className="mk-primary" onClick={this.initTree}>重置</Button>
                {/* <Button className="mk-purple" onClick={this.syncTree}>同步</Button> */}
                <Button className="mk-green save" onClick={this.saveTree}>保存</Button>
                <Button className="mk-green" onClick={this.triggerThaw}>解冻菜单</Button>
                <Search placeholder="综合搜索" onSearch={value => this.setState({ searchkey: value })} enterButton />
              </div>
              {trees && trees.length ? <Tree
                className="draggable-tree"
                defaultExpandedKeys={this.state.expandedKeys}
                // showLine
                draggable
                blockNode
                onDrop={this.onDrop}
              >
                {this.renderNode(trees)}
              </Tree> : <div className="empty">
                <Empty />
              </div>}
              <Table
                rowKey="MenuID"
                columns={columns}
                dataSource={_menulist}
                pagination={false}
                onChange={this.changeTable}
              />
            </div>
          </div>
          <Modal
            title="解除冻结"
            visible={this.state.visible}
            width={600}
            onOk={this.thawSubmit}
            confirmLoading={this.state.confirmLoading}
            onCancel={() => this.setState({visible: false, targetKeys: []})}
            destroyOnClose
          >
            <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>
          </Modal>
        </ConfigProvider>
          <div className="right-view">
            <div className="app-action">
              <Button className="mk-primary" onClick={this.initTree}>重置</Button>
              {/* <Button className="mk-purple" onClick={this.syncTree}>同步</Button> */}
              <Button className="mk-green save" onClick={this.saveTree}>保存</Button>
            </div>
            {trees && trees.length ? <Tree
              className="draggable-tree"
              defaultExpandedKeys={this.state.expandedKeys}
              // showLine
              draggable
              blockNode
              onDrop={this.onDrop}
            >
              {this.renderNode(trees)}
            </Tree> : <div className="empty">
              <Empty />
            </div>}
          </div>
        </div>
        <Modal
          title="解除冻结"
          visible={this.state.visible}
          width={600}
          onOk={this.thawSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={() => this.setState({visible: false, targetKeys: []})}
          destroyOnClose
        >
          <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>
        </Modal>
      </div>
    )
  }
src/views/sso/index.jsx
@@ -66,8 +66,6 @@
          res.menu_type = 'shutter'
        }
        const _href = window.location.href.split('#')[0]
        let _url = _href + 'system'
        let systemMsg = {
          favicon: res.titlelogo || '',
          platTitle: res.titleName || '',
@@ -103,12 +101,12 @@
          level = ''
        }
        localStorage.setItem(_href + 'pwdlevel', level)
        localStorage.setItem(window.GLOB.sysSign + 'pwdlevel', level)
        if (res.srcid) {
          localStorage.setItem(_href + 'srcId', res.srcid)
          localStorage.setItem(window.GLOB.sysSign + 'srcId', res.srcid)
        } else {
          localStorage.removeItem(_href + 'srcId')
          localStorage.removeItem(window.GLOB.sysSign + 'srcId')
        }
        sessionStorage.setItem('home_background', res.index_background_color || '')
@@ -123,9 +121,9 @@
        document.title = systemMsg.platTitle
        try {
          localStorage.setItem(_url, window.btoa(window.encodeURIComponent(JSON.stringify(systemMsg))))
          localStorage.setItem(window.GLOB.sysSign + 'system', window.btoa(window.encodeURIComponent(JSON.stringify(systemMsg))))
        } catch (e) {
          localStorage.removeItem(_url)
          localStorage.removeItem(window.GLOB.sysSign + 'system')
        }
        window.GLOB.mainlogo = systemMsg.mainlogo
src/views/systemfunc/index.jsx
@@ -1,7 +1,5 @@
import React, {Component} from 'react'
import { ConfigProvider } from 'antd'
import { withRouter } from 'react-router-dom'
import zhCN from 'antd/es/locale/zh_CN'
import asyncComponent from '@/utils/asyncComponent'
import Header from './header'
@@ -59,11 +57,9 @@
  render () {
    return (
      <div className="mk-main-view">
        <ConfigProvider locale={zhCN}>
          <Sidemenu key="sidemenu"/>
          <Tabview key="tabview"/>
          <Header key="header"/>
        </ConfigProvider>
        <Sidemenu key="sidemenu"/>
        <Tabview key="tabview"/>
        <Header key="header"/>
        <ImgScale />
      </div>
    )
src/views/systemfunc/sidemenu/config.jsx
@@ -84,6 +84,14 @@
    MenuID: '15827879285193g85m3i2uprektpgmpf',
    MenuNo: 'bd_mes_techM',
    MenuName: '工艺主数据',
  }, {
    src: '',
    systems: ['local'],
    PageParam: {OpenType: 'newtab', Template: 'CustomPage'},
    type: 'CustomPage',
    MenuID: '17180925258436em38rhpqncckvohv0s',
    MenuNo: 's_app_lang_translation_M',
    MenuName: '语言包',
  }]
}, {
  MenuID: 'systemManageViewInterface',
src/views/systemproc/index.jsx
@@ -1,7 +1,5 @@
import React, {Component} from 'react'
import { ConfigProvider } from 'antd'
import { withRouter } from 'react-router-dom'
import zhCN from 'antd/es/locale/zh_CN'
import Header from '../systemfunc/header'
import Proc from './proc'
@@ -20,10 +18,8 @@
    return (
      <div className="mk-proc-view">
        <ConfigProvider locale={zhCN}>
          <Header key="header"/>
          <Proc func={func} />
        </ConfigProvider>
        <Header key="header"/>
        <Proc func={func} />
      </div>
    )
  }
src/views/tabledesign/index.jsx
@@ -4,15 +4,15 @@
import { is, fromJS } from 'immutable'
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { ConfigProvider, notification, Modal, Collapse, Card, Switch, Button, Typography } from 'antd'
import { notification, Modal, Collapse, Card, Switch, Button, Typography } from 'antd'
import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons'
import md5 from 'md5'
import Api from '@/api'
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import { langs } from '@/store/options'
import MKEmitter from '@/utils/events.js'
import { getTables, getFuncsAndInters } from '@/utils/utils-custom.js'
import { getTables, getFuncsAndInters, getLangTrans } from '@/utils/utils-custom.js'
import SourceElement from '@/templates/zshare/dragsource'
import asyncComponent from '@/utils/asyncComponent'
import Source from './source'
@@ -23,7 +23,6 @@
const { Panel } = Collapse
const { confirm } = Modal
const { Paragraph } = Typography
const _locale = antdZhCN
const MenuForm = asyncComponent(() => import('./menuform'))
const PopView = asyncComponent(() => import('./popview'))
@@ -59,6 +58,7 @@
    comloading: false,
    settingshow: sessionStorage.getItem('settingshow') !== 'false',
    view: null,
    langName: '',
    popConfig: null
  }
@@ -93,6 +93,7 @@
        ParentId: param.ParentId || '',
        MenuName: param.MenuName || '',
        MenuNo: param.MenuNo || '',
        langName: sessionStorage.getItem('lang') !== 'zh-CN' && langs[sessionStorage.getItem('lang')] ? `(${langs[sessionStorage.getItem('lang')]})` : ''
      }, () => {
        this.getMenuParam()
      })
@@ -425,8 +426,8 @@
        window.GLOB.urlFields = config.urlFields || []
        this.setState({
          oriConfig: config,
          config: fromJS(config).toJS()
          oriConfig: config.components[0].isNew ? {} : fromJS(config).toJS(),
          config: config
        })
        window.GLOB.customMenu = config
      } else {
@@ -532,6 +533,18 @@
    if (!this.checkBase()) {
      return
    } else if (this.checklog()) {
      if (sessionStorage.getItem('langList') && !config.trans) {
      } else {
        notification.success({
          top: 92,
          message: '当前配置未修改,无需保存。',
          duration: 5
        })
        MKEmitter.emit('completeSave')
        return
      }
    }
    this.setState({
@@ -582,6 +595,7 @@
      let interfaces = getFuncsAndInters(config)
      let urlFields = config.urlFields ? config.urlFields.join(',') : ''
      let langSql = getLangTrans(config)
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
@@ -595,12 +609,16 @@
        MenuName: config.MenuName || '',
        PageParam: JSON.stringify({Template: 'BaseTable', OpenType: config.OpenType || 'newtab', hidden: config.hidden || 'false', menuColor: config.menuColor || '', interfaces, urlFields}),
        open_edition: config.open_edition,
        LText: '',
        LTexttb: '',
        // LText: '',
        // LTexttb: '',
        debug_md5: key,
        debug_url: url,
        debug_list: window.btoa(tbs),
        LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(config)))
      }
      if (langSql) {
        param.lang_translation = window.btoa(window.encodeURIComponent(langSql))
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -841,11 +859,11 @@
  }
  render () {
    const { view, activeKey, comloading, MenuId, config, settingshow, ParentId, menuloading } = this.state
    const { view, activeKey, comloading, MenuId, config, settingshow, ParentId, menuloading, langName } = this.state
    return (
      <ConfigProvider locale={_locale}>
        <Header menuName={config ? config.MenuName : ''}/>
      <>
        <Header menuName={config ? config.MenuName + langName : ''}/>
        <DndProvider backend={HTML5Backend}>
        {view !== 'popview' ? <div className="pc-table-view">
            <div className="menu-body">
@@ -921,7 +939,7 @@
        </DndProvider>
        <StyleController />
        <ModalController />
      </ConfigProvider>
      </>
    )
  }
}