king
2022-10-27 83592b5c2dcbfd0a91d36dfa89f1a6cbe95ab1d1
2022-10-27
1 文件已重命名
47个文件已修改
5个文件已添加
3个文件已删除
5068 ■■■■■ 已修改文件
src/assets/css/main.scss 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/qrcode/index.scss 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/tabview/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/base-table/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/customscript/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/createview/index.jsx 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/basetable/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/calendar/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/share/normalTable/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 1002 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.scss 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/formtab/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/treepage/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/index.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.jsx 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/cardcomponent/index.jsx 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/tablenodes/index.jsx 458 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/tablenodes/index.scss 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/settingform/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/customscript/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/billprint/index.jsx 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/billprint/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/homeform/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/menuform/index.jsx 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/popview/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/printmenuform/index.jsx 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 687 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 846 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.scss 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/popdesign/index.jsx 743 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/popdesign/menuform/index.jsx 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/popdesign/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/views/rolemanage/index.jsx 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/systemfunc/sidemenu/config.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/index.jsx 138 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/menuform/index.jsx 71 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/popview/index.jsx 234 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/popview/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/views/tabledesign/source.jsx 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/main.scss
@@ -264,28 +264,6 @@
  }
}
// .ant-modal.popview-modal {
//   top: 70px;
//   .ant-modal-body {
//     min-height: 200px;
//     max-height: calc(100vh - 210px);
//     overflow-y: auto;
//   }
//   .ant-modal-body::-webkit-scrollbar {
//     width: 7px;
//   }
//   .ant-modal-body::-webkit-scrollbar-thumb {
//     border-radius: 5px;
//     box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
//     background: rgba(0, 0, 0, 0.13);
//   }
//   .ant-modal-body::-webkit-scrollbar-track {
//     box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
//     border-radius: 3px;
//     border: 1px solid rgba(0, 0, 0, 0.07);
//     background: rgba(0, 0, 0, 0);
//   }
// }
.ant-modal-wrap.popview-modal {
  .ant-modal {
    top: 70px;
src/components/qrcode/index.scss
@@ -1,5 +1,6 @@
.qrcode-box {
  display: inline-block;
  position: relative;
  canvas {
    vertical-align: top;
    max-width: 100%;
src/components/tabview/index.jsx
@@ -20,7 +20,7 @@
const BaseTable = asyncComponent(() => import('@/tabviews/basetable'))
const CalendarPage = asyncComponent(() => import('@/tabviews/calendar'))
const TreePage = asyncComponent(() => import('@/tabviews/treepage'))
const TabManage = asyncComponent(() => import('@/tabviews/tabmanage'))
// const TabManage = asyncComponent(() => import('@/tabviews/tabmanage'))
const Iframe = asyncComponent(() => import('@/tabviews/iframe'))
const RoleManage = asyncComponent(() => import('@/tabviews/rolemanage'))
const FormTab = asyncComponent(() => import('@/tabviews/formtab'))
@@ -199,8 +199,8 @@
      return (<TreePage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
    } else if (view.type === 'CalendarPage') {
      return (<CalendarPage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID} param={view.param}/>)
    } else if (view.type === 'TabManage') {
      return (<TabManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    // } else if (view.type === 'TabManage') {
    //   return (<TabManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'RolePermission') {
      return (<RoleManage MenuNo={view.MenuNo} MenuID={view.MenuID} MenuName={view.MenuName} key={view.MenuID}/>)
    } else if (view.type === 'FormTab') {
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -580,7 +580,7 @@
      key: 'noValue',
      label: '空值',
      initVal: card.noValue || 'show',
      tooltip: '当元素内容为空时,是否显示当前元素。',
      tooltip: '当元素内容为空时,是否显示当前元素。注:数值类型元素包括数字0(非文本)。',
      required: false,
      options: [
        { value: 'show', text: '显示' },
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -201,7 +201,7 @@
  }
  let closetab = []
  if (!appType) {
  if (!appType && viewType !== 'popview') {
    closetab = [{
      value: 'closetab',
      text: '关闭标签'
src/menu/components/table/base-table/index.jsx
@@ -67,6 +67,10 @@
        isNew: true
      }
      if (card.name === '主表') {
        _card.setting.supModule = ['empty']
      }
      this.updateComponent(_card)
    } else {
      let _card = fromJS(card).toJS()
src/menu/datasource/verifycard/customscript/index.jsx
@@ -151,7 +151,9 @@
            loading: false
          })
          MKEmitter.emit('editLineId', values.uuid)
          if (values.uuid) {
            MKEmitter.emit('editLineId', values.uuid)
          }
          this.props.form.setFieldsValue({
            sql: ' '
src/menu/datasource/verifycard/index.jsx
@@ -14,6 +14,7 @@
import SettingForm from './settingform'
import PasteForm from '@/templates/zshare/pasteform'
import SettingUtils from './utils'
import MKEmitter from '@/utils/events.js'
import MinView from '@/assets/img/minview.png'
import './index.scss'
@@ -354,6 +355,7 @@
    } else {
      values.uuid = Utils.getuuid()
      scripts.push(values)
      MKEmitter.emit('editLineId', values.uuid)
    }
    this.setState({ scripts })
src/pc/createview/index.jsx
@@ -5,7 +5,7 @@
import moment from 'moment'
import Utils from '@/utils/utils.js'
import MenuUtils from '@/utils/utils-custom.js'
import MenuUtils, { getTables } from '@/utils/utils-custom.js'
import SettingForm from './settingform'
import Api from '@/api'
import './index.scss'
@@ -56,7 +56,7 @@
      })
      let config = {
        version: 1.0,
        version: 2.0,
        uuid: menuId,
        MenuID: menuId,
        Template: 'webPage',
@@ -170,6 +170,11 @@
            config.tables = _config.tables || []
            config.style = _config.style || {}
            config.statusBarbgColor = _config.statusBarbgColor || ''
            if (config.version !== 2.0) {
              config.components = this.collectTB(config.components)
              config.version = 2.0
            }
          }
  
          param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(config)))
@@ -201,6 +206,36 @@
    })
  }
  collectTB = (components) => {
    return components.map(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          delete tab.floor
          delete tab.hasSearch
          delete tab.parentId
          tab.components = this.collectTB(tab.components)
        })
      } else if (item.type === 'group') {
        item.components = this.collectTB(item.components)
      } else if (!['search', 'navbar', 'login', 'topbar', 'officialAccount'].includes(item.type)) {
        item.$tables = getTables(item)
      }
      if (item.subtype === 'tablecard') { // 兼容
        item.type = 'card'
      }
      delete item.tabId
      delete item.parentId
      delete item.btnlog
      delete item.floor
      delete item.dataName
      return item
    })
  }
  render () {
    const { config } = this.props
    const { visible, loading } = this.state
src/router/index.js
@@ -16,7 +16,6 @@
const AppCheck = asyncLoadComponent(() => import('@/views/appcheck'))
const PCDesign = asyncLoadComponent(() => import('@/views/pcdesign'))
const MobDesign = asyncLoadComponent(() => import('@/views/mobdesign'))
const PopDesign = asyncLoadComponent(() => import('@/views/popdesign'))
const ImDesign = asyncLoadComponent(() => import('@/views/imdesign'))
const MenuDesign = asyncLoadComponent(() => import('@/views/menudesign'))
const BaseDesign = asyncLoadComponent(() => import('@/views/basedesign'))
@@ -42,7 +41,6 @@
  {path: '/menudesign/:param', name: 'menudesign', component: MenuDesign, auth: true},
  {path: '/basedesign/:param', name: 'basedesign', component: BaseDesign, auth: true},
  {path: '/tabledesign/:param', name: 'tabledesign', component: TableDesign, auth: true},
  {path: '/popdesign/:param', name: 'popdesign', component: PopDesign, auth: true},
  {path: '/billprint/:param', name: 'billprint', component: BillPrint, auth: true},
  {path: '/docprint/:menuId', name: 'docprint', component: BillPrint, auth: false},
  {path: '/docprint/:menuId/:id', name: 'docprint', component: BillPrint, auth: false},
src/tabviews/basetable/index.jsx
@@ -16,7 +16,7 @@
const AntvTabs = asyncComponent(() => import('@/tabviews/custom/components/tabs/antv-tabs'))
const MkBaseTable = asyncComponent(() => import('@/tabviews/custom/components/table/base-table'))
const SettingComponent = asyncComponent(() => import('@/tabviews/zshare/settingcomponent'))
const PagemsgComponent = asyncComponent(() => import('@/tabviews/zshare/pageMessage'))
const TableNodes = asyncComponent(() => import('@/tabviews/zshare/tablenodes'))
const DebugTable = asyncComponent(() => import('@/tabviews/debugtable'))
class BasePage extends Component {
@@ -327,18 +327,16 @@
      item.statFields = Array.from(new Set(statFields))
      // 权限过滤
      let tabId = this.props.Tab ? this.props.Tab.uuid : '' // 弹窗标签按钮Id
      if (item.action && item.action.length > 0) {
        item.action = item.action.filter(cell => {
          if (item.hidden === 'true') return false
          if (cell.hidden === 'true') return false
          cell.logLabel = item.$menuname + '-' + cell.label
          cell.ContainerId = this.state.ContainerId
          cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
          cell.$menuId = item.uuid
          cell.$MenuID = this.props.MenuID
          cell.$tabId = tabId
          cell.$view = 'BasePage'
          cell.$view = 'popview'
          cell.$toolbtn = true
          if (cell.syncComponentId === item.setting.supModule) {
@@ -364,8 +362,7 @@
          cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
          cell.$menuId = item.uuid
          cell.$MenuID = this.props.MenuID
          cell.$tabId = tabId
          cell.$view = 'BasePage'
          cell.$view = 'popview'
          if (cell.syncComponentId === item.setting.supModule) {
            cell.syncComponentId = ''
@@ -580,7 +577,7 @@
        {(loadingview || loading) ? <Spin className="view-spin" size="large" /> : null}
        <Row className="component-wrap">{this.getComponents()}</Row>
        {config && window.GLOB.breakpoint ? <DebugTable /> : null}
        {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <PagemsgComponent menu={{MenuName: this.props.MenuName, MenuNo: this.props.MenuNo}} config={config} dict={this.state.dict} /> : null}
        {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <TableNodes config={config} /> : null}
        {!window.GLOB.mkHS && config ? <SettingComponent config={config} dict={this.state.dict} shortcuts={shortcuts || []}/> : null}
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
src/tabviews/calendar/index.jsx
@@ -31,7 +31,6 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    ContainerId: Utils.getuuid(), // 菜单外层html Id
    BID: null,            // 页面跳转时携带ID
    loadingview: true,    // 页面加载中
    viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
@@ -546,7 +545,7 @@
    const { BID, setting, searchlist, loadingview, viewlost, config, loading, data, triggerTime } = this.state
    return (
      <div className="calendar-page" id={this.state.ContainerId}>
      <div className="calendar-page">
        {loadingview && <Spin size="large" />}
        {searchlist && searchlist.length > 0 ?
          <MainSearch BID={BID} searchlist={searchlist} setting={setting} refreshdata={this.refreshbysearch}/> : null
src/tabviews/commontable/index.jsx
@@ -166,6 +166,8 @@
            if (tab.supMenu === 'mainTable') {
              tab.supMenu = MenuID
            }
            tab.ContainerId = this.state.ContainerId
            return window.GLOB.mkActions[tab.linkTab]
          })
        })
@@ -176,6 +178,8 @@
            if (tab.supMenu === 'mainTable') {
              tab.supMenu = MenuID
            }
            tab.ContainerId = this.state.ContainerId
            return tab
          })
        })
@@ -228,6 +232,7 @@
      // 标记主页面,用于按钮固定及表单挂载设置
      config.setting.tabType = 'main'
      config.setting.ContainerId = this.state.ContainerId
      // 数据源信息预处理
      config.setting.laypage = config.setting.laypage !== 'false'     // 是否分页,转为boolean 统一格式
@@ -305,6 +310,7 @@
      config.action.forEach(item => {
        item.logLabel = MenuName + '-' + item.label // 用于sPC_TableData_InUpDe记录操作按钮
        item.$menuId = this.props.MenuID
        item.ContainerId = this.state.ContainerId
        if (item.OpenType === 'funcbutton' && item.funcType === 'print' && item.verify) { // 打印机设置
          let _item = window.GLOB.UserCacheMap.get(this.props.MenuID + item.uuid)
@@ -1169,7 +1175,6 @@
                      dict={this.state.dict}
                      MenuID={MenuID}
                      selectedData={selectedData}
                      ContainerId={this.state.ContainerId}
                    />
                  </div>
                  <div className="main-table-box">
@@ -1188,7 +1193,6 @@
                      total={this.state.total}
                      loading={this.state.loading}
                      statFValue={this.state.statFValue}
                      ContainerId={this.state.ContainerId}
                      refreshdata={this.refreshbytable}
                      chgSelectData={this.changeSelectedData}
                    />
@@ -1207,7 +1211,6 @@
                    columns={columns}
                    data={this.state.data}
                    loading={this.state.loading}
                    ContainerId={this.state.ContainerId}
                  />
                </Col>
              )
@@ -1236,7 +1239,6 @@
              dict={this.state.dict}
              MenuID={MenuID}
              selectedData={selectedData}
              ContainerId={this.state.ContainerId}
            />
          </div>
          <div className="main-table-box">
@@ -1255,7 +1257,6 @@
              total={this.state.total}
              loading={this.state.loading}
              statFValue={this.state.statFValue}
              ContainerId={this.state.ContainerId}
              refreshdata={this.refreshbytable}
              chgSelectData={this.changeSelectedData}
            />
@@ -1276,7 +1277,6 @@
                    SupMenuID={MenuID}
                    MenuID={_tab.linkTab}
                    mainSearch={_tab.searchPass === 'true' ? search : null}
                    ContainerId={this.state.ContainerId}
                    BID={this.state.BIDs[_tab.supMenu] || ''}
                    BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
                  />
src/tabviews/custom/components/share/normalTable/index.jsx
@@ -404,7 +404,6 @@
    columns: PropTypes.array,        // 表格列
    lineMarks: PropTypes.array,      // 行标记
    fields: PropTypes.array,         // 组件字段集
    ContainerId: PropTypes.any,      // 标签页外层Id
    data: PropTypes.any,             // 表格数据
    total: PropTypes.any,            // 总数
    loading: PropTypes.bool,         // 表格加载中
src/tabviews/custom/index.jsx
@@ -36,11 +36,11 @@
const NormalTree = asyncComponent(() => import('./components/tree/antd-tree'))
const Balcony = asyncComponent(() => import('./components/card/balcony'))
const SettingComponent = asyncComponent(() => import('@/tabviews/zshare/settingcomponent'))
const PagemsgComponent = asyncComponent(() => import('@/tabviews/zshare/pageMessage'))
const CustomChart = asyncComponent(() => import('./components/chart/custom-chart'))
const TimeLine = asyncComponent(() => import('./components/timeline/normal-timeline'))
const Voucher = asyncComponent(() => import('./components/module/voucher'))
const DebugTable = asyncComponent(() => import('@/tabviews/debugtable'))
const TableNodes = asyncComponent(() => import('@/tabviews/zshare/tablenodes'))
const MkInterfaces = asyncComponent(() => import('@/tabviews/custom/components/interfaces'))
class CustomPage extends Component {
@@ -172,9 +172,15 @@
        })
      }
      let popview = 'CustomPage'
      if (config.version === 2.0) {
        popview = 'popview'
      }
      config.interfaces = this.formatInterSetting(config.interfaces, regs)
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, skip, param, MenuID, config.interfaces)
      config.components = this.filterComponent(config.components, roleId, window.GLOB.mkActions, balMap, skip, param, MenuID, config.interfaces, popview)
      
      // 获取主搜索条件
      let mainSearch = []
@@ -282,7 +288,7 @@
    }
  }
  filterComponent = (components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces) => {
  filterComponent = (components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview) => {
    return components.filter(item => {
      item.$pageId = pageId
      
@@ -368,7 +374,7 @@
        item.subtabs = item.subtabs.map(tab => {
          tab.$pageId = pageId
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces)
          tab.components = this.filterComponent(tab.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview)
          return tab
        })
@@ -381,7 +387,7 @@
          return false
        }
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces)
        item.components = this.filterComponent(item.components, roleId, permAction, balMap, skip, urlparam, pageId, interfaces, popview)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart'].includes(item.type)) {
@@ -422,15 +428,12 @@
        let statFields = []
        let getCols = (cols) => {
          return cols.filter(col => {
            if (item.subtype !== 'editable') {
              if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
                return false
              } else if (col.Hide === 'true') {
                return false
              }
            } else if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
              col.Hide = 'true'
            if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
              return false
            } else if (col.Hide === 'true') {
              return false
            }
            if (col.type === 'number') {
              if (col.sum === 'true' && !statFields.includes(col.field)) {
                statFields.push(col)
@@ -492,18 +495,16 @@
      }
      // 权限过滤
      let tabId = this.props.Tab ? this.props.Tab.uuid : '' // 弹窗标签按钮Id
      if (item.action && item.action.length > 0) {
        item.action = item.action.filter(cell => {
          if (item.hidden === 'true') return false
          if (cell.hidden === 'true') return false
          cell.logLabel = item.$menuname + '-' + cell.label
          cell.ContainerId = this.state.ContainerId
          cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
          cell.$menuId = item.uuid
          cell.$MenuID = this.props.MenuID
          cell.$tabId = tabId
          cell.$view = 'CustomPage'
          cell.$view = popview
          cell.$toolbtn = true
          if (!mutil && cell.syncComponentId === item.setting.supModule) {
@@ -542,8 +543,7 @@
              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
              cell.$menuId = item.uuid
              cell.$MenuID = this.props.MenuID
              cell.$tabId = tabId
              cell.$view = 'CustomPage'
              cell.$view = popview
              if (!mutil && cell.syncComponentId === item.setting.supModule) {
                cell.syncComponentId = ''
@@ -583,8 +583,7 @@
              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
              cell.$menuId = item.uuid
              cell.$MenuID = this.props.MenuID
              cell.$tabId = tabId
              cell.$view = 'CustomPage'
              cell.$view = popview
              if (!mutil && cell.syncComponentId === item.setting.supModule) {
                cell.syncComponentId = ''
@@ -629,8 +628,7 @@
            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
            cell.$menuId = item.uuid
            cell.$MenuID = this.props.MenuID
            cell.$tabId = tabId
            cell.$view = 'CustomPage'
            cell.$view = popview
            if (cell.syncComponentId === item.wrap.supModule) {
              cell.syncComponentId = ''
@@ -665,8 +663,7 @@
            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
            cell.$menuId = item.uuid
            cell.$MenuID = this.props.MenuID
            cell.$tabId = tabId
            cell.$view = 'CustomPage'
            cell.$view = popview
            if (cell.syncComponentId === item.setting.supModule) {
              cell.syncComponentId = ''
@@ -1251,7 +1248,7 @@
        <Row className="component-wrap">{this.getComponents()}</Row>
        {config && config.interfaces.length > 0 ? <MkInterfaces BID={BID} interfaces={config.interfaces}/> : null}
        {config && window.GLOB.breakpoint ? <DebugTable /> : null}
        {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <PagemsgComponent menu={{MenuName: this.props.MenuName, MenuNo: this.props.MenuNo}} config={config} dict={this.state.dict} /> : null}
        {!window.GLOB.mkHS && window.GLOB.systemType !== 'production' ? <TableNodes config={config} /> : null}
        {!window.GLOB.mkHS && config ? <SettingComponent config={config} dict={this.state.dict} shortcuts={shortcuts || []}/> : null}
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
src/tabviews/custom/popview/index.jsx
New file
@@ -0,0 +1,1002 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { notification, Spin, Row, Col } from 'antd'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
import Utils from '@/utils/utils.js'
import { getStructuredParams, getStructDefaultParam } from '@/utils/utils-datamanage.js'
import asyncComponent from '@/utils/asyncComponent'
import NotFount from '@/components/404'
import './index.scss'
// 通用组件
const AntvBarAndLine = asyncComponent(() => import('../components/chart/antv-bar-line'))
const AntvPie = asyncComponent(() => import('../components/chart/antv-pie'))
const AntvTabs = asyncComponent(() => import('../components/tabs/antv-tabs'))
const AntvDashboard = asyncComponent(() => import('../components/chart/antv-dashboard'))
const AntvScatter = asyncComponent(() => import('../components/chart/antv-scatter'))
const DataCard = asyncComponent(() => import('../components/card/data-card'))
const PropCard = asyncComponent(() => import('../components/card/prop-card'))
const SimpleForm = asyncComponent(() => import('../components/form/simple-form'))
const StepForm = asyncComponent(() => import('../components/form/step-form'))
const TabForm = asyncComponent(() => import('../components/form/tab-form'))
const CarouselDataCard = asyncComponent(() => import('../components/carousel/data-card'))
const CarouselPropCard = asyncComponent(() => import('../components/carousel/prop-card'))
const TableCard = asyncComponent(() => import('../components/card/table-card'))
const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch'))
const NormalTable = asyncComponent(() => import('../components/table/normal-table'))
const BaseTable = asyncComponent(() => import('../components/table/base-table'))
const EditTable = asyncComponent(() => import('../components/table/edit-table'))
const NormalGroup = asyncComponent(() => import('../components/group/normal-group'))
const BraftEditor = asyncComponent(() => import('../components/editor/braft-editor'))
const SandBox = asyncComponent(() => import('../components/code/sand-box'))
const NormalTree = asyncComponent(() => import('../components/tree/antd-tree'))
const Balcony = asyncComponent(() => import('../components/card/balcony'))
const CustomChart = asyncComponent(() => import('../components/chart/custom-chart'))
const TimeLine = asyncComponent(() => import('../components/timeline/normal-timeline'))
const Voucher = asyncComponent(() => import('../components/module/voucher'))
class CustomPage extends Component {
  static propTpyes = {
    param: PropTypes.any,        // 其他页面传递的参数
    Tab: PropTypes.string,       // 弹窗标签
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    BID: '',              // 页面跳转时携带ID
    viewlost: false,      // 页面丢失:1、未获取到配置-页面丢失;2、页面未启用
    lostmsg: '',          // 页面丢失时的提示信息
    config: null,         // 页面配置信息,包括组件等
    mainSearch: null,     // 主搜索
    data: null,           // 列表数据集
    loading: false,       // 列表数据加载中
  }
  /**
   * @description 获取页面配置信息
   */
  async loadconfig () {
    const { Tab } = this.props
    let config = Tab.config || ''
    if (config) {
      try { // 配置信息解析
        config = JSON.stringify(config)
        config = config.replace(/@mywebsite@\//ig, window.GLOB.baseurl)
        config = JSON.parse(config)
      } catch (e) {
        console.warn('Parse Failure')
        config = ''
      }
    }
    // 页面配置解析错误时提示
    if (!config) {
      this.setState({
        viewlost: true
      })
      return
    }
    // 页面未启用时,显示未启用页面
    if (!config.enabled) {
      this.setState({
        viewlost: true,
        lostmsg: this.state.dict['main.view.unenabled']
      })
      return
    }
    // 数据缓存设置
    if (config.cacheUseful === 'true') {
      if (!['day', 'hour'].includes(config.timeUnit)) {
        config.timeUnit = 'day'
      }
      config.cacheTime = config.cacheTime || 1
    }
    // 权限过滤
    let roleId = sessionStorage.getItem('role_id') || '' // 角色ID
    let balMap = new Map()
    let param = this.props.param || {} // url参数
    window.GLOB.CacheData.set(Tab.uuid, param)
    let userName = sessionStorage.getItem('User_Name') || ''
    let fullName = sessionStorage.getItem('Full_Name') || ''
    if (sessionStorage.getItem('isEditState') === 'true') {
      userName = sessionStorage.getItem('CloudUserName') || ''
      fullName = sessionStorage.getItem('CloudFullName') || ''
    }
    let regs = [
      { reg: /@userName@/ig, value: `'${userName}'` },
      { reg: /@fullName@/ig, value: `'${fullName}'` }
    ]
    if (window.GLOB.externalDatabase !== null) {
      regs.push({
        reg: /@db@/ig,
        value: window.GLOB.externalDatabase
      })
    }
    config.components = this.filterComponent(config.components, roleId, balMap, param, Tab)
    // 获取主搜索条件
    let mainSearch = []
    config.components.forEach(component => {
      if (component.type !== 'search') return
      component.search = component.search.map(item => {
        item.oriInitval = item.initval
        if (['text', 'select', 'link'].includes(item.type) && param.$searchkey === item.field) {
          item.initval = param.$searchval
        }
        return item
      })
      mainSearch = Utils.initMainSearch(component.search)
    })
    let params = []
    let BID = param.$BID || ''
    let inherit = {}
    if (config.cacheUseful === 'true') { // 缓存继承
      inherit.cacheUseful = config.cacheUseful
      inherit.timeUnit = config.timeUnit
      inherit.cacheTime = config.cacheTime
    }
    config.components = this.formatSetting(config.components, params, mainSearch, inherit, regs, balMap)
    if ([...balMap.keys()].length > 0) {
      config.components = this.filterBalcony(config.components, balMap)
    }
    this.setState({
      BID: BID,
      config,
      mainSearch
    }, () => {
      if (params.length > 0) {
        this.loadmaindata(params)
      }
    })
  }
  filterComponent = (components, roleId, balMap, urlparam, Tab) => {
    return components.filter(item => {
      item.$pageId = Tab.uuid
      if (item.style && item.style.boxShadow) {
        delete item.style.hShadow
        delete item.style.vShadow
        delete item.style.shadowBlur
        delete item.style.shadowColor
      }
      item.$menuname = (Tab.label || '') + '-' + (item.name || '')
      if (item.type === 'tabs') {
        if (
          item.setting.blacklist && item.setting.blacklist.length > 0 &&
          item.setting.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
        ) {
          return false
        }
        item.subtabs = item.subtabs.filter(tab => {
          if (
            tab.blacklist && tab.blacklist.length > 0 &&
            tab.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
          ) {
            return false
          } else if (tab.hide === 'true') {
            return false
          }
          return true
        })
        if (item.setting.supModule) {
          let pid = item.setting.supModule.pop()
          item.setting.supModule = pid || ''
          if (item.setting.supModule) {
            item.setting.controlField = item.setting.controlField.toLowerCase()
            if (item.setting.supModule === 'preview') {
              item.setting.supModule = ''
              let val = ''
              Object.keys(urlparam).forEach(key => {
                if (key.toLowerCase() === item.setting.controlField) {
                  val = urlparam[key]
                }
              })
              item.subtabs = item.subtabs.filter(tab => {
                if (tab.controlVal === val) {
                  return false
                } else if (/,/ig.test(tab.controlVal)) {
                  return !tab.controlVal.split(',').includes(val)
                }
                return true
              })
            }
          }
        }
        if (item.setting.selectField) {
          item.setting.selectField = item.setting.selectField.toLowerCase()
          let val = ''
          Object.keys(urlparam).forEach(key => {
            if (key.toLowerCase() === item.setting.selectField) {
              val = urlparam[key]
            }
          })
          let activeKey = ''
          item.subtabs.forEach(tab => {
            if (!activeKey && tab.selectVal === val) {
              activeKey = tab.uuid
            }
          })
          item.activeKey = activeKey
        }
        item.subtabs = item.subtabs.map(tab => {
          tab.$pageId = Tab.uuid
          tab.components = this.filterComponent(tab.components, roleId, balMap, urlparam, Tab)
          return tab
        })
        return true
      } else if (item.type === 'group') {
        if (
          item.setting.blacklist && item.setting.blacklist.length > 0 &&
          item.setting.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
        ) {
          return false
        }
        item.components = this.filterComponent(item.components, roleId, balMap, urlparam, Tab)
        return true
      } else if (['pie', 'bar', 'line', 'dashboard', 'scatter', 'chart'].includes(item.type)) {
        if (
          item.plot.blacklist && item.plot.blacklist.length > 0 &&
          item.plot.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
        ) {
          return false
        }
      } else if (item.wrap) {
        if (
          item.wrap.blacklist && item.wrap.blacklist.length > 0 &&
          item.wrap.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
        ) {
          return false
        }
      }
      // 搜索条件初始化
      if (item.search && item.search.length > 0) {
        item.search = Utils.initSearchVal(item.search)
      }
      if (item.type === 'table') {
        let statFields = []
        let getCols = (cols) => {
          return cols.filter(col => {
            if (col.blacklist && col.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
              return false
            } else if (col.Hide === 'true') {
              return false
            }
            if (col.type === 'number') {
              if (col.sum === 'true' && !statFields.includes(col.field)) {
                statFields.push(col)
              }
              if (typeof(col.decimal) === 'number') {
                col.round = Math.pow(10, col.decimal)
                if (col.format === 'percent') {
                  col.decimal = col.decimal > 2 ? col.decimal - 2 : 0
                }
              }
            } else if (col.type === 'colspan') {
              col.subcols = getCols(col.subcols || [])
              if (col.subcols.length === 0) {
                return false
              }
            } else if (col.type === 'custom') {
              col.elements = col.elements.map(cell => {
                if (['text', 'number', 'formula'].includes(cell.eleType)) {
                  if (!cell.height) {
                    cell.innerHeight = 'auto'
                  }
                  if (cell.eleType === 'number' && typeof(cell.decimal) === 'number') {
                    cell.round = Math.pow(10, cell.decimal)
                    if (cell.format === 'percent') {
                      cell.decimal = cell.decimal > 2 ? cell.decimal - 2 : 0
                    }
                  }
                }
                return cell
              })
            }
            if (col.linkmenu && col.linkmenu.length > 0) {
              let menu_id = col.linkmenu.pop()
              col.linkThdMenu = window.GLOB.mkThdMenus.filter(m => m.MenuID === menu_id)[0] || ''
            } else {
              col.linkThdMenu = ''
            }
            return true
          })
        }
        item.cols = getCols(item.cols)
        item.statFields = statFields
      }
      let mutil = false
      if (item.wrap && item.wrap.supType === 'multi') { // 数据卡多上级组件
        mutil = true
        item.setting.supModule = item.supNodes[0].componentId
      } else if (item.setting && item.setting.supModule) {
        let pid = item.setting.supModule.pop()
        if (pid && pid !== 'empty') {
          item.setting.supModule = pid
        } else {
          item.setting.supModule = ''
        }
      }
      // 权限过滤
      if (item.action && item.action.length > 0) {
        item.action = item.action.filter(cell => {
          if (cell.hidden === 'true' || ['popview', 'funcbutton'].includes(cell.OpenType)) return false
          cell.logLabel = item.$menuname + '-' + cell.label
          cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
          cell.$menuId = item.uuid
          cell.$tabId = Tab.uuid
          cell.$toolbtn = true
          if (!mutil && cell.syncComponentId === item.setting.supModule) {
            cell.syncComponentId = ''
          }
          if (cell.btnstyle) { // 兼容
            cell.style = cell.style || {}
            cell.style = {...cell.style, ...cell.btnstyle}
          }
          return true
        })
      }
      if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
        item.subcards && item.subcards.forEach(card => {
          if (card.style.boxShadow) {
            delete card.style.hShadow
            delete card.style.vShadow
            delete card.style.shadowBlur
            delete card.style.shadowColor
          }
          card.elements = card.elements.filter(cell => {
            if (cell.eleType === 'button') {
              if (cell.hidden === 'true' || ['popview', 'funcbutton'].includes(cell.OpenType)) return false
              cell.logLabel = item.$menuname + '-' + cell.label
              cell.Ot = cell.Ot || 'requiredSgl'
              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
              cell.$menuId = item.uuid
              cell.$tabId = Tab.uuid
              if (!mutil && cell.syncComponentId === item.setting.supModule) {
                cell.syncComponentId = ''
              }
              if (card.btnstyle) { // 兼容
                card.style = card.style || {}
                card.style = {...card.style, ...card.btnstyle}
              }
            } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
              if (!cell.height) {
                cell.innerHeight = 'auto'
              }
              if (cell.eleType === 'number' && typeof(cell.decimal) === 'number') {
                cell.round = Math.pow(10, cell.decimal)
                if (cell.format === 'percent') {
                  cell.decimal = cell.decimal > 2 ? cell.decimal - 2 : 0
                }
              }
            }
            return true
          })
          if (!card.backElements || card.backElements.length === 0) return
          card.backElements = card.backElements.filter(cell => {
            if (cell.eleType === 'button') {
              if (cell.hidden === 'true' || ['popview', 'funcbutton'].includes(cell.OpenType)) return false
              cell.logLabel = item.$menuname + '-' + cell.label
              cell.Ot = cell.Ot || 'requiredSgl'
              cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
              cell.$menuId = item.uuid
              cell.$tabId = Tab.uuid
              if (!mutil && cell.syncComponentId === item.setting.supModule) {
                cell.syncComponentId = ''
              }
              if (card.btnstyle) { // 兼容
                card.style = card.style || {}
                card.style = {...card.style, ...card.btnstyle}
              }
            } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
              if (!cell.height) {
                cell.innerHeight = 'auto'
              }
              if (cell.eleType === 'number' && typeof(cell.decimal) === 'number') {
                cell.round = Math.pow(10, cell.decimal)
                if (cell.format === 'percent') {
                  cell.decimal = cell.decimal > 2 ? cell.decimal - 2 : 0
                }
              }
            }
            return true
          })
        })
      } else if (item.type === 'balcony') {
        if (item.wrap.linkType === 'sync') {
          item.wrap.syncModuleId = item.wrap.syncModule.pop()
          balMap.set(item.wrap.syncModuleId, true)
        } else if (item.wrap.linkType === 'sup') {
          item.wrap.supModule = item.wrap.supModule.pop()
          item.setting.supModule = item.wrap.supModule
        }
        item.elements = item.elements.filter(cell => {
          if (cell.eleType === 'button') {
            if (cell.hidden === 'true' || ['popview', 'funcbutton'].includes(cell.OpenType)) return false
            cell.logLabel = item.$menuname + '-' + cell.label
            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
            cell.$menuId = item.uuid
            cell.$tabId = Tab.uuid
            if (cell.syncComponentId === item.wrap.supModule) {
              cell.syncComponentId = ''
            }
          } else if (['text', 'number', 'formula'].includes(cell.eleType)) {
            if (!cell.height) {
              cell.innerHeight = 'auto'
            }
            if (cell.eleType === 'number' && typeof(cell.decimal) === 'number') {
              cell.round = Math.pow(10, cell.decimal)
              if (cell.format === 'percent') {
                cell.decimal = cell.decimal > 2 ? cell.decimal - 2 : 0
              }
            }
          }
          return true
        })
      } else if (item.type === 'table') {
        item.cols = item.cols.filter(col => {
          if (col.type !== 'action') return true
          col.elements = col.elements.filter(cell => {
            if (cell.hidden === 'true' || ['popview', 'funcbutton'].includes(cell.OpenType)) return false
            cell.logLabel = item.$menuname + '-' + cell.label
            cell.Ot = cell.Ot || 'requiredSgl'
            cell.syncComponentId = cell.syncComponent ? (cell.syncComponent.pop() || '') : ''
            cell.$menuId = item.uuid
            cell.$tabId = Tab.uuid
            if (cell.syncComponentId === item.setting.supModule) {
              cell.syncComponentId = ''
            }
            if (cell.btnstyle) { // 兼容
              cell.style = cell.style || {}
              cell.style = {...cell.style, ...cell.btnstyle}
            }
            return true
          })
          return col.elements.length !== 0
        })
        if (item.subtype === 'editable') {
          item.submit.logLabel = item.$menuname + '-提交'
          item.submit.$menuId = item.uuid
        }
      } else if (item.type === 'form') {
        item.subcards = item.subcards.map(group => {
          group.subButton.uuid = group.uuid
          group.subButton.$menuId = group.uuid
          group.subButton.OpenType = 'formSubmit'
          group.subButton.execError = 'never'
          group.subButton.logLabel = item.$menuname + '-' + group.subButton.label
          if (!group.subButton.Ot) {
            group.subButton.Ot = item.wrap.datatype === 'static' ? 'notRequired' : 'requiredSgl'
          }
          group.subButton.syncComponentId = group.subButton.syncComponent ? group.subButton.syncComponent.pop() : ''
          if (group.subButton.syncComponentId === item.setting.supModule) {
            group.subButton.syncComponentId = ''
          }
          group.fields = group.fields.map(cell => {
            // 数据源sql语句,预处理,权限黑名单字段设置为隐藏表单
            if (['select', 'link', 'multiselect', 'radio', 'checkbox', 'checkcard'].includes(cell.type) && cell.resourceType === '1') {
              let _option = Utils.getSelectQueryOptions(cell)
              cell.data_sql = Utils.formatOptions(_option.sql)
              cell.base_sql = window.btoa(window.encodeURIComponent(_option.sql))
              cell.arr_field = _option.field
            }
            // 字段权限黑名单
            if (!cell.blacklist || !roleId || cell.blacklist.length === 0) return cell
            if (cell.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0) {
              cell.hidden = 'true'
            }
            return cell
          })
          return group
        })
      }
      return true
    })
  }
  filterBalcony = (components, balMap) => {
    return components.filter(item => {
      if (item.type === 'tabs') {
        item.subtabs = item.subtabs.map(tab => {
          tab.components = this.filterBalcony(tab.components, balMap)
          return tab
        })
      } else if (item.type === 'group') {
        item.components = this.filterBalcony(item.components, balMap)
      }
      if (item.type === 'balcony' && item.wrap.linkType === 'sync') {
        let conf = balMap.get(item.wrap.syncModuleId)
        if (!conf || conf === true) {
          return false
        }
        item.syncConfig = {
          uuid: conf.uuid,
          wrap: conf.wrap,
          setting: conf.setting,
          columns: conf.columns
        }
        if (item.wrap.checkAll === 'show') {
          if (conf.subtype === 'datacard' && conf.wrap.cardType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          } else if (conf.subtype === 'normaltable' && conf.wrap.tableType !== 'checkbox') {
            item.wrap.checkAll = 'hidden'
          }
        }
      }
      return true
    })
  }
  getPrinter = (item, parentId) => {
    let _item = window.GLOB.UserCacheMap.get(parentId + item.uuid)
    if (_item) {
      item.printer = _item.printer || ''
      item.verify.defaultPrinter = _item.printer || ''
      if (item.verify.printerTypeList && _item.printerList) {
        item.verify.printerTypeList = item.verify.printerTypeList.map(cell => {
          cell.printer = _item.printerList[cell.Value] || ''
          return cell
        })
      }
    }
    return item
  }
  // 格式化默认设置
  formatSetting = (components, params, mainSearch, inherit, regs, balMap) => {
    let delay = 20
    return components.map(component => {
      if (component.type === 'tabs') {
        component.subtabs = component.subtabs.map(tab => {
          tab.components = this.formatSetting(tab.components, null, null, inherit, regs, balMap)
          tab = {...tab, ...inherit}
          return tab
        })
        return component
      } else if (component.type === 'group') {
        component.components = this.formatSetting(component.components, null, null, inherit, regs, balMap)
        component = {...component, ...inherit}
        return component
      } else if (component.wrap && component.wrap.datatype === 'public') {
        return component
      }
      if (component.setting) {
        component.setting.useMSearch = component.setting.useMSearch === 'true'
        component.setting.syncRefresh = (component.setting.useMSearch && component.setting.syncRefresh === 'true')
      }
      if (component.wrap && component.wrap.datatype === 'static') {
        component.format = ''
        component.setting = component.setting || {}
        component.setting.useMSearch = false
        component.setting.syncRefresh = false
      }
      if (!component.setting || !component.format) return component  // 1、不使用系统函数时;2、 没有动态数据  数据格式 array 或 object
      if (component.setting.interType !== 'system') { // 不使用系统函数时
        component.setting.sync = 'false'
        component.setting.laypage = component.setting.laypage === 'true'
        return component
      }
      let _customScript = ''
      component.scripts && component.scripts.forEach(script => {
        if (script.status !== 'false') {
          _customScript += `
          ${script.sql}
          `
        }
      })
      delete component.scripts
      component.setting.$name = component.$menuname || ''
      component.setting.execute = component.setting.execute !== 'false'  // 默认sql是否执行,转为boolean 统一格式
      component.setting.laypage = component.setting.laypage === 'true'   // 是否分页,转为boolean 统一格式
      if (!component.setting.execute) {
        component.setting.dataresource = ''
      }
      if (/\s/.test(component.setting.dataresource)) {
        component.setting.dataresource = '(' + component.setting.dataresource + ') tb'
      }
      if (sessionStorage.getItem('dataM') === 'true') { // 数据权限
        component.setting.dataresource = component.setting.dataresource.replace(/\$@/ig, '/*').replace(/@datam@/ig, '\'Y\'')
        component.setting.dataresource = component.setting.dataresource.replace(/@\$/ig, '*/')
        _customScript = _customScript.replace(/\$@/ig, '/*').replace(/@datam@/ig, '\'Y\'')
        _customScript = _customScript.replace(/@\$/ig, '*/')
      } else {
        component.setting.dataresource = component.setting.dataresource.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
        _customScript = _customScript.replace(/@\$|\$@/ig, '').replace(/@datam@/ig, '\'\'')
      }
      regs.forEach(cell => {
        component.setting.dataresource = component.setting.dataresource.replace(cell.reg, cell.value)
        _customScript = _customScript.replace(cell.reg, cell.value)
      })
      component.setting.customScript = _customScript // 整理后自定义脚本
      // dataName 系统生成的数据源名称
      if (component.setting.sync === 'true') {
        component.dataName = Utils.getdataName()
      }
      // floor    组件的层级
      // pageable 是否分页,组件属性,不分页的组件才可以统一查询
      if (params && (!component.pageable || (component.pageable && !component.setting.laypage)) && component.setting.onload === 'true' && component.setting.sync === 'true') {
        let searchlist = []
        if (component.search && component.search.length > 0) {
          searchlist = Utils.initMainSearch(component.search)
        }
        if (component.setting.useMSearch) {
          let keys = searchlist.map(item => item.key)
          mainSearch.forEach(item => {
            if (!keys.includes(item.key)) {
              searchlist.push(item)
            }
          })
        }
        if (searchlist.filter(item => item.required && item.value === '').length > 0) {
          component.setting.sync = 'false'
          component.setting.onload = 'false'
        } else {
          params.push(getStructDefaultParam(component, searchlist, params.length === 0))
        }
      } else if (params) {
        component.setting.sync = 'false'
        component.setting.delay = delay
        delay += 20
      }
      if (balMap.has(component.uuid)) {
        component.setting.$hasSyncModule = true
        balMap.set(component.uuid, component)
      }
      return component
    })
  }
  /**
   * @description 主表数据加载
   */
  loadmaindata = (params) => {
    let param = getStructuredParams(params, this.state.config, this.state.BID || '')
    this.setState({loading: true})
    Api.genericInterface(param).then(result => {
      if (result.status) {
        delete result.status
        delete result.message
        delete result.ErrMesg
        delete result.ErrCode
        this.setState({
          data: result,
          loading: false
        })
      } else {
        this.setState({
          data: '',
          loading: false
        })
        notification.error({
          top: 92,
          message: result.message,
          duration: 10
        })
      }
    })
  }
  UNSAFE_componentWillMount () {
    // 组件加载时,获取菜单数据
    this.loadconfig()
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    window.GLOB.CacheData.delete(this.props.Tab.uuid)
    if (this.state.config) {
      this.deleteCache(this.state.config.components)
    }
  }
  deleteCache = (components) => {
    components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          this.deleteCache(tab.components)
        })
      } else if (item.type === 'group') {
        this.deleteCache(item.components)
      } else {
        window.GLOB.CacheData.delete(item.uuid)
      }
    })
  }
  resetSearch = (search) => {
    this.setState({mainSearch: null}, () => {
      this.setState({mainSearch: search})
    })
  }
  getComponents = () => {
    const { config, BID, data, mainSearch } = this.state
    if (!config) return
    return config.components.map(item => {
      if (item.type === 'card' && item.subtype === 'datacard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <DataCard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'card' && item.subtype === 'propcard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <PropCard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'table' && item.subtype === 'basetable') {
        return (
          <Col span={item.width} key={item.uuid}>
            <BaseTable config={item}/>
          </Col>
        )
      } else if (item.type === 'bar' || item.type === 'line') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvBarAndLine config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'pie') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvPie config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'scatter') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvScatter config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'dashboard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvDashboard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'form' && item.subtype === 'simpleform') {
        return (
          <Col span={item.width} key={item.uuid}>
            <SimpleForm config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'form' && item.subtype === 'stepform') {
        return (
          <Col span={item.width} key={item.uuid}>
            <StepForm config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'form' && item.subtype === 'tabform') {
        return (
          <Col span={item.width} key={item.uuid}>
            <TabForm config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'search') {
        return (
          <Col span={item.width} key={item.uuid}>
            <MainSearch config={item} BID={BID} refreshdata={this.resetSearch} />
          </Col>
        )
      } else if (item.type === 'tabs') {
        return (
          <Col span={item.width} key={item.uuid}>
            <AntvTabs config={item} mainSearch={mainSearch} />
          </Col>
        )
      } else if (item.type === 'balcony') {
        return (
          <Col span={item.width} key={item.uuid}>
            <Balcony config={item} data={data}/>
          </Col>
        )
      } else if (item.type === 'timeline') {
        return (
          <Col span={item.width} key={item.uuid}>
            <TimeLine config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'carousel' && item.subtype === 'datacard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <CarouselDataCard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'carousel' && item.subtype === 'propcard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <CarouselPropCard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'card' && item.subtype === 'tablecard') {
        return (
          <Col span={item.width} key={item.uuid}>
            <TableCard config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'table' && item.subtype === 'normaltable') {
        return (
          <Col span={item.width} key={item.uuid}>
            <NormalTable config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'table' && item.subtype === 'editable') {
        return (
          <Col span={item.width} key={item.uuid}>
            <EditTable config={item} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'group' && item.subtype === 'normalgroup') {
        return (
          <Col span={item.width} key={item.uuid}>
            <NormalGroup config={item} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'editor') {
        return (
          <Col span={item.width} key={item.uuid}>
            <BraftEditor config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'tree') {
        return (
          <Col span={item.width} key={item.uuid}>
            <NormalTree config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'code') {
        return (
          <Col span={item.width} key={item.uuid}>
            <SandBox config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'chart') {
        return (
          <Col span={item.width} key={item.uuid}>
            <CustomChart config={item} data={data} mainSearch={mainSearch}/>
          </Col>
        )
      } else if (item.type === 'module' && item.subtype === 'voucher') {
        return (
          <Col span={item.width} key={item.uuid}>
            <Voucher config={item}/>
          </Col>
        )
      } else {
        return null
      }
    })
  }
  render() {
    const { viewlost, config, loading } = this.state
    return (
      <div className={'pop-page-wrap ' + (loading ? 'loading' : '')} style={config.style}>
        {loading ? <Spin className="view-spin" size="large" /> : null}
        <Row className="component-wrap">{this.getComponents()}</Row>
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
      </div>
    )
  }
}
export default CustomPage
src/tabviews/custom/popview/index.scss
New file
@@ -0,0 +1,60 @@
.pop-page-wrap {
  position: relative;
  min-height: calc(100vh - 94px);
  height: 100%;
  padding-top: 16px;
  padding-bottom: 80px;
  padding-left: 16px;
  padding-right: 16px;
  background-size: 100%;
  .component-wrap >.ant-col {
    min-height: 0;
  }
  .box404 {
    padding-top: 30px;
  }
  .ant-modal-mask {
    position: absolute;
  }
  .ant-modal-wrap {
    position: absolute;
  }
  .action-modal .ant-modal {
    top: 40px;
    max-width: 95%;
    .ant-modal-body {
      max-height: calc(100vh - 265px);
    }
  }
  > .ant-spin {
    position: absolute;
    z-index: 10;
    left: calc(50% - 16px);
    top: calc(50vh - 70px);
  }
  .common-table-copy {
    position: fixed;
    z-index: 2;
    bottom: 65px;
    right: 30px;
    width: 40px;
    height: 40px;
  }
  .ant-btn-link:hover {
    opacity: 0.8;
  }
  .button-list.toolbar-button {
    button {
      height: auto;
      min-height: 28px;
    }
  }
}
.pop-page-wrap.loading {
  .ant-spin-spinning:not(.view-spin) {
    display: none;
  }
}
src/tabviews/formtab/index.jsx
@@ -109,6 +109,7 @@
            if (tab.supMenu === 'mainTable') {
              tab.supMenu = MenuID
            }
            tab.ContainerId = this.state.ContainerId
            return window.GLOB.mkActions[tab.linkTab]
          })
        })
@@ -118,6 +119,7 @@
            if (tab.supMenu === 'mainTable') {
              tab.supMenu = MenuID
            }
            tab.ContainerId = this.state.ContainerId
            return true
          })
        })
@@ -654,7 +656,6 @@
                        Tab={_tab}
                        MenuID={_tab.linkTab}
                        SupMenuID={this.props.MenuID}
                        ContainerId={this.state.ContainerId}
                        BID={this.state.BIDs[_tab.supMenu] || ''}
                        BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
                      />
src/tabviews/subtable/index.jsx
@@ -33,7 +33,6 @@
    MenuID: PropTypes.string,        // 菜单Id
    SupMenuID: PropTypes.string,     // 上级菜单Id
    mainSearch: PropTypes.any,       // 主表搜索条件
    ContainerId: PropTypes.any,      // 三级菜单Container(html) ID
  }
  state = {
@@ -99,6 +98,7 @@
        config.setting.$name = Tab.label
        config.setting.foreignKey = Tab.foreignKey || ''
        config.setting.supModule = Tab.supMenu || ''
        config.setting.ContainerId = Tab.ContainerId || ''
      } catch (e) {
        console.warn('Parse Failure')
        config = ''
@@ -407,7 +407,7 @@
        statFValue: [],
        total: 0
      })
      MKEmitter.emit('changeTableLine', this.props.ContainerId, this.props.Tab.uuid, '', '')
      MKEmitter.emit('changeTableLine', this.props.Tab.ContainerId, this.props.Tab.uuid, '', '')
      return
    } else if (window.GLOB.systemType === 'production' && setting.interType === 'custom' && !setting.proInterface) {
      notification.warning({
@@ -421,7 +421,7 @@
    this.setState({
      selectedData: []
    })
    MKEmitter.emit('changeTableLine', this.props.ContainerId, this.props.Tab.uuid, '', '')
    MKEmitter.emit('changeTableLine', this.props.Tab.ContainerId, this.props.Tab.uuid, '', '')
    if (setting.interType === 'custom' && loadCustomApi) {
      if (setting.execTime === 'once') {
@@ -1025,7 +1025,6 @@
                      columns={columns}
                      MenuID={this.props.MenuID}
                      selectedData={selectedData}
                      ContainerId={this.props.ContainerId}
                    />
                  </div>
                  <div className="subtable-box">
@@ -1045,7 +1044,6 @@
                      MenuID={this.props.MenuID}
                      loading={this.state.loading}
                      statFValue={this.state.statFValue}
                      ContainerId={this.props.ContainerId}
                      refreshdata={this.refreshbytable}
                      chgSelectData={this.changeSelectedData}
                    />
@@ -1065,7 +1063,6 @@
                    MenuID={this.props.MenuID}
                    loading={this.state.loading}
                    tableId={this.props.Tab.uuid}
                    ContainerId={this.props.ContainerId}
                  />
                </Col>
              )
@@ -1094,7 +1091,6 @@
              columns={columns}
              MenuID={this.props.MenuID}
              selectedData={selectedData}
              ContainerId={this.props.ContainerId}
            />
          </div>
          <div className="subtable-box">
@@ -1114,7 +1110,6 @@
              MenuID={this.props.MenuID}
              loading={this.state.loading}
              statFValue={this.state.statFValue}
              ContainerId={this.props.ContainerId}
              refreshdata={this.refreshbytable}
              chgSelectData={this.changeSelectedData}
            />
src/tabviews/treepage/index.jsx
@@ -122,6 +122,8 @@
          if (tab.supMenu === 'mainTable') {
            tab.supMenu = MenuID
          }
          tab.ContainerId = this.state.ContainerId
          return window.GLOB.mkActions[tab.linkTab]}
        )
      })
@@ -619,7 +621,6 @@
                          MenuID={_tab.linkTab}
                          mainSearch={null}
                          SupMenuID={this.props.MenuID}
                          ContainerId={this.state.ContainerId}
                          BID={this.state.BIDs[_tab.supMenu] || ''}
                          BData={this.state.BIDs[_tab.supMenu + 'data'] || ''}
                        /> : null}
src/tabviews/zshare/actionList/index.jsx
@@ -27,7 +27,6 @@
    actions: PropTypes.array,         // 按钮组
    columns: PropTypes.array,         // 显示列
    setting: PropTypes.any,           // 页面通用设置
    ContainerId: PropTypes.any        // tab页面ID,用于弹窗控制
  }
  state = {}
@@ -37,7 +36,7 @@
  }
  getButtonList = (actions) => {
    const { BID, BData, MenuID, columns, setting, ContainerId, selectedData, lock } = this.props
    const { BID, BData, MenuID, columns, setting, selectedData, lock } = this.props
    return actions.map(item => {
      if (['exec', 'prompt', 'pop'].includes(item.OpenType)) {
        return (
@@ -50,7 +49,6 @@
            BData={BData}
            setting={setting}
            columns={columns}
            ContainerId={ContainerId}
            selectedData={selectedData}
          />
        )
@@ -141,7 +139,6 @@
              btn={item}
              BData={BData}
              setting={setting}
              ContainerId={ContainerId}
              selectedData={selectedData}
            />
          )
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -27,7 +27,6 @@
    btn: PropTypes.object,            // 按钮
    columns: PropTypes.any,           // 字段列
    setting: PropTypes.any,           // 页面通用设置
    ContainerId: PropTypes.any,       // tab页面ID,用于弹窗控制
    disabled: PropTypes.any,          // 行按钮禁用
  }
@@ -2534,7 +2533,7 @@
   * @description 显示模态框
   */
  getModels = () => {
    const { setting, BID, btn, BData } = this.props
    const { BID, btn, BData } = this.props
    const { btnconfig, visible } = this.state
    if (!btnconfig || !btnconfig.setting) return null
@@ -2583,12 +2582,9 @@
    } else {
      let container = document.body
      if (
        (setting.tabType === 'main' && btnconfig.setting.container === 'tab' && this.props.ContainerId) ||
        (btnconfig.setting.container === 'tab' && btn.ContainerId)
      ) {
      if (btnconfig.setting.container === 'tab' && btn.ContainerId) {
        width = btnconfig.setting.width > 100 ? btnconfig.setting.width : btnconfig.setting.width + '%'
        container = () => document.getElementById(this.props.ContainerId || btn.ContainerId)
        container = () => document.getElementById(btn.ContainerId)
      }
      return (
        <Modal
src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -12,6 +12,7 @@
const SubTabTable = asyncSpinComponent(() => import('@/tabviews/subtabtable'))
const CustomPage = asyncSpinComponent(() => import('@/tabviews/custom'))
const PopView = asyncSpinComponent(() => import('@/tabviews/custom/popview'))
class PopupButton extends Component {
  static propTpyes = {
@@ -244,7 +245,7 @@
        ratio = ratio + 'vw'
      }
      return <Modal
        className={'popview-modal ' + (btn.$view === 'CustomPage' ? 'custom-popview' : '')}
        wrapClassName={'popview-modal ' + (!btn.$view ? '' : 'custom-popview')}
        title={btn.label}
        width={ratio}
        maskClosable={btn.clickouter === 'close'}
@@ -255,14 +256,9 @@
        ]}
        destroyOnClose
      >
        {btn.$view !== 'CustomPage' ? <SubTabTable
          Tab={btn}
          MenuID={btn.linkTab}
          SupMenuID={this.props.MenuID}
          BID={popData ? primaryId : this.props.BID}
          BData={popData || this.props.BData}
        /> : null}
        {!btn.$view ? <SubTabTable Tab={btn} MenuID={btn.linkTab} SupMenuID={this.props.MenuID} BID={popData ? primaryId : this.props.BID} BData={popData || this.props.BData}/> : null}
        {btn.$view === 'CustomPage' ? <CustomPage Tab={btn} MenuID={btn.uuid} MenuName={btn.label} param={{$BID: (popData ? primaryId : this.props.BID), ...(popData || this.props.BData || {})}} /> : null}
        {btn.$view === 'popview' ? <PopView Tab={btn} param={{$BID: (popData ? primaryId : this.props.BID), ...(popData || this.props.BData || {})}} /> : null}
      </Modal>
    } else {
      let height = '100vh'
@@ -288,7 +284,7 @@
      return (
        <Drawer
          title={btn.label}
          className={btn.$view === 'CustomPage' ? 'custom-drawer-popview' : 'table-drawer-popview'}
          className={!btn.$view ? 'table-drawer-popview' : 'custom-drawer-popview' }
          width={width}
          height={height}
          maskClosable={btn.clickouter === 'close'}
@@ -297,14 +293,9 @@
          placement={btn.placement || 'right'}
          destroyOnClose
        >
          {btn.$view !== 'CustomPage' ? <SubTabTable
            Tab={btn}
            MenuID={btn.linkTab}
            SupMenuID={this.props.MenuID}
            BID={popData ? primaryId : this.props.BID}
            BData={popData || this.props.BData}
          /> : null}
          {!btn.$view ? <SubTabTable Tab={btn} MenuID={btn.linkTab} SupMenuID={this.props.MenuID} BID={popData ? primaryId : this.props.BID} BData={popData || this.props.BData}/> : null}
          {btn.$view === 'CustomPage' ? <CustomPage Tab={btn} MenuName={btn.label} MenuID={btn.uuid} param={{$BID: (popData ? primaryId : this.props.BID), ...(popData || this.props.BData || {})}} /> : null}
          {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}>
              关闭
src/tabviews/zshare/actionList/popupbutton/index.scss
@@ -4,6 +4,9 @@
    .custom-page-wrap {
      min-height: 200px;
    }
    .pop-page-wrap {
      min-height: 200px;
    }
  }
}
.table-drawer-popview {
@@ -43,6 +46,9 @@
      .custom-page-wrap {
        min-height: calc(100vh - 110px);
      }
      .pop-page-wrap {
        min-height: calc(100vh - 110px);
      }
    }
  }
}
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -27,7 +27,6 @@
    MenuID: PropTypes.string,         // 菜单ID
    btn: PropTypes.object,            // 按钮
    setting: PropTypes.any,           // 页面通用设置
    ContainerId: PropTypes.any,       // tab页面ID,用于弹窗控制
    disabled: PropTypes.any,          // 行按钮禁用
  }
@@ -1658,7 +1657,7 @@
   * @description 显示模态框
   */
  getModels = () => {
    const { setting, BID, btn } = this.props
    const { BID, btn } = this.props
    const { btnconfig } = this.state
    if (!this.state.visible || !btnconfig || !btnconfig.setting) return null
@@ -1668,12 +1667,9 @@
    let clickouter = false
    let container = document.body
    if (
      (setting.tabType === 'main' && btnconfig.setting.container === 'tab' && this.props.ContainerId) ||
      (btnconfig.setting.container === 'tab' && btn.ContainerId)
    ) {
    if (btnconfig.setting.container === 'tab' && btn.ContainerId) {
      width = btnconfig.setting.width > 100 ? btnconfig.setting.width : btnconfig.setting.width + '%'
      container = () => document.getElementById(this.props.ContainerId || btn.ContainerId)
      container = () => document.getElementById(btn.ContainerId)
    }
    if (btnconfig.setting.clickouter === 'close') {
src/tabviews/zshare/cardcomponent/index.jsx
@@ -146,7 +146,7 @@
   * @description 获取按钮元素
   */
  getActionList = (actions) => {
    const { BData, setting, columns, ContainerId, data, MenuID } = this.props
    const { BData, setting, columns, data, MenuID } = this.props
    
    return actions.map(item => {
      if (['exec', 'prompt', 'pop'].includes(item.OpenType)) {
@@ -159,7 +159,6 @@
            setting={setting}
            columns={columns}
            selectedData={[data]}
            ContainerId={ContainerId}
          />
        )
      } else if (item.OpenType === 'popview') {
@@ -210,7 +209,6 @@
              BData={BData}
              setting={setting}
              selectedData={[data]}
              ContainerId={ContainerId}
            />
          )
        }
@@ -497,7 +495,6 @@
              setting={this.props.setting}
              columns={this.props.columns}
              selectedData={[]}
              ContainerId={this.props.ContainerId}
            />
          </div>
        </Card> : null}
@@ -513,7 +510,6 @@
    MenuID: PropTypes.string,         // 菜单ID
    config: PropTypes.object,         // 页面配置信息
    columns: PropTypes.array,         // 显示列
    ContainerId: PropTypes.any,       // tab页面ID,用于弹窗控制
    plot: PropTypes.object,
    tableId: PropTypes.string,
    loading: PropTypes.bool,
@@ -745,11 +741,11 @@
    this.setState({selectKey: data.key})
    MKEmitter.emit('changeTableLine', this.props.ContainerId, this.props.tableId, _id, data)
    MKEmitter.emit('changeTableLine', config.setting.ContainerId, this.props.tableId, _id, data)
  }
  render() {
    const { plot, data, loading, BID, BData, MenuID, config, columns, ContainerId } = this.props
    const { plot, data, loading, BID, BData, MenuID, config, columns } = this.props
    const { card, colMap, selectKey, actionList } = this.state
    
    return (
@@ -800,7 +796,6 @@
              columns={columns}
              selectKey={selectKey}
              setting={config.setting}
              ContainerId={ContainerId}
              switchCard={this.switchCard}
            />
          ))
@@ -815,7 +810,6 @@
            BData={BData}
            MenuID={MenuID}
            setting={config.setting}
            ContainerId={ContainerId}
            switchCard={() => {}}
          /> : null
        }
src/tabviews/zshare/normalTable/index.jsx
@@ -48,7 +48,6 @@
    pickup: PropTypes.any,           // 数据收起
    columns: PropTypes.array,        // 表格列
    fields: PropTypes.array,         // 组件字段集
    ContainerId: PropTypes.any,      // 标签页外层Id
    BData: PropTypes.any,            // 主表数据
    data: PropTypes.any,             // 表格数据
    total: PropTypes.any,            // 总数
@@ -758,7 +757,6 @@
                  BData={this.props.BData}
                  setting={this.props.setting}
                  columns={this.props.fields || this.props.columns}
                  ContainerId={this.props.ContainerId}
                />
              )
            } else if (btn.OpenType === 'popview') {
@@ -1121,9 +1119,9 @@
  }
  changedata = (index) => {
    const { data, setting, tableId, ContainerId } = this.props
    const { data, setting, tableId } = this.props
    if (!tableId || !ContainerId) return
    if (!tableId || !setting.ContainerId) return
    let _id = ''
    let _data = ''
@@ -1133,7 +1131,7 @@
      _data = data[index] || ''
    }
    MKEmitter.emit('changeTableLine', ContainerId, tableId, _id, _data)
    MKEmitter.emit('changeTableLine', setting.ContainerId, tableId, _id, _data)
  }
  resetTable = (id, repage) => {
src/tabviews/zshare/tablenodes/index.jsx
New file
@@ -0,0 +1,458 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal, Button, notification, Spin, Input, Typography } from 'antd'
import Api from '@/api'
import G6 from "@antv/g6"
import Utils from '@/utils/utils.js'
import options from '@/store/options.js'
import './index.scss'
const { Search } = Input
const { Paragraph } = Typography
class TableNodes extends Component {
  static propTpyes = {
    config: PropTypes.object
  }
  state = {
    debug: sessionStorage.getItem('debug') === 'true',
    visible: false,
    loading: false,
    nodes: null,
    empty: false
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  getTbs = (config) => {
    let tbs = []
    let ptbs = []
    let traversal = (components) => {
      components.forEach(item => {
        if (item.$tables) {
          ptbs.push(...item.$tables)
          item.$tables.forEach(tb => {
            tbs.push({
              label: item.name,
              table: tb,
              color: '#5AD8A6',
              id: Utils.getuuid(),
              direction: 'left'
            })
          })
        }
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            traversal(tab.components)
          })
        } else if (item.type === 'group') {
          traversal(item.components)
        }
      })
    }
    if (config.Template === 'BaseTable') {
      config.components.forEach(item => {
        if (item.type === 'tabs') {
          item.subtabs.forEach(tab => {
            if (tab.components[0].$tables) {
              ptbs.push(...tab.components[0].$tables)
              tab.components[0].$tables.forEach(tb => {
                tbs.push({
                  label: tab.label,
                  table: tb,
                  color: '#5AD8A6',
                  id: Utils.getuuid(),
                  direction: 'left'
                })
              })
            }
          })
        } else if (item.$tables) {
          ptbs.push(...item.$tables)
          item.$tables.forEach(tb => {
            tbs.push({
              label: '主表',
              table: tb,
              color: '#5AD8A6',
              id: Utils.getuuid(),
              direction: 'left'
            })
          })
        }
      })
    } else {
      traversal(config.components)
      if (config.interfaces) {
        config.interfaces.forEach(item => {
          if (item.$tables) {
            ptbs.push(...item.$tables)
            item.$tables.forEach(tb => {
              tbs.push({
                label: item.name,
                table: tb,
                color: '#5AD8A6',
                id: Utils.getuuid(),
                direction: 'left'
              })
            })
          }
        })
      }
    }
    return {tbs, ptbs}
  }
  trigger = () => {
    const { config } = this.props
    if (!config) return
    if (config.Template === 'CustomPage' && config.version !== 2.0) {
      notification.warning({
        top: 92,
        message: '请升级当前菜单!',
        duration: 5
      })
      return
    }
    this.setState({visible: true, loading: true, empty: false}, () => {
      let param = {
        func: 's_get_menus_tb_list_cloud_sso',
        TypeCharOne: '',
        typename: '',
        MenuID: config.uuid
      }
      Api.getSystemConfig(param).then(result => {
        if (!result.status) {
          notification.warning({
            top: 92,
            message: result.message,
            duration: 5
          })
          this.setState({empty: true, loading: false})
          return
        }
        let data = {
          label: config.MenuName || '空',
          id: config.uuid,
          MenuID: config.MenuID,
          children: []
        }
        let { tbs, ptbs } = this.getTbs(config)
        ptbs = Array.from(new Set(ptbs))
        ptbs.sort()
        if (ptbs.length && sessionStorage.getItem('mk_tb_names')) {
          let names = sessionStorage.getItem('mk_tb_names')
          ptbs = ptbs.filter(tb => names.indexOf(',' + tb.toLowerCase() + ',') > -1)
        }
        if (ptbs.length) {
          ptbs.forEach((item, i) => {
            let cell = {
              label: item,
              name: item.toLowerCase(),
              id: 'par' + i,
              direction: 'left',
              color: '#5AD8A6',
              children: []
            }
            tbs.forEach(t => {
              if (t.table === item) {
                cell.children.push(t)
              }
            })
            data.children.push(cell)
          })
        }
        if (result.tb_list) {
          result.tb_list.sort((a, b) => a.tbname > b.tbname ? 1 : -1)
          result.tb_list.forEach((item, i) => {
            let cell = {
              label: item.tbname,
              name: item.tbname.toLowerCase(),
              id: 'table' + i,
              direction: 'right',
              color: '#1890ff',
              children: []
            }
            if (item[item.tbname]) {
              item[item.tbname].forEach((m, i) => {
                if (m.debug_url) {
                  let _param = JSON.parse(window.decodeURIComponent(window.atob(m.debug_url)))
                  let label = _param.MenuName
                  if (_param && _param.type === 'app') {
                    label += ` (${_param.kei_no} | ${_param.typename}${param.lang !== 'zh-CN' ? ' | ' + param.lang : ''})`
                  }
                  cell.children.push({
                    label: label,
                    id: item.tbname + 'menu' + i,
                    direction: 'right',
                    color: '#1890ff',
                    param: _param
                  })
                }
              })
            }
            data.children.push(cell)
          })
        }
        if (data.children.length === 0) {
          this.setState({empty: true, loading: false})
        } else {
          this.setState({loading: false, nodes: data})
          this.getForks(data)
        }
      })
    })
  }
  resetNodes = (key) => {
    let data = fromJS(this.state.nodes).toJS()
    key = key ? key.toLowerCase() : ''
    data.children.forEach(cell => {
      cell.fontcolor = ''
      if (!cell.name) return
      if (key && cell.name.indexOf(key) > -1) {
        cell.fontcolor = 'orange'
      }
    })
    let _element = document.getElementById('mkTableNode')
    if (_element) {
      _element.innerHTML = ''
    }
    this.setState({}, () => {
      this.getForks(data)
    })
  }
  getForks = (data) => {
    const { Util } = G6
    G6.registerNode(
      'dice-mind-map-root', {
        jsx: (cfg) => {
          const width = Util.getTextSize(cfg.label, 14)[0] + 12;
          const stroke = cfg.style.stroke || '#096dd9';
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 30, stroke: ${stroke}, radius: 4}} keyshape>
              <text style={{ fontSize: 14, marginLeft: 6, marginTop: 6 }}>${cfg.label}</text>
            </rect>
          </group>
        `;
        },
        getAnchorPoints() {
          return [
            [0, 0.5],
            [1, 0.5],
          ];
        },
      },
      'single-node',
    );
    G6.registerNode(
      'dice-mind-map-leaf', {
        jsx: (cfg) => {
          const width = Util.getTextSize(cfg.label, 12)[0] + 24;
          const color = cfg.color;
          return `
          <group>
            <rect draggable="true" style={{width: ${width}, height: 26, fill: 'transparent' }}>
              <text style={{ fontSize: 12, fill: ${cfg.fontcolor ? cfg.fontcolor : 'black'}, marginLeft: 12, marginTop: 6 }}>${cfg.label}</text>
            </rect>
            <rect style={{ fill: ${color}, width: ${width}, height: 2, x: 0, y: 32 }} />
          </group>
        `;
        },
        getAnchorPoints() {
          return [
            [0, 0.965],
            [1, 0.965],
          ];
        },
      },
      'single-node',
    );
    G6.registerBehavior('dice-mindmap', {
      getEvents() {
        return {
          'node:dblclick': 'editNode',
        };
      }
    });
    G6.registerBehavior('scroll-canvas', {
      getEvents: function getEvents() {
        return {
          wheel: 'onWheel',
        };
      },
      onWheel: function onWheel(ev) {
        const {
          graph
        } = this;
        if (!graph) {
          return;
        }
        if (ev.ctrlKey) {
          const canvas = graph.get('canvas');
          const point = canvas.getPointByClient(ev.clientX, ev.clientY);
          let ratio = graph.getZoom();
          if (ev.wheelDelta > 0) {
            ratio += ratio * 0.05;
          } else {
            ratio *= ratio * 0.05;
          }
          graph.zoomTo(ratio, {
            x: point.x,
            y: point.y,
          });
        } else {
          const x = ev.deltaX || ev.movementX;
          const y = ev.deltaY || ev.movementY || (-ev.wheelDelta * 125) / 3;
          graph.translate(-x, -y);
        }
        ev.preventDefault();
      },
    });
    const dataTransform = (data) => {
      const changeData = (d, level = 0, color) => {
        const data = {
          ...d,
        };
        switch (level) {
          case 0:
            data.type = 'dice-mind-map-root';
            break;
          default:
            data.type = 'dice-mind-map-leaf';
            break;
        }
        data.hover = false;
        if (color) {
          data.color = color;
        }
        if (d.children) {
          data.children = d.children.map((child) => changeData(child, level + 1, data.color));
        }
        return data;
      };
      return changeData(data);
    };
    const tree = new G6.TreeGraph({
      container: 'mkTableNode',
      width: this.wrap.offsetWidth,
      height: this.wrap.offsetHeight,
      fitView: true,
      fitViewPadding: [10, 20],
      layout: {
        type: 'mindmap',
        direction: 'H',
        getHeight: () => {
          return 16;
        },
        getWidth: (node) => {
          return node.level === 0 ?
            Util.getTextSize(node.label, 16)[0] + 12 :
            Util.getTextSize(node.label, 12)[0];
        },
        getVGap: () => {
          return 10;
        },
        getHGap: () => {
          return 60;
        },
        getSide: (node) => {
          return node.data.direction;
        },
      },
      defaultEdge: {
        type: 'cubic-horizontal',
        style: {
          lineWidth: 2,
        },
      },
      minZoom: 0.5,
      modes: {
        default: ['drag-canvas', 'zoom-canvas', 'dice-mindmap'],
      },
    });
    tree.data(dataTransform(data));
    tree.render();
  }
  render() {
    const { config } = this.props
    const { visible, loading, empty, debug } = this.state
    return (
      <div className={'page-message-wrap ' + (debug && options.sysType !== 'cloud' ? 'exist' : '')}>
        {debug && options.sysType !== 'cloud' ? <Button
          icon="fork"
          shape="circle"
          className="page-message"
          onClick={this.trigger}
        /> : null}
        <Modal
          title=""
          wrapClassName="view-table-modal"
          visible={visible}
          width={'90vw'}
          closable={false}
          maskClosable={false}
          footer={[]}
          destroyOnClose
        >
          <div className="header">表关系图({config && config.MenuNo ? <Paragraph copyable>{config.MenuNo}</Paragraph> : ''})</div>
          <Search className="tb-search" placeholder="请输入表名" onSearch={value => this.resetNodes(value)} enterButton />
          <div className="wrap">
            {loading ? <Spin size="large" /> : null}
            {empty ? <div className="empty">未查询到表名信息。</div> : null}
            <div className="mountNode" id="mkTableNode" ref={ref => this.wrap = ref}></div>
          </div>
          <div className="footer">
            <Button key="cancel" onClick={() => { this.setState({ visible: false })}}>关闭</Button>
          </div>
        </Modal>
      </div>
    )
  }
}
export default TableNodes
src/tabviews/zshare/tablenodes/index.scss
New file
@@ -0,0 +1,73 @@
.page-message-wrap {
  .page-message {
    position: fixed;
    z-index: 2;
    bottom: 55px;
    right: 20px;
    width: 40px;
    height: 40px;
  }
}
.view-table-modal {
  .ant-modal {
    top: 55px;
  }
  .ant-modal-body {
    padding: 20px 50px 20px;
    user-select: none;
  }
  .ant-modal-footer {
    display: none;
  }
  .wrap {
    position: relative;
    height: calc(100vh - 240px);
    margin: 10px 0px;
    overflow: hidden;
    .mountNode {
      height: 100%;
    }
    .ant-spin {
      position: absolute;
      top: calc(50% - 16px);
      left: calc(50% - 16px);
    }
    .empty {
      position: relative;
      text-align: center;
      color: #959595;
      padding-top: 200px;
    }
    .empty + .mountNode {
      opacity: 0;
    }
  }
  .header {
    font-weight: 500;
    text-align: center;
    font-size: 18px;
    white-space: nowrap;
    .ant-typography {
      color: #1890ff;
      display: inline-block;
      .ant-typography-copy {
        font-size: 14px;
      }
    }
  }
  .footer {
    text-align: center;
  }
  .tb-search {
    position: absolute;
    width: 200px;
    z-index: 1;
    right: 40px;
    top: 16px;
  }
}
src/templates/modalconfig/settingform/index.jsx
@@ -19,6 +19,7 @@
    display: this.props.config.setting.display || 'modal',
    placement: this.props.config.setting.placement || 'right',
    appType: sessionStorage.getItem('appType'),
    viewType: sessionStorage.getItem('editMenuType') || '',
    dialogInput: false
  }
@@ -315,7 +316,7 @@
              )}
            </Form.Item>
          </Col> : null}
          {!this.props.isSubTab && !appType && display === 'modal' ? <Col span={12}>
          {!this.props.isSubTab && !appType && this.state.viewType !== 'popview' && display === 'modal' ? <Col span={12}>
            <Form.Item label="挂载对象">
              {getFieldDecorator('container', {
                initialValue: config.setting.container || 'tab'
src/templates/zshare/verifycard/customscript/index.jsx
@@ -176,7 +176,7 @@
        }
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.LText = param.LText.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id)@/ig, `'${param.timestamp}'`)
        param.LText = param.LText.replace(/@(BID|ID|LoginUID|SessionUid|UserID|Appkey|time_id|typename)@/ig, `'${param.timestamp}'`)
        console.info(`/* sql 验证 */\n${param.LText.replace(/\n\s{6,20}/ig, '\n')}`)
@@ -272,7 +272,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, time_id, typename</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并赋值。'}><span style={{color: '#fa8c16'}}>UserName, FullName, RoleID, mk_departmentcode, mk_organization, mk_user_type, mk_nation, mk_province, mk_city, mk_district, mk_address</span></Tooltip>,&nbsp;
              <Tooltip mouseLeaveDelay={0.3} mouseEnterDelay={0.3} placement="top" title={'系统变量,系统会定义变量并在单号生成或创建凭证时使用。'}><span style={{color: '#13c2c2'}}>BillCode, BVoucher, FIBVoucherDate, FiYear, ModularDetailCode</span></Tooltip>
              {usefulfields ? <span>, {usefulfields}</span> : ''}
src/templates/zshare/verifycard/index.jsx
@@ -827,6 +827,10 @@
          keys.push('bid')
          values.push('@BID@')
        }
        if (!keys.includes('typename')) {
          keys.push('typename')
          values.push('@typename@')
        }
  
        keys = keys.join(', ')
        values = values.join(', ')
@@ -861,6 +865,9 @@
          if (!_arr.includes('submituserid')) {
            _form.push('submituserid=@userid@')
          }
          if (!_arr.includes('typename')) {
            _form.push(`typename=@typename@`)
          }
        } else {
          if (!_arr.includes('modifydate')) {
            _form.push('modifydate=getdate()')
@@ -873,6 +880,9 @@
          }
          if (!_arr.includes('modifyuserid')) {
            _form.push('modifyuserid=@userid@')
          }
          if (!_arr.includes('typename')) {
            _form.push(`typename=@typename@`)
          }
        }
@@ -925,7 +935,7 @@
            _index++
          })
        }
        _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${card.sql} 数据: ${_msg}${_primaryKey}='+@ID@,200),@userid@,@username,@fullname delete ${card.sql} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
        _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff,typename) select left('删除表:${card.sql} 数据: ${_msg}${_primaryKey}='+@ID@,200),@userid@,@username,@fullname,@typename@ delete ${card.sql} where ${_primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
      }
      let _columns = []
src/utils/option.js
@@ -52,13 +52,13 @@
    baseconfig: '',
    isSystem: true
  },
  // {
  //   title: '基础表格(新)',
  //   type: 'BaseTable',
  //   url: nortable,
  //   baseconfig: '',
  //   isSystem: true
  // },
  {
    title: '基础表格(新)',
    type: 'BaseTable',
    url: nortable,
    baseconfig: '',
    isSystem: true
  },
  // {
  //   title: '主子表表格',
  //   type: 'CommonTable',
src/utils/utils-custom.js
@@ -850,20 +850,22 @@
  let trimreg = /(from|update|insert\s+into)\s+(@db@)?/ig
  if (!config.wrap || !config.wrap.datatype || config.wrap.datatype === 'dynamic') {
    if (config.setting.interType === 'system') {
      if (config.setting.execute !== 'false') {
        let tbs = config.setting.dataresource.match(cutreg)
        tbs && cuts.push(...tbs)
      }
      config.scripts && config.scripts.forEach(script => {
        if (script.status === 'false') return
        let tbs = script.sql.match(cutreg)
        tbs && cuts.push(...tbs)
      })
    } else {
      let tb = config.setting.tableName.replace(/@db@|\s+/ig, '')
      if (/[a-z_]+/ig.test(tb)) {
        tables.push(tb)
    if (config.setting) {
      if (config.setting.interType === 'system') {
        if (config.setting.execute !== 'false') {
          let tbs = config.setting.dataresource.match(cutreg)
          tbs && cuts.push(...tbs)
        }
        config.scripts && config.scripts.forEach(script => {
          if (script.status === 'false') return
          let tbs = script.sql.match(cutreg)
          tbs && cuts.push(...tbs)
        })
      } else {
        let tb = config.setting.tableName.replace(/@db@|\s+/ig, '')
        if (/[a-z_]+/ig.test(tb)) {
          tables.push(tb)
        }
      }
    }
  }
src/utils/utils.js
@@ -1931,6 +1931,11 @@
      values.push('@BID@')
    }
    if (!keys.includes('typename')) {
      keys.push('typename')
      values.push('@typename@')
    }
    keys = keys.join(',')
    values = values.join(',')
    _insertsql = `insert into ${btn.sql} (${keys}) select ${values};`
@@ -1988,6 +1993,9 @@
        _form.push('FiYear=@FiYear')
      }
    }
    if (!_arr.includes('typename')) {
      _form.push('typename=@typename@')
    }
    _form = _form.join(',')
    let _ID = '=@ID@'
@@ -2040,7 +2048,7 @@
    _sql += `
      /* 默认sql */
      insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${btn.sql} 数据: ${_msg}${primaryKey}='+@ID@,200),@userid@,@username,@fullname
      insert into snote (remark,createuserid,CreateUser,CreateStaff,typename) select left('删除表:${btn.sql} 数据: ${_msg}${primaryKey}='+@ID@,200),@userid@,@username,@fullname,@typename@
      delete ${btn.sql} where ${primaryKey}${_ID};`
  } else if (_actionType === 'insertOrUpdate') {
    _sql += `
@@ -2095,6 +2103,7 @@
  _sql = _sql.replace(/@SessionUid@/ig, `'${localStorage.getItem('SessionUid') || ''}'`)
  _sql = _sql.replace(/@UserID@/ig, `'${sessionStorage.getItem('UserID') || ''}'`)
  _sql = _sql.replace(/@Appkey@/ig, `'${window.GLOB.appkey || ''}'`)
  _sql = _sql.replace(/@typename@/ig, `'admin'`)
  if (window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')) {
    // _sql = _sql.replace(/\n\s{8}/ig, '\n')
@@ -2134,6 +2143,7 @@
    if (mark.field[1] === 'static') {
      contrastVal = mark.contrastValue
      originVal = originVal + ''
    } else {
      contrastVal = record[mark.field[2]]
    }
src/views/billprint/index.jsx
@@ -26,6 +26,7 @@
const SandBox = asyncComponent(() => import('@/tabviews/custom/components/code/sand-box'))
const TimeLine = asyncComponent(() => import('@/tabviews/custom/components/timeline/normal-timeline'))
const Balcony = asyncComponent(() => import('@/tabviews/custom/components/card/balcony'))
const DebugTable = asyncComponent(() => import('@/tabviews/debugtable'))
class BillPrint extends Component {
  state = {
@@ -38,6 +39,7 @@
    tempId: '',
    config: null,
    urlParam: null,
    visible: false,
    auto: true
  }
@@ -78,6 +80,53 @@
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount() {
    const _this = this
    Object.defineProperty(window, 'debug', {
      configurable: true,
      enumerable: true,
      set(value) {
        if (value + '' === 'false') {
          window.debugger = false
          window.GLOB.breakpoint = false
          sessionStorage.removeItem('breakpoint')
        } else {
          window.debugger = true
          window.GLOB.breakpoint = value + ''
          sessionStorage.setItem('breakpoint', value)
        }
        _this.debugChange()
      }
    })
    document.onkeydown = (event) => {
      let e = event || window.event
      let keyCode = e.keyCode || e.which || e.charCode
      let preKey = ''
      if (e.ctrlKey) {
        preKey = 'ctrl'
      } else if (e.shiftKey) {
        preKey = 'shift'
      } else if (e.altKey) {
        preKey = 'alt'
      }
      if (!preKey || !keyCode) return
      let _shortcut = `${preKey}+${keyCode}`
      if (window.GLOB.breakpoint && _shortcut === 'ctrl+67') {
        window.debugger = false
        window.GLOB.breakpoint = false
        sessionStorage.removeItem('breakpoint')
        _this.debugChange()
      }
    }
  }
  /**
   * @description 组件销毁,清除state更新
   */
@@ -85,6 +134,10 @@
    this.setState = () => {
      return
    }
  }
  debugChange = () => {
    this.setState({visible: !this.state.visible})
  }
  getTouristMsg = () => {
@@ -633,10 +686,30 @@
    })
  }
  canvasToImage(canvas) {
    let image = new Image()
    image.src = canvas.toDataURL('image/jpg')
    image.style = 'width:100%;height:100%;position:absolute;z-index:1;left:0px;top:0px;'
    return image
  }
  print = () => {
    const { config, printing } = this.state
    if (printing) return
    let qrcodes = document.getElementsByClassName('qrcode-box')
    for (let i = 0; i < qrcodes.length; i++) {
      let canvas = qrcodes[i].getElementsByTagName('canvas')[0]
      if (canvas) {
        let img = this.canvasToImage(canvas)
        canvas.remove()
        qrcodes[i].append(img)
      }
    }
    let jubuData = document.getElementById('bill-print').innerHTML
@@ -770,6 +843,7 @@
          {pages.map((components, index) => (<div className={'print-page' + (auto ? ' auto' : '')} key={index} style={{...config.style, overflow: 'hidden', boxSizing: 'border-box'}}><Row>{this.getComponents(components)}</Row></div>))}
        </div> : null}
        {viewlost ? <NotFount msg={this.state.lostmsg} /> : null}
        {config && window.GLOB.breakpoint ? <DebugTable /> : null}
        {pages && !loadingview && !viewlost ? <div className="print-button"><Button icon="printer" size="large" shape="circle" onClick={this.print}></Button></div> : null}
        {!loadingview && !viewlost ? <div className="refresh-button"><Button icon="reload" size="large" shape="circle" onClick={this.reload}></Button></div> : null}
      </div>
src/views/billprint/index.scss
@@ -35,6 +35,14 @@
  .ant-empty {
    display: none;
  }
  .debugtable {
    .ant-table-placeholder {
      display: block;
    }
    .ant-empty {
      display: block;
    }
  }
}
.print-page {
src/views/menudesign/homeform/index.jsx
@@ -13,15 +13,18 @@
    updateConfig: PropTypes.func
  }
  state = {
    menulist: []
  }
  state = {}
  UNSAFE_componentWillMount () {
    let _param = {func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}
    _param.pro_sys = window.GLOB.systemType === 'production' ? 'Y' : ''
    if (sessionStorage.getItem('thdMenuList') && sessionStorage.getItem('fstMenuList')) {
    Api.getSystemConfig(_param).then(result => {
    } else {
      this.getMenus()
    }
  }
  getMenus = () => {
    Api.getSystemConfig({func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}).then(result => {
      if (result.status) {
        let thdMenuList = []
        let menulist = result.fst_menu.map(fst => {
src/views/menudesign/index.jsx
@@ -166,6 +166,9 @@
        let node = document.getElementById('save-modal-config')
        if (!node) {
          node = document.getElementById('save-pop-config')
        }
        if (!node) {
          node = document.getElementById('save-config')
        }
@@ -582,6 +585,7 @@
    let popBtns = []
    config.components = this.collectTB(config.components, popBtns)
    config.version = 2.0
    if (popBtns.length === 0) {
      this.setState({
src/views/menudesign/menuform/index.jsx
@@ -26,7 +26,57 @@
  }
  UNSAFE_componentWillMount () {
    if (sessionStorage.getItem('thdMenuList') && sessionStorage.getItem('fstMenuList')) {
      this.setMenus()
    } else {
      this.getMenus()
    }
  }
  setMenus = () => {
    const { MenuId, config } = this.props
    let menulist = sessionStorage.getItem('fstMenuList')
    let thdMenuList = sessionStorage.getItem('thdMenuList')
    menulist = JSON.parse(menulist)
    thdMenuList = JSON.parse(thdMenuList)
    let thdMenu = null
    thdMenuList.forEach(trd => {
      if (MenuId === trd.MenuID) {
        thdMenu = trd
      }
    })
    let smenulist = []
    if (thdMenu) {
      menulist.forEach(item => {
        if (item.MenuID === thdMenu.FstId) {
          smenulist = item.children
        }
      })
    }
    this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
    this.setState({
      fstMenuId: thdMenu ? thdMenu.FstId : '',
      menulist,
      smenulist
    }, () => {
      this.props.form.setFieldsValue({
        fstMenuId: thdMenu ? thdMenu.FstId : '',
        parentId: thdMenu ? thdMenu.ParentId : ''
      })
    })
  }
  getMenus = () => {
    const { MenuId, config } = this.props
    Api.getSystemConfig({func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}).then(result => {
      if (result.status) {
        let thdMenu = null
@@ -64,12 +114,7 @@
                    value: trd.MenuID,
                    label: trd.MenuName,
                    type: 'CommonTable',
                    // disabled: trd.MenuID === MenuId
                    disabled: false
                  }
                  if (MenuId === trd.MenuID) {
                    thdMenu = trdItem
                  }
                  if (trd.PageParam) {
@@ -79,6 +124,10 @@
                    } catch (e) {
                    }
                  }
                  if (MenuId === trd.MenuID) {
                    thdMenu = trdItem
                  }
                  thdMenuList.push(trdItem)
@@ -93,11 +142,13 @@
        })
        let smenulist = []
        menulist.forEach(item => {
          if (thdMenu && (item.MenuID === thdMenu.FstId)) {
            smenulist = item.children
          }
        })
        if (thdMenu) {
          menulist.forEach(item => {
            if (item.MenuID === thdMenu.FstId) {
              smenulist = item.children
            }
          })
        }
        sessionStorage.setItem('fstMenuList', JSON.stringify(menulist))
        sessionStorage.setItem('thdMenuList', JSON.stringify(thdMenuList))
        this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
src/views/menudesign/popview/index.jsx
@@ -113,6 +113,7 @@
  completeSave = () => {
    this.setState({
      oriConfig: fromJS(this.state.config).toJS(),
      menuloading: false
    })
  }
@@ -142,7 +143,7 @@
    window.GLOB.customMenu = config
    this.props.save(config)
    this.props.save(fromJS(config).toJS())
  }
  onEnabledChange = () => {
src/views/menudesign/printmenuform/index.jsx
@@ -11,13 +11,6 @@
    updateConfig: PropTypes.func
  }
  // changeFirstCount = (val) => {
  //   if (typeof(val) !== 'number') {
  //     val = ''
  //   }
  //   this.props.updateConfig({...this.props.config, firstCount: val})
  // }
  changeCount = (val) => {
    if (typeof(val) !== 'number') {
      val = ''
@@ -42,13 +35,6 @@
  onPrintPageChange = (val) => {
    this.props.updateConfig({...this.props.config, printPage: val})
  }
  // changeLastCount = (val) => {
  //   if (typeof(val) !== 'number') {
  //     val = ''
  //   }
  //   this.props.updateConfig({...this.props.config, lastCount: val})
  // }
  pageSizeChange = (val) => {
    this.props.updateConfig({...this.props.config, pageSize: val})
src/views/mobdesign/index.jsx
@@ -12,7 +12,7 @@
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import MKEmitter from '@/utils/events.js'
import MenuUtils from '@/utils/utils-custom.js'
import MenuUtils, { getTables } from '@/utils/utils-custom.js'
import asyncComponent from '@/utils/asyncComponent'
import '@/assets/css/design.scss'
@@ -64,11 +64,10 @@
    MenuId: '',
    MenuName: '',
    MenuNo: '',
    activeKey: 'component',
    activeKey: 'basedata',
    menuloading: false,
    oriConfig: null,
    config: null,
    customComponents: [],
    direction: 'vertical',
    settingshow: true,
    controlshow: true,
@@ -76,6 +75,7 @@
    adapters: [],
    viewType: 'menu',
    eyeopen: false,
    needUpdate: false
  }
  UNSAFE_componentWillMount() {
@@ -121,7 +121,6 @@
          viewType: /^userbind/.test(param.MenuID) ? 'userbind' : 'menu'
        }, () => {
          this.getMenuParam(param)
          this.getRelationMenus()
        })
      }
    } catch (e) {
@@ -150,16 +149,7 @@
    }
    MKEmitter.addListener('triggerMenuSave', this.submitConfig)
    MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
    MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
    setTimeout(() => {
      if (sessionStorage.getItem('app_custom_components')) {
        let list = sessionStorage.getItem('app_custom_components')
        list = JSON.parse(list)
        this.setCustomComponent(list)
      } else {
        this.updateCustomComponent()
      }
      this.getAppPictures()
      this.getSmStemp()
      this.getRoleFields()
@@ -229,46 +219,47 @@
    }
    MKEmitter.removeListener('triggerMenuSave', this.submitConfig)
    MKEmitter.removeListener('changeEditMenu', this.changeEditMenu)
    MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
  }
  getSmStemp = () => {
    let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
      inner join (select openid from sapp where id='${window.GLOB.appkey}') b
      on a.openid=b.openid`
    _sql = Utils.formatOptions(_sql)
    let param = {
      func: 'sPC_Get_SelectedList',
      LText: _sql,
      obj_name: 'data',
      arr_field: 'ID,TemplateCode,SignName'
    }
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
    Api.getSystemConfig(param).then(res => {
      let msgs = []
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      } else if (res.data) {
        msgs = res.data
    if (!sessionStorage.getItem('msgTemplate')) {
      let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
        inner join (select openid from sapp where id='${window.GLOB.appkey}') b
        on a.openid=b.openid`
      _sql = Utils.formatOptions(_sql)
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: _sql,
        obj_name: 'data',
        arr_field: 'ID,TemplateCode,SignName'
      }
      sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
    })
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
      Api.getSystemConfig(param).then(res => {
        let msgs = []
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        } else if (res.data) {
          msgs = res.data
        }
        sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
      })
    }
  }
  changeEditMenu = (menu) => {
    const { oriConfig, config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -411,60 +402,12 @@
    })
  }
  updateCustomComponent = () => {
    Api.getSystemConfig({
      func: 's_get_custom_components',
      typename: sessionStorage.getItem('typename'),
      typecharone: ''
    }).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      } else if (res.cus_list) {
        sessionStorage.setItem('app_custom_components', JSON.stringify(res.cus_list))
        this.setCustomComponent(res.cus_list)
      }
    })
  }
  setCustomComponent = (cus_list) => {
    let coms = []
    cus_list.forEach(item => {
      let config = ''
      try {
        config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param)))
      } catch (e) {
        console.warn('Parse Failure')
        config = ''
      }
      if (!config || !item.c_name) return
      window.GLOB.UserComponentMap.set(item.c_id, item.c_name)
      coms.push({
        uuid: item.c_id,
        type: 'menu',
        title: item.c_name,
        url: item.images,
        component: config.type,
        subtype: config.subtype,
        config
      })
    })
    this.setState({customComponents: coms})
  }
  closeView = () => {
    const { oriConfig, config } = this.state
    if (!config) {
      window.close()
    } else if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    } else if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      confirm({
        title: '配置信息未保存,确定关闭吗?',
        content: '',
@@ -483,7 +426,7 @@
    if (!config) {
      window.history.back()
    } else if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    } else if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      confirm({
        title: '配置信息未保存,确定后退吗?',
        content: '',
@@ -520,7 +463,6 @@
        this.getCopyParam(urlParam)
      } else {
        let config = null
        let isCreate = false
        try {
          config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null
@@ -535,15 +477,13 @@
        }
        if (!config) {
          isCreate = true
          config = {
            version: 1.0,
            version: 2.0,
            uuid: MenuId,
            MenuID: MenuId,
            Template: 'webPage',
            enabled: false,
            MenuName: urlParam.MenuName || '',
            // MenuNo: urlParam.MenuNo || '',
            MenuNo: '',
            tables: [],
            components: [],
@@ -560,59 +500,43 @@
        config.open_edition = result.open_edition || ''
        window.GLOB.urlFields = config.urlFields || []
        let indeComs = []
        if (config.version !== 2.0) {
          config.components = this.collectTB(config.components)
          config.version = 2.0
          this.setState({
            needUpdate: true
          })
        }
        let navItem = null
        config.components.forEach(item => {
          if (item.type === 'navbar') {
            indeComs.push(fromJS(item).toJS())
            navItem = fromJS(item).toJS()
          }
        })
        if (indeComs.length === 0) {
        if (!navItem) {
          this.setState({
            oriConfig: isCreate ? null : config,
            config: fromJS(config).toJS(),
            activeKey: isCreate ? 'basedata' : 'component',
            oriConfig: fromJS(config).toJS(),
            config: config,
            loading: false
          })
          window.GLOB.customMenu = config
        } else {
          this.jointComponents(config, indeComs, isCreate)
          this.jointComponents(config, navItem)
        }
      }
    })
    this.getAppMenus()
  }
  getRelationMenus = () => {
    const { MenuId } = this.state
    let param = {
      func: 's_get_menu_used_list',
      TypeCharOne: sessionStorage.getItem('kei_no'),
      typename: sessionStorage.getItem('typename'),
      par_menuid: MenuId,
      // used_menuid: MenuId
    }
    Api.getSystemConfig(param).then(result => {
      if (!result.status) {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
        return
      }
    })
  }
  setUserBindMenu = (config, result) => {
    const { MenuId } = this.state
    let isCreate = !config
    if (!config) {
      config = {
        version: 1.0,
        version: 2.0,
        uuid: MenuId,
        MenuID: MenuId,
        Template: 'webPage',
@@ -677,9 +601,8 @@
    config.open_edition = result.open_edition || ''
    this.setState({
      oriConfig: isCreate ? null : config,
      config: fromJS(config).toJS(),
      activeKey: isCreate ? 'basedata' : 'component',
      oriConfig: fromJS(config).toJS(),
      config: config,
      loading: false
    })
    window.GLOB.customMenu = config
@@ -767,7 +690,7 @@
      
      if (!config) {
        config = {
          version: 1.0,
          version: 2.0,
          uuid: MenuId,
          MenuID: MenuId,
          Template: 'webPage',
@@ -792,6 +715,16 @@
        }
        config.components = MenuUtils.resetConfig(config.components, uuids, urlParam.clearMenu)
        if (config.version !== 2.0) {
          config.components = this.collectTB(config.components)
          config.version = 2.0
          this.setState({
            needUpdate: true
          })
        }
        config.enabled = false
        message.success('复制成功,保存后生效。')
      }
@@ -803,14 +736,14 @@
      // config.MenuNo = urlParam.MenuNo || ''
      config.MenuNo = ''
      let indeComs = []
      let navItem = null
      config.components.forEach(item => {
        if (item.type === 'navbar') {
          indeComs.push(fromJS(item).toJS())
          navItem = fromJS(item).toJS()
        }
      })
      if (indeComs.length === 0) {
      if (!navItem) {
        this.setState({
          oriConfig: null,
          config: fromJS(config).toJS(),
@@ -819,37 +752,27 @@
        window.GLOB.customMenu = config
      } else {
        this.jointComponents(config, indeComs, true)
        this.jointComponents(config, navItem)
      }
    })
  }
  jointComponents = (config, indeComs, isCreate) => {
    let deffers = indeComs.map(item => {
      return new Promise(resolve => {
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          TypeCharOne: sessionStorage.getItem('kei_no'),
          typename: sessionStorage.getItem('typename'),
          MenuID: item.uuid
        }).then(res => {
          res.uuid = item.uuid
          if (!res.status) {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
          resolve(res)
  jointComponents = (config, navItem) => {
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      TypeCharOne: sessionStorage.getItem('kei_no'),
      typename: sessionStorage.getItem('typename'),
      MenuID: navItem.uuid
    }).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      })
    })
    Promise.all(deffers).then(result => {
      let _conf = {}
      result.forEach(res => {
        config.components = config.components.filter(item => item.type !== 'navbar')
      } else {
        let _config = null
        try {
          _config = res.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) : null
@@ -860,40 +783,56 @@
        if (_config) {
          _config.open_edition = res.open_edition || ''
          _conf[res.uuid] = _config
          window.GLOB.CacheIndependent.set(res.uuid, fromJS(_config).toJS())
          config.components = config.components.map(item => {
            if (item.type === 'navbar') {
              return _config
            }
            return item
          })
          window.GLOB.CacheIndependent.set(navItem.uuid, fromJS(_config).toJS())
        } else {
          config.components = config.components.filter(item => item.type !== 'navbar')
        }
      })
      let _length = config.components.length
      config.components = config.components.map(item => {
        if (item.type === 'navbar') {
          if (_conf[item.uuid]) {
            item = _conf[item.uuid]
          } else {
            item = null
          }
        }
        return item
      })
      config.components = config.components.filter(Boolean)
      if (_length > config.components.length) {
        notification.warning({
          top: 92,
          message: '部分组件已删除!',
          duration: 5
        })
      }
      this.setState({
        oriConfig: isCreate ? null : fromJS(config).toJS(),
        activeKey: isCreate ? 'basedata' : 'component',
        oriConfig: fromJS(config).toJS(),
        config: config,
        loading: false
      })
      window.GLOB.customMenu = config
    })
  }
  collectTB = (components) => {
    return components.map(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          delete tab.floor
          delete tab.hasSearch
          delete tab.parentId
          tab.components = this.collectTB(tab.components)
        })
      } else if (item.type === 'group') {
        item.components = this.collectTB(item.components)
      } else if (!['search', 'navbar', 'login', 'topbar', 'officialAccount'].includes(item.type)) {
        item.$tables = getTables(item)
      }
      if (item.subtype === 'tablecard') { // 兼容
        item.type = 'card'
      }
      delete item.tabId
      delete item.parentId
      delete item.btnlog
      delete item.floor
      delete item.dataName
      return item
    })
  }
@@ -907,15 +846,21 @@
          tbs.push(...item.$tables)
        }
        if (item.plot && item.plot.permission !== 'true') {
          return
        } else if (['login', 'navbar', 'topbar'].includes(item.type) || item.subtype === 'commonbar') {
          return
        } else if (!['tabs', 'group'].includes(item.type) && item.wrap && item.wrap.permission !== 'true') {
          return
        }
        let m = {
          key: item.uuid,
          title: item.name,
          children: []
        }
        if (item.type === 'topbar' || item.type === 'login' || item.type === 'navbar' || (item.type === 'menubar' && item.subtype === 'commonbar')) {
          return null
        } else if (item.type === 'tabs') {
        if (item.type === 'tabs') {
          let tabs = []
          let mm = []
          item.subtabs.forEach(tab => {
@@ -942,7 +887,7 @@
            list.push(...mm)
          }
          
          return null
          return
        } else if (item.type === 'group') {
          m.children = traversal(item.components)
@@ -952,12 +897,8 @@
            list.push(...m.children)
          }
          
          return null
        } if (item.plot && item.plot.permission !== 'true') {
          return null
        } if (item.wrap && item.wrap.permission !== 'true') {
          return null
        } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
          return
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.action && item.action.forEach(btn => {
            if (btn.hidden === 'true') return
@@ -968,20 +909,7 @@
          })
          item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.hidden === 'true') return
              m.children.push({
                key: cell.uuid,
                title: cell.label,
              })
            })
          })
        } else if (item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.hidden === 'true') return
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              m.children.push({
                key: cell.uuid,
@@ -991,8 +919,7 @@
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType !== 'button') return
            if (cell.hidden === 'true') return
            if (cell.eleType !== 'button' || cell.hidden === 'true') return
            m.children.push({
              key: cell.uuid,
@@ -1019,7 +946,7 @@
              }
            })
          }
        } else if (item.type === 'table' && item.subtype === 'normaltable') {
        } else if (item.type === 'table') {
          item.action && item.action.forEach(btn => {
            if (btn.hidden === 'true') return
@@ -1048,6 +975,14 @@
    }
    let trees = traversal(config.components)
    if (config.interfaces) {
      config.interfaces.forEach(item => {
        if (item.$tables) {
          tbs.push(...item.$tables)
        }
      })
    }
    return trees
  }
@@ -1088,7 +1023,6 @@
                menus.push({
                  MenuID: m.uuid,
                  MenuName: m.setting.name,
                  // MenuNo: m.setting.MenuNo
                  MenuNo: ''
                })
              }
@@ -1102,7 +1036,7 @@
          })
        } else if (item.type === 'group') {
          traversal(item.components)
        } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.action && item.action.forEach(btn => {
            if (btn.linkmenu && menuObj[btn.linkmenu]) {
              menus.push(menuObj[btn.linkmenu])
@@ -1130,21 +1064,6 @@
              }
            })
          })
        } else if (item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            if (card.setting.click === 'menu' && menuObj[card.setting.menu]) {
              menus.push(menuObj[card.setting.menu])
            }
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.linkmenu && menuObj[cell.linkmenu]) {
                menus.push(menuObj[cell.linkmenu])
              } else if (cell.openmenu && menuObj[cell.openmenu]) {
                menus.push(menuObj[cell.openmenu])
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType !== 'button') return
@@ -1161,7 +1080,7 @@
              menus.push(menuObj[m.subButton.linkmenu])
            }
          })
        } else if (item.type === 'table' && item.subtype === 'normaltable') {
        } else if (item.type === 'table') {
          item.action && item.action.forEach(btn => {
            if (btn.linkmenu && menuObj[btn.linkmenu]) {
              menus.push(menuObj[btn.linkmenu])
@@ -1220,7 +1139,7 @@
          })
        } else if (item.type === 'group') {
          item.components = traversal(item.components)
        } else if (['card', 'carousel', 'timeline'].includes(item.type) || (item.type === 'table' && item.subtype === 'tablecard')) {
        } else if (['card', 'carousel', 'timeline'].includes(item.type)) {
          item.subcards.forEach(card => {
            card.miniStyle = this.transferStyle(card.style)
            card.elements = card.elements.map(cell => {
@@ -1237,7 +1156,7 @@
            menu.miniStyle = this.transferStyle(menu.style)
            return menu
          })
        } else if (item.type === 'table' && item.subtype === 'normaltable') {
        } else if (item.type === 'table') {
          let getCols = (cols) => {
            return cols.map(col => {
              if (col.type === 'colspan') {
@@ -1408,172 +1327,151 @@
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt('', param.timestamp)
      new Promise(resolve => {
        let _config = fromJS(config).toJS()
        let indeComs = []
        _config.components = _config.components.map(item => {
          if (item.type === 'navbar') {
            indeComs.push(item)
            return {
              type: 'navbar',
              uuid: item.uuid
            }
      let _config = fromJS(config).toJS()
      let NavBar = null
      _config.components = _config.components.map(item => {
        if (item.type === 'navbar') {
          NavBar = fromJS(item).toJS()
          return {
            type: 'navbar',
            uuid: item.uuid
          }
          return item
        })
        }
        return item
      })
        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
      param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
        if (indeComs.length === 0) {
          resolve(true)
      new Promise(resolve => {
        if (!NavBar) {
          resolve({status: true})
        } else {
          let new_open_edition = {}
          let deffers = indeComs.map(item => {
            return new Promise(resolve => {
              let _item = window.GLOB.CacheIndependent.get(item.uuid)
              if (_item && is(fromJS(_item), fromJS(item))) {
                new_open_edition[item.uuid] = item.open_edition || ''
                resolve()
                return
              }
              let roles = {
                type: 'navbar',
                version: '1.0',
                key: item.uuid,
                title: item.name,
                children: []
              }
              if (item.wrap.permission === 'true') {
                roles.children = item.menus.map(menu => {
                  return {
                    key: menu.MenuID,
                    title: menu.name
                  }
                })
              } else {
                roles.pass = true
              }
              let _param = {
                func: 'sPC_TrdMenu_AddUpt',
                FstID: 'mk_app',
                SndID: 'mk_app',
                ParentID: 'mk_app',
                MenuID: item.uuid,
                MenuNo: item.wrap.MenuNo || Utils.getuuid(),
                EasyCode: '',
                Template: item.type,
                TypeCharOne: sessionStorage.getItem('kei_no'),
                Typename: sessionStorage.getItem('typename'),
                MenuName: item.name || '',
                PageParam: JSON.stringify({Template: item.type}),
                open_edition: _item ? (_item.open_edition || '') : '',
                menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
                LText: '',
                LTexttb: ''
              }
              _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(item)))
              _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
              _param.secretkey = Utils.encrypt('', _param.timestamp)
              Api.getSystemConfig(_param).then(res => {
                if (!res.status) {
                  notification.warning({
                    top: 92,
                    message: res.message,
                    duration: 5
                  })
                  this.setState({ menuloading: false })
                  return
                }
                new_open_edition[item.uuid] = res.open_edition || ''
                resolve()
              })
            })
          })
          Promise.all(deffers).then(() => {
            let appViewList = sessionStorage.getItem('appViewList')
            appViewList = JSON.parse(appViewList)
            let _appViewList = fromJS(appViewList).toJS()
            let appIndeList = appViewList.map(item => item.keys_id).join(',')
            config.components = config.components.map(item => {
              if (item.type === 'navbar') {
                item.open_edition = new_open_edition[item.uuid] || ''
                window.GLOB.CacheIndependent.set(item.uuid, fromJS(item).toJS())
                if (appIndeList.indexOf(item.uuid) === -1) {
                  appViewList.unshift({
                    appkey: window.GLOB.appkey || '',
                    bid: sessionStorage.getItem('appId') || '',
                    kei_no: sessionStorage.getItem('kei_no') || '',
                    keys_id: item.uuid,
                    keys_type: 'navbar',
                    remark: item.name
                  })
                } else {
                  appViewList = appViewList.map(view => {
                    if (view.keys_id === item.uuid) {
                      view.remark = item.name
                    }
                    return view
                  })
                }
              }
              return item
            })
            if (!is(fromJS(appViewList), fromJS(_appViewList))) {
              let param = {
                func: 's_kei_link_keyids_addupt',
                BID: sessionStorage.getItem('appId'),
                exec_type: 'y',
                LText: ''
              }
          let _item = window.GLOB.CacheIndependent.get(NavBar.uuid) || {}
          NavBar.open_edition = _item.open_edition || ''
          if (is(fromJS(_item), fromJS(NavBar))) {
            resolve({status: true})
          } else {
            let roles = {
              type: 'navbar',
              version: '1.0',
              key: NavBar.uuid,
              title: NavBar.name,
              children: []
            }
    
              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)
              param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
              param.secretkey = Utils.encrypt('', param.timestamp)
              Api.getSystemConfig(param).then(result => {
                if (!result.status) {
                  notification.warning({
                    top: 92,
                    message: result.message,
                    duration: 5
                  })
                  this.setState({ menuloading: false })
                } else {
                  sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
                  resolve(true)
            if (NavBar.wrap.permission === 'true') {
              roles.children = NavBar.menus.map(menu => {
                return {
                  key: menu.MenuID,
                  title: menu.name
                }
              })
            } else {
              resolve(true)
              roles.pass = true
            }
          })
            let _param = {
              func: 'sPC_TrdMenu_AddUpt',
              FstID: 'mk_app',
              SndID: 'mk_app',
              ParentID: 'mk_app',
              MenuID: NavBar.uuid,
              MenuNo: NavBar.wrap.MenuNo || Utils.getuuid(),
              EasyCode: '',
              Template: NavBar.type,
              TypeCharOne: sessionStorage.getItem('kei_no'),
              Typename: sessionStorage.getItem('typename'),
              MenuName: NavBar.name || '',
              PageParam: JSON.stringify({Template: NavBar.type}),
              open_edition: _item ? (_item.open_edition || '') : '',
              menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
              LText: '',
              LTexttb: ''
            }
            _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(NavBar)))
            _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
            _param.secretkey = Utils.encrypt('', _param.timestamp)
            Api.getSystemConfig(_param).then(res => {
              if (res.status) {
                NavBar.open_edition = res.open_edition || ''
                window.GLOB.CacheIndependent.set(NavBar.uuid, fromJS(NavBar).toJS())
                let appViewList = sessionStorage.getItem('appViewList')
                let _appViewList = JSON.parse(appViewList)
                let index = _appViewList.findIndex(item => item.keys_id === NavBar.uuid)
                if (index === -1) {
                  _appViewList.unshift({
                    appkey: window.GLOB.appkey || '',
                    bid: sessionStorage.getItem('appId') || '',
                    kei_no: sessionStorage.getItem('kei_no') || '',
                    keys_id: NavBar.uuid,
                    keys_type: 'navbar',
                    remark: NavBar.name
                  })
                } else {
                  _appViewList = _appViewList.map(item => {
                    if (item.keys_id === NavBar.uuid && item.remark !== NavBar.name) {
                      item.remark = NavBar.name
                    }
                    return item
                  })
                }
                let viewList = JSON.stringify(_appViewList)
                if (appViewList !== viewList) {
                  let kparam = {
                    func: 's_kei_link_keyids_addupt',
                    BID: sessionStorage.getItem('appId'),
                    exec_type: 'y',
                    LText: ''
                  }
                  kparam.LText = _appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
                  kparam.LText = kparam.LText.join(' union all ')
                  kparam.LText = Utils.formatOptions(kparam.LText)
                  kparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
                  kparam.secretkey = Utils.encrypt('', kparam.timestamp)
                  Api.getSystemConfig(kparam).then(result => {
                    if (result.status) {
                      sessionStorage.setItem('appViewList', viewList)
                    }
                    resolve(result)
                  })
                } else {
                  resolve(res)
                }
              } else {
                resolve(res)
              }
            })
          }
        }
      }).then(res => { // 页面保存
        if (!res) return
        if (!res || !res.status) return res
        return Api.getSystemConfig(param)
      }).then(res => {
        this.setState({
          menuloading: false
        })
        if (!res) return
        if (res.status) {
          config.open_edition = res.open_edition || ''
          this.setState({
            config,
            oriConfig: fromJS(config).toJS(),
            menuloading: false
            needUpdate: false
          })
          notification.success({
@@ -1581,23 +1479,21 @@
            message: '保存成功',
            duration: 2
          })
          MKEmitter.emit('completeSave')
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          this.setState({
            menuloading: false
          })
        }
        MKEmitter.emit('completeSave')
      })
    }, 300 + (+sessionStorage.getItem('mkDelay')))
  }
  getRoleFields = () => {
    if (sessionStorage.getItem('sysRoles') || sessionStorage.getItem('permFuncField')) return
    if (sessionStorage.getItem('sysRoles')) return
    Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => {
      if (res.status) {
        let _permFuncField = []
@@ -1682,10 +1578,6 @@
    }
    check(config.components, 1, 'view')
    // if (!error && viewType === 'userbind' && config.components.filter(item => item.type === 'login').length === 0) {
    //   error = '用户绑定页面必须添加登录。'
    // }
    if (!error && searchSum > 1) {
      error = '搜索组件与导航栏的搜索功能不可同时使用。'
@@ -1773,7 +1665,7 @@
  refreshView = () => {
    const { oriConfig, config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1793,7 +1685,7 @@
  setHomeView = () => {
    const { oriConfig, config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1852,7 +1744,7 @@
  setLoginView = () => {
    const { oriConfig, config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1946,7 +1838,7 @@
  render () {
    const { viewType, comloading, loading, settingshow, controlshow, activeKey, MenuId, config, menuloading, customComponents, adapters, eyeopen } = this.state
    const { viewType, comloading, loading, settingshow, controlshow, activeKey, MenuId, config, menuloading, adapters, eyeopen, needUpdate } = this.state
    return (
      <ConfigProvider locale={antdZhCN}>
@@ -1982,9 +1874,6 @@
                  <Panel header="元素" key="element">
                    <Modulecell />
                  </Panel>
                  {customComponents && customComponents.length ? <Panel header="自定义组件" className="cuscomponent" key="cuscomponent">
                    <SourceWrap components={customComponents} />
                  </Panel> : null}
                  <Panel header={'页面样式'} key="background">
                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                  </Panel>
@@ -1997,7 +1886,7 @@
                {!controlshow ? <DoubleLeftOutlined onClick={() => {this.setState({controlshow: true})}}/> : null}
              </div>
              <div className="wrap">
                <Button type="primary" onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
                <Button type="primary" className={needUpdate ? 'update-tip' : ''} onClick={this.submitConfig} id="save-config" loading={menuloading}>保存</Button>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config && config.enabled} onChange={this.onEnabledChange} />
                <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
                <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
src/views/mobdesign/index.scss
@@ -9,6 +9,17 @@
      display: none;
    }
  }
  .update-tip::after {
    content: ' ';
    display: inline-block;
    position: absolute;
    top: -4px;
    right: -4px;
    width: 8px;
    height: 8px;
    background-color: red;
    border-radius: 8px;
  }
  .component-name {
    position: absolute;
    z-index: 9;
@@ -304,4 +315,8 @@
body {
  overflow-y: hidden;
}
.user-component-wrap {
  display: none!important;
}
src/views/pcdesign/index.jsx
@@ -10,7 +10,7 @@
import Api from '@/api'
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
// import antdEnUS from 'antd/es/locale/en_US'
import { getTables } from '@/utils/utils-custom.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import MKEmitter from '@/utils/events.js'
import MenuUtils from '@/utils/utils-custom.js'
@@ -24,6 +24,8 @@
const { Paragraph } = Typography
const MenuForm = asyncComponent(() => import('./menuform'))
const Header = asyncComponent(() => import('@/menu/header'))
const PopView = asyncComponent(() => import('@/views/menudesign/popview'))
const Transfer = asyncComponent(() => import('@/pc/transfer'))
const Versions = asyncComponent(() => import('@/menu/versions'))
const MenuShell = asyncComponent(() => import('@/pc/menushell'))
@@ -63,11 +65,13 @@
    menuloading: false,
    oriConfig: null,
    config: null,
    customComponents: [],
    settingshow: sessionStorage.getItem('settingshow') !== 'false',
    controlshow: sessionStorage.getItem('controlshow') !== 'false',
    comloading: false,
    eyeopen: false,
    view: '',
    popConfig: null,
    needUpdate: false
  }
  UNSAFE_componentWillMount() {
@@ -75,7 +79,6 @@
    sessionStorage.setItem('editMenuType', 'menu') // 编辑菜单类型
    window.GLOB.UserComponentMap = new Map() // 缓存用户自定义组件
    window.GLOB.TabsMap = new Map()          // 缓存用户操作的标签页
    window.GLOB.CacheIndependent = new Map()
    window.GLOB.urlFields = []               // url变量
@@ -126,16 +129,8 @@
    MKEmitter.addListener('changePopview', this.initPopview)
    MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
    MKEmitter.addListener('triggerMenuSave', this.triggerMenuSave)
    MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent)
    setTimeout(() => {
      if (sessionStorage.getItem('app_custom_components')) {
        let list = sessionStorage.getItem('app_custom_components')
        list = JSON.parse(list)
        this.setCustomComponent(list)
      } else {
        this.updateCustomComponent()
      }
    setTimeout(() => {
      this.getAppPictures()
      this.getSmStemp()
      this.getRoleFields()
@@ -209,10 +204,11 @@
    MKEmitter.removeListener('changePopview', this.initPopview)
    MKEmitter.removeListener('changeEditMenu', this.changeEditMenu)
    MKEmitter.removeListener('triggerMenuSave', this.triggerMenuSave)
    MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent)
  }
  triggerMenuSave = () => {
    if (this.state.view === 'popview') return
    this.submitConfig()
  }
@@ -432,71 +428,110 @@
    })
  }
  updateCustomComponent = () => {
    Api.getSystemConfig({
      func: 's_get_custom_components',
      typename: 'pc',
      typecharone: ''
    }).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      } else if (res.cus_list) {
        sessionStorage.setItem('app_custom_components', JSON.stringify(res.cus_list))
        this.setCustomComponent(res.cus_list)
      }
    })
  }
  setCustomComponent = (cus_list) => {
    let coms = []
    cus_list.forEach(item => {
      let config = ''
      try {
        config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param)))
      } catch (e) {
        console.warn('Parse Failure')
        config = ''
      }
      if (!config || !item.c_name) return
      window.GLOB.UserComponentMap.set(item.c_id, item.c_name)
      coms.push({
        uuid: item.c_id,
        type: 'menu',
        title: item.c_name,
        url: item.images,
        component: config.type,
        subtype: config.subtype,
        config
      })
    })
    this.setState({customComponents: coms})
  }
  initPopview = (card, btn) => {
    const { oriConfig, config } = this.state
    const { config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
        duration: 5
      })
    if (!this.checkBase()) {
      return
    }
    let _btn = fromJS(btn).toJS()
    _btn.MenuName = config.MenuName + '-' + card.name + '-' + btn.label
    _btn.ParentMenuID = config.uuid
    this.props.history.push('/popdesign/' + window.btoa(window.encodeURIComponent((JSON.stringify(_btn)))))
    if (_btn.config) {
      _btn.config.uuid = _btn.uuid
      _btn.config.MenuID = _btn.uuid
      _btn.config.ParentId = card.uuid
      _btn.config.MenuName = _btn.label
    } else {
      _btn.config = {
        uuid: _btn.uuid,
        MenuID: _btn.uuid,
        ParentId: card.uuid,
        enabled: false,
        MenuName: _btn.label,
        tables: config.tables || [],
        Template: 'CustomPage',
        components: [],
        viewType: 'popview',
        style: { backgroundColor: '#ffffff', backgroundImage: '', paddingTop: '16px', paddingBottom: '40px', paddingLeft: '16px', paddingRight: '16px' }
      }
    }
    this.setState({view: 'popview', popConfig: _btn})
  }
  submitPopConfig = (btnconfig) => {
    let parents = {[btnconfig.ParentId]: true}
    let popbtns = {[btnconfig.uuid]: fromJS(btnconfig).toJS()}
    let config = fromJS(this.state.config).toJS()
    config.components = this.setPopView(config.components, parents, popbtns)
    this.setState({ config }, () => {
      this.submitConfig()
    })
  }
  setPopView = (components, parents, popbtns) => {
    return components.map(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          tab.components = this.setPopView(tab.components, parents, popbtns)
        })
      } else if (item.type === 'group') {
        item.components = this.setPopView(item.components, parents, popbtns)
      } else if (parents[item.uuid]) {
        this.setpopConfig(item, popbtns)
      }
      return item
    })
  }
  setpopConfig = (config, popbtns) => {
    config.subcards && config.subcards.forEach(item => {
      item.elements.forEach(cell => {
        if (cell.eleType !== 'button') return
        if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
          cell.config = popbtns[cell.uuid]
        }
      })
    })
    config.cols && config.cols.forEach(col => {
      if (col.type === 'action') {
        col.elements.forEach(cell => {
          if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
            cell.config = popbtns[cell.uuid]
          }
        })
      }
    })
    config.elements && config.elements.forEach(cell => {
      if (cell.eleType !== 'button') return
      if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
        cell.config = popbtns[cell.uuid]
      }
    })
    config.action && config.action.forEach(cell => {
      if (cell.OpenType === 'popview' && popbtns[cell.uuid]) {
        cell.config = popbtns[cell.uuid]
      }
    })
    config.$tables = getTables(config)
  }
  closePop = () => {
    const {config} = this.state
    sessionStorage.setItem('editMenuType', 'menu')
    window.GLOB.urlFields = config.urlFields || []
    window.GLOB.customMenu = config
    this.setState({view: '', popConfig: null})
  }
  closeView = () => {
@@ -560,7 +595,6 @@
        this.getCopyParam(urlParam)
      } else {
        let config = null
        let isCreate = false
        try {
          config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null
@@ -570,9 +604,8 @@
        }
        if (!config) {
          isCreate = true
          config = {
            version: 1.0,
            version: 2.0,
            uuid: MenuId,
            MenuID: MenuId,
            Template: 'webPage',
@@ -593,27 +626,66 @@
        config.open_edition = result.open_edition || ''
        window.GLOB.urlFields = config.urlFields || []
        let indeComs = []
        if (config.version !== 2.0) {
          config.components = this.collectTB(config.components)
          config.version = 2.0
          this.setState({
            needUpdate: true
          })
        }
        let navItem = null
        config.components.forEach(item => {
          if (item.type === 'navbar') {
            indeComs.push(fromJS(item).toJS())
            navItem = fromJS(item).toJS()
          }
        })
        if (indeComs.length === 0) {
        if (!navItem) {
          this.setState({
            oriConfig: isCreate ? null : config,
            config: fromJS(config).toJS(),
            oriConfig: fromJS(config).toJS(),
            config: config,
            loading: false
          })
          window.GLOB.customMenu = config
        } else {
          this.jointComponents(config, indeComs, isCreate)
          this.jointComponents(config, navItem)
        }
      }
    })
    this.getAppMenus()
  }
  collectTB = (components) => {
    return components.map(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          delete tab.floor
          delete tab.hasSearch
          delete tab.parentId
          tab.components = this.collectTB(tab.components)
        })
      } else if (item.type === 'group') {
        item.components = this.collectTB(item.components)
      } else if (!['search', 'navbar', 'login', 'topbar', 'officialAccount'].includes(item.type)) {
        item.$tables = getTables(item)
      }
      if (item.subtype === 'tablecard') { // 兼容
        item.type = 'card'
      }
      delete item.tabId
      delete item.parentId
      delete item.btnlog
      delete item.floor
      delete item.dataName
      return item
    })
  }
  getAppMenus = () => {
@@ -671,12 +743,6 @@
        })
        this.setState({loading: false})
        return
      } else if (!result.LongParam) {
        notification.warning({
          top: 92,
          message: '未查询到复制菜单配置信息!',
          duration: 5
        })
      }
      let config = null
@@ -687,11 +753,10 @@
        console.warn('Parse Failure')
        config = null
      }
      
      if (!config) {
        config = {
          version: 1.0,
          version: 2.0,
          uuid: MenuId,
          MenuID: MenuId,
          Template: 'webPage',
@@ -715,6 +780,16 @@
          })
        }
        config.components = MenuUtils.resetConfig(config.components, uuids, urlParam.clearMenu)
        if (config.version !== 2.0) {
          config.components = this.collectTB(config.components)
          config.version = 2.0
          this.setState({
            needUpdate: true
          })
        }
        config.enabled = false
        message.success('复制成功,保存后生效。')
      }
@@ -725,52 +800,42 @@
      config.MenuName = urlParam.MenuName || ''
      config.MenuNo = ''
      let indeComs = []
      let navItem = null
      config.components.forEach(item => {
        if (item.type === 'navbar') {
          indeComs.push(fromJS(item).toJS())
          navItem = fromJS(item).toJS()
        }
      })
      if (indeComs.length === 0) {
      if (!navItem) {
        this.setState({
          oriConfig: null,
          config: fromJS(config).toJS(),
          oriConfig: fromJS(config).toJS(),
          config: config,
          loading: false
        })
        window.GLOB.customMenu = config
      } else {
        this.jointComponents(config, indeComs, true)
        this.jointComponents(config, navItem)
      }
    })
  }
  jointComponents = (config, indeComs, isCreate) => {
    let deffers = indeComs.map(item => {
      return new Promise(resolve => {
        Api.getSystemConfig({
          func: 'sPC_Get_LongParam',
          TypeCharOne: sessionStorage.getItem('kei_no'),
          typename: 'pc',
          MenuID: item.uuid
        }).then(res => {
          res.uuid = item.uuid
          if (!res.status) {
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
          resolve(res)
  jointComponents = (config, navItem) => {
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      TypeCharOne: sessionStorage.getItem('kei_no'),
      typename: 'pc',
      MenuID: navItem.uuid
    }).then(res => {
      if (!res.status) {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      })
    })
    Promise.all(deffers).then(result => {
      let _conf = {}
      result.forEach(res => {
        config.components = config.components.filter(item => item.type !== 'navbar')
      } else {
        let _config = null
        try {
          _config = res.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) : null
@@ -781,35 +846,21 @@
        if (_config) {
          _config.open_edition = res.open_edition || ''
          _conf[res.uuid] = _config
          window.GLOB.CacheIndependent.set(res.uuid, fromJS(_config).toJS())
          config.components = config.components.map(item => {
            if (item.type === 'navbar') {
              return _config
            }
            return item
          })
          window.GLOB.CacheIndependent.set(navItem.uuid, fromJS(_config).toJS())
        } else {
          config.components = config.components.filter(item => item.type !== 'navbar')
        }
      })
      let _length = config.components.length
      config.components = config.components.map(item => {
        if (item.type === 'navbar') {
          if (_conf[item.uuid]) {
            item = _conf[item.uuid]
          } else {
            item = null
          }
        }
        return item
      })
      config.components = config.components.filter(Boolean)
      if (_length > config.components.length) {
        notification.warning({
          top: 92,
          message: '部分组件已删除!',
          duration: 5
        })
      }
      this.setState({
        oriConfig: isCreate ? null : fromJS(config).toJS(),
        oriConfig: fromJS(config).toJS(),
        config: config,
        loading: false
      })
@@ -821,7 +872,6 @@
  getMenuMessage = (tbs) => {
    const { config } = this.state
    let nodes = {type: 'view', version: '1.0', key: config.uuid, title: config.MenuName, children: []}
    let popviews = []
    let traversal = (components) => {
      let list = []
@@ -830,14 +880,21 @@
          tbs.push(...item.$tables)
        }
        if (item.plot && item.plot.permission !== 'true') {
          return
        } else if (item.type === 'login' || item.type === 'navbar') {
          return
        } else if (!['tabs', 'group'].includes(item.type) && item.wrap && item.wrap.permission !== 'true') {
          return
        }
        let m = {
          key: item.uuid,
          title: item.name,
          children: []
        }
        if (item.type === 'login' || item.type === 'navbar') {
          return null
        } else if (item.type === 'tabs') {
        if (item.type === 'tabs') {
          let tabs = []
          let mm = []
          item.subtabs.forEach(tab => {
@@ -864,7 +921,7 @@
            list.push(...mm)
          }
          
          return null
          return
        } else if (item.type === 'group') {
          m.children = traversal(item.components)
@@ -874,12 +931,8 @@
            list.push(...m.children)
          }
          
          return null
        } if (item.plot && item.plot.permission !== 'true') {
          return null
        } if (item.wrap && item.wrap.permission !== 'true') {
          return null
        } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
          return
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.action && item.action.forEach(btn => {
            if (btn.hidden === 'true') return
@@ -887,74 +940,34 @@
              key: btn.uuid,
              title: btn.label,
            })
            if (btn.OpenType === 'popview') {
              popviews.push(btn.uuid)
            }
          })
          item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.hidden === 'true') return
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              m.children.push({
                key: cell.uuid,
                title: cell.label,
              })
              if (cell.OpenType === 'popview') {
                popviews.push(cell.uuid)
              }
            })
            card.backElements && card.backElements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.hidden === 'true') return
              if (cell.eleType !== 'button' || cell.hidden === 'true') return
              m.children.push({
                key: cell.uuid,
                title: cell.label,
              })
              if (cell.OpenType === 'popview') {
                popviews.push(cell.uuid)
              }
            })
          })
        } else if (item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.hidden === 'true') return
              m.children.push({
                key: cell.uuid,
                title: cell.label,
              })
              if (cell.OpenType === 'popview') {
                popviews.push(cell.uuid)
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType !== 'button') return
            if (cell.hidden === 'true') return
            if (cell.eleType !== 'button' || cell.hidden === 'true') return
            m.children.push({
              key: cell.uuid,
              title: cell.label,
            })
            if (cell.OpenType === 'popview') {
              popviews.push(cell.uuid)
            }
          })
        } else if (item.type === 'menubar') {
          if (item.wrap.title) {
            m.title = item.wrap.title
          }
          m.children = item.subMenus.map(menu => {
            return {
              key: menu.uuid,
              title: menu.setting.name
            }
          })
        } else if (item.type === 'form') {
          if (item.subtype !== 'simpleform') {
@@ -965,19 +978,16 @@
              }
            })
          }
        } else if (item.type === 'table' && (item.subtype === 'normaltable' || item.subtype === 'editable')) {
          item.action && item.action.forEach(btn => {
        } else if (item.type === 'table') {
          item.action.forEach(btn => {
            if (btn.hidden === 'true') return
            m.children.push({
              key: btn.uuid,
              title: btn.label,
            })
            if (btn.OpenType === 'popview') {
              popviews.push(btn.uuid)
            }
          })
          item.cols && item.cols.forEach(col => {
          item.cols.forEach(col => {
            if (col.type !== 'action') return
            col.elements.forEach(btn => {
              if (btn.hidden === 'true') return
@@ -986,9 +996,6 @@
                key: btn.uuid,
                title: btn.label,
              })
              if (btn.OpenType === 'popview') {
                popviews.push(btn.uuid)
              }
            })
          })
        }
@@ -1002,7 +1009,6 @@
    let trees = traversal(config.components)
    nodes.children = trees
    nodes.popviews = popviews
    if (config.components.findIndex(item => item.type === 'login') > -1) {
      nodes.login = true
@@ -1010,6 +1016,14 @@
    }
    if (nodes.children.length === 0) {
      nodes.pass = true
    }
    if (config.interfaces) {
      config.interfaces.forEach(item => {
        if (item.$tables) {
          tbs.push(...item.$tables)
        }
      })
    }
    return nodes
@@ -1037,7 +1051,7 @@
          })
        } else if (item.type === 'group') {
          traversal(item.components)
        } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
        } else if (item.type === 'card' || item.type === 'carousel' || item.type === 'timeline') {
          item.action && item.action.forEach(btn => {
            if (btn.linkmenu && menuObj[btn.linkmenu]) {
              menus.push(menuObj[btn.linkmenu])
@@ -1065,21 +1079,6 @@
              }
            })
          })
        } else if (item.type === 'carousel' || item.type === 'timeline') {
          item.subcards.forEach(card => {
            if (card.setting.click === 'menu' && menuObj[card.setting.menu]) {
              menus.push(menuObj[card.setting.menu])
            }
            card.elements && card.elements.forEach(cell => {
              if (cell.eleType !== 'button') return
              if (cell.linkmenu && menuObj[cell.linkmenu]) {
                menus.push(menuObj[cell.linkmenu])
              } else if (cell.openmenu && menuObj[cell.openmenu]) {
                menus.push(menuObj[cell.openmenu])
              }
            })
          })
        } else if (item.type === 'balcony') {
          item.elements && item.elements.forEach(cell => {
            if (cell.eleType !== 'button') return
@@ -1096,7 +1095,7 @@
              menus.push(menuObj[m.subButton.linkmenu])
            }
          })
        } else if (item.type === 'table' && item.subtype === 'normaltable') {
        } else if (item.type === 'table') {
          item.action && item.action.forEach(btn => {
            if (btn.linkmenu && menuObj[btn.linkmenu]) {
              menus.push(menuObj[btn.linkmenu])
@@ -1130,8 +1129,8 @@
    return menus
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
  checkBase = () => {
    const { config } = this.state
    if (!config.MenuName || !config.MenuNo || (config.cacheUseful === 'true' && !config.cacheTime)) {
      notification.warning({
@@ -1144,6 +1143,15 @@
        settingshow: true,
        activeKey: 'basedata'
      })
      return false
    }
    return true
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
    if (!this.checkBase()) {
      return
    }
@@ -1227,192 +1235,159 @@
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt('', param.timestamp)
      new Promise(resolve => {
        let _config = fromJS(config).toJS()
        let indeComs = []
        _config.components = _config.components.map(item => {
          if (item.type === 'navbar') {
            indeComs.push(item)
            return {
              type: 'navbar',
              uuid: item.uuid
            }
      let _config = fromJS(config).toJS()
      let NavBar = null
      _config.components = _config.components.map(item => {
        if (item.type === 'navbar') {
          NavBar = fromJS(item).toJS()
          return {
            type: 'navbar',
            uuid: item.uuid
          }
          return item
        })
        }
        return item
      })
        param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
      param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config)))
        if (indeComs.length === 0) {
          resolve(true)
      new Promise(resolve => {
        if (!NavBar) {
          resolve({status: true})
        } else {
          let new_open_edition = {}
          let deffers = indeComs.map(item => {
            return new Promise(resolve => {
              let _item = window.GLOB.CacheIndependent.get(item.uuid)
              if (_item && is(fromJS(_item), fromJS(item))) {
                new_open_edition[item.uuid] = item.open_edition || ''
                resolve()
                return
              }
          let _item = window.GLOB.CacheIndependent.get(NavBar.uuid) || {}
          NavBar.open_edition = _item.open_edition || ''
          if (is(fromJS(_item), fromJS(NavBar))) {
            resolve({status: true})
          } else {
            let roles = {
              type: 'navbar',
              version: '1.0',
              key: NavBar.uuid,
              title: NavBar.name,
              children: []
            }
              let roles = {
                type: 'navbar',
                version: '1.0',
                key: item.uuid,
                title: item.name,
                children: []
              }
              if (item.wrap.permission === 'true') {
                roles.children = item.menus.map(fst => {
                  if (fst.property === 'classify' && fst.sublist.length > 0) {
                    return {
                      key: fst.MenuID,
                      title: fst.name,
                      children: fst.sublist.map(scd => {
                        if (scd.property === 'classify' && scd.sublist.length > 0) {
                          return {
                            key: scd.MenuID,
                            title: scd.name,
                            children: scd.sublist.map(thd => {
                              return { key: thd.MenuID, title: thd.name }
                            })
                          }
                        } else {
                          return { key: scd.MenuID, title: scd.name }
            if (NavBar.wrap.permission === 'true') {
              roles.children = NavBar.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: fst.MenuID, title: fst.name }
                      } else {
                        return { key: scd.MenuID, title: scd.name }
                      }
                    })
                  }
                })
              } else {
                roles.pass = true
              }
              let _param = {
                func: 'sPC_TrdMenu_AddUpt',
                FstID: 'mk_app',
                SndID: 'mk_app',
                ParentID: 'mk_app',
                MenuID: item.uuid,
                MenuNo: item.wrap.MenuNo || Utils.getuuid(),
                EasyCode: '',
                Template: item.type,
                TypeCharOne: sessionStorage.getItem('kei_no'),
                Typename: 'pc',
                MenuName: item.name || '',
                PageParam: JSON.stringify({Template: item.type}),
                menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
                open_edition: item.open_edition || '',
                LText: '',
                LTexttb: ''
              }
              _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(item)))
              _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
              _param.secretkey = Utils.encrypt('', _param.timestamp)
              Api.getSystemConfig(_param).then(res => {
                if (!res.status) {
                  notification.warning({
                    top: 92,
                    message: res.message,
                    duration: 5
                  })
                  this.setState({ menuloading: false })
                  return
                }
                new_open_edition[item.uuid] = res.open_edition || ''
                resolve()
              })
            })
          })
          Promise.all(deffers).then(() => {
            let appViewList = sessionStorage.getItem('appViewList')
            appViewList = JSON.parse(appViewList)
            let _appViewList = fromJS(appViewList).toJS()
            let appIndeList = appViewList.map(item => item.keys_id).join(',')
            config.components = config.components.map(item => {
              if (item.type === 'navbar') {
                item.open_edition = new_open_edition[item.uuid] || ''
                window.GLOB.CacheIndependent.set(item.uuid, fromJS(item).toJS())
                if (appIndeList.indexOf(item.uuid) === -1) {
                  appViewList.unshift({
                    appkey: window.GLOB.appkey || '',
                    bid: sessionStorage.getItem('appId') || '',
                    kei_no: sessionStorage.getItem('kei_no') || '',
                    keys_id: item.uuid,
                    keys_type: 'navbar',
                    remark: item.name
                  })
                } else {
                  appViewList = appViewList.map(view => {
                    if (view.keys_id === item.uuid) {
                      view.remark = item.name
                    }
                    return view
                  })
                }
              }
              return item
            })
            if (!is(fromJS(appViewList), fromJS(_appViewList))) {
              let kparam = {
                func: 's_kei_link_keyids_addupt',
                BID: sessionStorage.getItem('appId'),
                exec_type: 'y',
                LText: ''
              }
              kparam.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
              kparam.LText = kparam.LText.join(' union all ')
              kparam.LText = Utils.formatOptions(kparam.LText)
              kparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
              kparam.secretkey = Utils.encrypt('', kparam.timestamp)
              Api.getSystemConfig(kparam).then(result => {
                if (!result.status) {
                  notification.warning({
                    top: 92,
                    message: result.message,
                    duration: 5
                  })
                  this.setState({ menuloading: false })
                } else {
                  sessionStorage.setItem('appViewList', JSON.stringify(appViewList))
                  resolve(true)
                  return { key: fst.MenuID, title: fst.name }
                }
              })
            } else {
              resolve(true)
              roles.pass = true
            }
          })
        }
      }).then(res => { // 按钮或菜单删除
        if (!res) return
            let _param = {
              func: 'sPC_TrdMenu_AddUpt',
              FstID: 'mk_app',
              SndID: 'mk_app',
              ParentID: 'mk_app',
              MenuID: NavBar.uuid,
              MenuNo: NavBar.wrap.MenuNo || Utils.getuuid(),
              EasyCode: '',
              Template: NavBar.type,
              TypeCharOne: sessionStorage.getItem('kei_no'),
              Typename: 'pc',
              MenuName: NavBar.name || '',
              PageParam: JSON.stringify({Template: NavBar.type}),
              menus_rolelist: window.btoa(window.encodeURIComponent(JSON.stringify(roles))),
              open_edition: NavBar.open_edition,
              LText: '',
              LTexttb: ''
            }
            _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(NavBar)))
            _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
            _param.secretkey = Utils.encrypt('', _param.timestamp)
            Api.getSystemConfig(_param).then(res => {
              if (res.status) {
                NavBar.open_edition = res.open_edition || ''
                window.GLOB.CacheIndependent.set(NavBar.uuid, fromJS(NavBar).toJS())
                let appViewList = sessionStorage.getItem('appViewList')
                let _appViewList = JSON.parse(appViewList)
                let index = _appViewList.findIndex(item => item.keys_id === NavBar.uuid)
                if (index === -1) {
                  _appViewList.unshift({
                    appkey: window.GLOB.appkey || '',
                    bid: sessionStorage.getItem('appId') || '',
                    kei_no: sessionStorage.getItem('kei_no') || '',
                    keys_id: NavBar.uuid,
                    keys_type: 'navbar',
                    remark: NavBar.name
                  })
                } else {
                  _appViewList = _appViewList.map(item => {
                    if (item.keys_id === NavBar.uuid && item.remark !== NavBar.name) {
                      item.remark = NavBar.name
                    }
                    return item
                  })
                }
                let viewList = JSON.stringify(_appViewList)
                if (appViewList !== viewList) {
                  let kparam = {
                    func: 's_kei_link_keyids_addupt',
                    BID: sessionStorage.getItem('appId'),
                    exec_type: 'y',
                    LText: ''
                  }
                  kparam.LText = _appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`)
                  kparam.LText = kparam.LText.join(' union all ')
                  kparam.LText = Utils.formatOptions(kparam.LText)
                  kparam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
                  kparam.secretkey = Utils.encrypt('', kparam.timestamp)
                  Api.getSystemConfig(kparam).then(result => {
                    if (result.status) {
                      sessionStorage.setItem('appViewList', viewList)
                    }
                    resolve(result)
                  })
                } else {
                  resolve(res)
                }
              } else {
                resolve(res)
              }
            })
          }
        }
      }).then(res => { // 页面保存
        if (!res) return
        if (!res || !res.status) return res
        if (res.status) {
          return Api.getSystemConfig(param)
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          return false
        }
      }).then(res => { // 页面按钮关系保存
        return Api.getSystemConfig(param)
      }).then(res => {
        this.setState({
          menuloading: false
        })
        if (!res) return
        if (res.status) {
@@ -1421,45 +1396,22 @@
          this.setState({
            config,
            oriConfig: fromJS(config).toJS(),
            needUpdate: false
          })
          return {
            status: true
          }
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          return false
        }
      }).then(res => { // 按钮复制
        if (!res) return
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
          return false
        }
      }).then(res => {
        if (res && res.status) {
          this.setState({
            menuloading: false
          })
          notification.success({
            top: 92,
            message: '保存成功',
            duration: 2
          })
          MKEmitter.emit('completeSave')
        } else {
          this.setState({
            menuloading: false
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
        MKEmitter.emit('completeSave')
      })
    }, 300 + (+sessionStorage.getItem('mkDelay')))
  }
@@ -1585,9 +1537,7 @@
  }
  refreshView = () => {
    const { oriConfig, config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(this.state.oriConfig || {}), fromJS(this.state.config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1605,9 +1555,9 @@
  }
  setHomeView = () => {
    const { oriConfig, config } = this.state
    const { config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(this.state.oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1664,9 +1614,9 @@
  }
  setLoginView = () => {
    const { oriConfig, config } = this.state
    const { config } = this.state
    if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) {
    if (!is(fromJS(this.state.oriConfig || {}), fromJS(config || {}))) {
      notification.warning({
        top: 92,
        message: '配置信息未保存!',
@@ -1725,13 +1675,13 @@
  }
  render () {
    const { loading, comloading, activeKey, settingshow, controlshow, MenuId, config, menuloading, customComponents, eyeopen } = this.state
    const { view, loading, comloading, activeKey, settingshow, controlshow, MenuId, config, menuloading, eyeopen, needUpdate } = this.state
    return (
      <ConfigProvider locale={antdZhCN}>
        <div className={'mk-pc-view '} id="mk-pc-design-view">
          {loading ? <Spin className="view-spin" size="large" /> : null}
          <DndProvider backend={HTML5Backend}>
        <DndProvider backend={HTML5Backend}>
          {view !== 'popview' ?<div className={'mk-pc-view '} id="mk-pc-design-view">
            {loading ? <Spin className="view-spin" size="large" /> : null}
            <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
              <div className="draw">
                {settingshow ? <DoubleLeftOutlined onClick={() => {sessionStorage.setItem('settingshow', 'false'); this.setState({settingshow: false})}}/> : null}
@@ -1759,9 +1709,6 @@
                  <Panel header="元素" key="element">
                    <Modulecell />
                  </Panel>
                  {customComponents && customComponents.length ? <Panel header="自定义组件" key="cuscomponent">
                    <SourceWrap components={customComponents} />
                  </Panel> : null}
                  <Panel header={'页面样式'} key="background">
                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                  </Panel>
@@ -1774,7 +1721,7 @@
                {!controlshow ? <DoubleLeftOutlined onClick={() => {sessionStorage.setItem('controlshow', 'true'); this.setState({controlshow: true})}}/> : null}
              </div>
              <div className="wrap">
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={menuloading}>保存</Button>
                <Button type="primary" className={needUpdate ? 'update-tip' : ''} id="save-config" onClick={this.submitConfig} loading={menuloading}>保存</Button>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config && config.enabled} onChange={this.onEnabledChange} />
                <ArrowLeftOutlined title="后退" className="back-view" onClick={this.backView}/>
                <Button className="mk-border-purple" onClick={() => this.setState({eyeopen: !eyeopen})}>{!eyeopen ? <EyeOutlined /> : <EyeInvisibleOutlined />} 组件名</Button>
@@ -1798,11 +1745,14 @@
            <div className={'menu-body menu-view' + (menuloading ? ' saving' : '') + (eyeopen ? ' eye-open' : '')}>
              {config && !comloading ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
            </div>
          </DndProvider>
          <StyleController />
          <StyleCombController />
          <ModalController />
        </div>
          </div> : <>
            <Header/>
            <PopView btn={this.state.popConfig} save={this.submitPopConfig} cancel={this.closePop}/>
          </>}
        </DndProvider>
        <StyleController />
        <StyleCombController />
        <ModalController />
      </ConfigProvider>
    )
  }
src/views/pcdesign/index.scss
@@ -13,6 +13,17 @@
      display: none;
    }
  }
  .update-tip::after {
    content: ' ';
    display: inline-block;
    position: absolute;
    top: -4px;
    right: -4px;
    width: 8px;
    height: 8px;
    background-color: red;
    border-radius: 8px;
  }
  .component-name {
    position: absolute;
    z-index: 9;
@@ -251,4 +262,7 @@
body {
  overflow-y: hidden;
}
.user-component-wrap {
  display: none!important;
}
src/views/popdesign/index.jsx
File was deleted
src/views/popdesign/menuform/index.jsx
File was deleted
src/views/popdesign/menuform/index.scss
src/views/rolemanage/index.jsx
@@ -398,10 +398,6 @@
      lang: app.lang
    }
    if (app.typename === 'pc' && record.nodes && record.nodes.popviews && record.nodes.popviews.length > 0) {
      param.MenuID = param.MenuID + ',' + record.nodes.popviews.join(',')
    }
    let _param = {
      func: 's_kei_link_keyids_addupt',
      BID: app.ID,
@@ -537,10 +533,6 @@
                  }
                  delete item.menus_rolelist
                }
                if (targetKeys.includes(item.MenuID) && item.nodes && item.nodes.popviews && item.nodes.popviews.length > 0) {
                  list = [...list, ...item.nodes.popviews]
                }
                
                return item
src/views/systemfunc/sidemenu/config.jsx
@@ -32,13 +32,13 @@
    MenuID: '1583979633842550imkchl4qt4qppsiv',
    MenuNo: 'sVersionMUpgrade',
    MenuName: '版本升级',
  }, {
    src: '',
    PageParam: {OpenType: 'newtab', Template: 'TabManage'},
    type: 'TabManage',
    MenuID: 'TabManageView',
    MenuNo: 'TabManage',
    MenuName: '标签页管理',
  // }, {
  //   src: '',
  //   PageParam: {OpenType: 'newtab', Template: 'TabManage'},
  //   type: 'TabManage',
  //   MenuID: 'TabManageView',
  //   MenuNo: 'TabManage',
  //   MenuName: '标签页管理',
  }, {
    src: '',
    PageParam: {OpenType: 'newtab', Template: 'CommonTable'},
src/views/tabledesign/index.jsx
@@ -12,6 +12,7 @@
import Utils, { setGLOBFuncs } from '@/utils/utils.js'
import antdZhCN from 'antd/es/locale/zh_CN'
import MKEmitter from '@/utils/events.js'
import { getTables } from '@/utils/utils-custom.js'
import SourceElement from '@/templates/zshare/dragsource'
import asyncComponent from '@/utils/asyncComponent'
import Source from './source'
@@ -25,6 +26,7 @@
const _locale = antdZhCN
const MenuForm = asyncComponent(() => import('./menuform'))
const PopView = asyncComponent(() => import('./popview'))
const TableNodes = asyncComponent(() => import('@/menu/tablenodes'))
const TableSource = asyncComponent(() => import('./tablesource'))
const Header = asyncComponent(() => import('@/menu/header'))
@@ -55,6 +57,8 @@
    config: null,
    comloading: false,
    settingshow: true,
    view: null,
    popConfig: null
  }
  UNSAFE_componentWillMount() {
@@ -141,6 +145,9 @@
        let node = document.getElementById('save-modal-config')
        if (!node) {
          node = document.getElementById('save-pop-config')
        }
        if (!node) {
          node = document.getElementById('save-config')
        }
@@ -164,6 +171,8 @@
  }
  triggerMenuSave = () => {
    if (this.state.view === 'popview') return
    this.submitConfig()
  }
@@ -212,22 +221,101 @@
  }
  initPopview = (card, btn) => {
    const { oriConfig, config } = this.state
    const { config } = this.state
    if (!is(fromJS(oriConfig), fromJS(config))) {
      notification.warning({
        top: 92,
        message: '配置已修改,请保存!',
        duration: 5
      })
    if (!this.checkBase()) {
      return
    }
    let _btn = fromJS(btn).toJS()
    _btn.MenuName = config.MenuName + '-' + card.name + '-' + btn.label
    _btn.ParentMenuID = config.uuid
    this.props.history.push('/popdesign/' + window.btoa(window.encodeURIComponent((JSON.stringify(_btn)))))
    if (_btn.config) {
      _btn.config.uuid = _btn.uuid
      _btn.config.MenuID = _btn.uuid
      _btn.config.ParentId = card.uuid
      _btn.config.MenuName = _btn.label
    } else {
      _btn.config = {
        uuid: _btn.uuid,
        MenuID: _btn.uuid,
        ParentId: card.uuid,
        enabled: false,
        MenuName: _btn.label,
        tables: config.tables || [],
        Template: 'BaseTable',
        components: [{
          uuid: Utils.getuuid(),
          type: 'table',
          width: 24,
          name: '主表',
          subtype: 'basetable',
          isNew: true
        }],
        viewType: 'popview',
        style: { backgroundColor: '#ffffff', backgroundImage: '', paddingTop: '16px', paddingBottom: '40px', paddingLeft: '16px', paddingRight: '16px' }
      }
    }
    this.setState({view: 'popview', popConfig: _btn})
  }
  submitPopConfig = (btnconfig) => {
    let config = fromJS(this.state.config).toJS()
    config.components.forEach(item => {
      if (item.type === 'tabs') {
        item.subtabs.forEach(tab => {
          if (btnconfig.ParentId !== tab.components[0].uuid) return
          tab.components[0].action.forEach(btn => {
            if (btn.OpenType === 'popview' && btn.uuid === btnconfig.uuid) {
              btn.config = btnconfig
            }
          })
          tab.components[0].cols.forEach(col => {
            if (col.type !== 'action') return
            col.elements.forEach(btn => {
              if (btn.OpenType === 'popview' && btn.uuid === btnconfig.uuid) {
                btn.config = btnconfig
              }
            })
          })
          tab.components[0].$tables = getTables(tab.components[0])
        })
      } else if (item.uuid === btnconfig.ParentId) {
        item.action.forEach(btn => {
          if (btn.OpenType === 'popview' && btn.uuid === btnconfig.uuid) {
            btn.config = btnconfig
          }
        })
        item.cols.forEach(col => {
          if (col.type !== 'action') return
          col.elements.forEach(btn => {
            if (btn.OpenType === 'popview' && btn.uuid === btnconfig.uuid) {
              btn.config = btnconfig
            }
          })
        })
        item.$tables = getTables(item)
      }
    })
    this.setState({ config }, () => {
      this.submitConfig()
    })
  }
  closePop = () => {
    const { config } = this.state
    sessionStorage.setItem('editMenuType', 'menu')
    window.GLOB.urlFields = config.urlFields || []
    window.GLOB.customMenu = config
    this.setState({view: '', popConfig: null})
  }
  closeView = () => {
@@ -392,8 +480,8 @@
    return buttons
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
  checkBase = () => {
    const { config } = this.state
    if (!config.MenuName || !config.MenuNo || !config.fstMenuId || !config.parentId) {
      notification.warning({
@@ -401,6 +489,15 @@
        message: '请完善菜单基本信息!',
        duration: 5
      })
      return false
    }
    return true
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
    if (!this.checkBase()) {
      return
    }
@@ -495,6 +592,7 @@
          localStorage.setItem('menuUpdate', new Date().getTime())
        }
        config.open_edition = res.open_edition || ''
        this.setState({
          config,
          oriConfig: fromJS(config).toJS(),
@@ -650,13 +748,13 @@
  }
  render () {
    const { activeKey, comloading, MenuId, config, settingshow, ParentId, menuloading } = this.state
    const { view, activeKey, comloading, MenuId, config, settingshow, ParentId, menuloading } = this.state
    return (
      <ConfigProvider locale={_locale}>
        <div className="pc-table-view">
          <Header />
          <DndProvider backend={HTML5Backend}>
        <Header />
        <DndProvider backend={HTML5Backend}>
        {view !== 'popview' ? <div className="pc-table-view">
            <div className="menu-body">
              <div className={'menu-setting ' + (!settingshow ? 'hidden' : '')}>
                <div className="draw">
@@ -718,10 +816,10 @@
                </Card>
              </div>
            </div>
          </DndProvider>
          <StyleController />
          <ModalController />
        </div>
          </div> : <PopView btn={this.state.popConfig} save={this.submitPopConfig} cancel={this.closePop}/>}
        </DndProvider>
        <StyleController />
        <ModalController />
      </ConfigProvider>
    )
  }
src/views/tabledesign/menuform/index.jsx
@@ -26,7 +26,57 @@
  }
  UNSAFE_componentWillMount () {
    if (sessionStorage.getItem('thdMenuList') && sessionStorage.getItem('fstMenuList')) {
      this.setMenus()
    } else {
      this.getMenus()
    }
  }
  setMenus = () => {
    const { MenuId, config } = this.props
    let menulist = sessionStorage.getItem('fstMenuList')
    let thdMenuList = sessionStorage.getItem('thdMenuList')
    menulist = JSON.parse(menulist)
    thdMenuList = JSON.parse(thdMenuList)
    let thdMenu = null
    thdMenuList.forEach(trd => {
      if (MenuId === trd.MenuID) {
        thdMenu = trd
      }
    })
    let smenulist = []
    if (thdMenu) {
      menulist.forEach(item => {
        if (item.MenuID === thdMenu.FstId) {
          smenulist = item.children
        }
      })
    }
    this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
    this.setState({
      fstMenuId: thdMenu ? thdMenu.FstId : '',
      menulist,
      smenulist
    }, () => {
      this.props.form.setFieldsValue({
        fstMenuId: thdMenu ? thdMenu.FstId : '',
        parentId: thdMenu ? thdMenu.ParentId : ''
      })
    })
  }
  getMenus = () => {
    const { MenuId, config } = this.props
    Api.getSystemConfig({func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}).then(result => {
      if (result.status) {
        let thdMenu = null
@@ -64,12 +114,7 @@
                    value: trd.MenuID,
                    label: trd.MenuName,
                    type: 'CommonTable',
                    // disabled: trd.MenuID === MenuId
                    disabled: false
                  }
                  if (MenuId === trd.MenuID) {
                    thdMenu = trdItem
                  }
                  if (trd.PageParam) {
@@ -79,6 +124,10 @@
                    } catch (e) {
                    }
                  }
                  if (MenuId === trd.MenuID) {
                    thdMenu = trdItem
                  }
                  thdMenuList.push(trdItem)
@@ -93,11 +142,13 @@
        })
        let smenulist = []
        menulist.forEach(item => {
          if (thdMenu && (item.MenuID === thdMenu.FstId)) {
            smenulist = item.children
          }
        })
        if (thdMenu) {
          menulist.forEach(item => {
            if (item.MenuID === thdMenu.FstId) {
              smenulist = item.children
            }
          })
        }
        sessionStorage.setItem('fstMenuList', JSON.stringify(menulist))
        sessionStorage.setItem('thdMenuList', JSON.stringify(thdMenuList))
        this.props.updateConfig({...config, fstMenuId: thdMenu ? thdMenu.FstId : ''})
src/views/tabledesign/popview/index.jsx
New file
@@ -0,0 +1,234 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import PropTypes from 'prop-types'
import { notification, Modal, Collapse, Card, Switch, Button } from 'antd'
import MKEmitter from '@/utils/events.js'
import SourceElement from '@/templates/zshare/dragsource'
import asyncComponent from '@/utils/asyncComponent'
import Source from '../source'
import './index.scss'
const { Panel } = Collapse
const { confirm } = Modal
const MenuShell = asyncComponent(() => import('@/menu/tableshell'))
const ReplaceField = asyncComponent(() => import('@/menu/replaceField'))
const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
class PopViewDesign extends Component {
  static propTpyes = {
    btn: PropTypes.object,
    save: PropTypes.func,
    cancel: PropTypes.func
  }
  state = {
    menuloading: false,
    oriConfig: null,
    config: null,
    comloading: false,
  }
  UNSAFE_componentWillMount() {
    const { btn } = this.props
    sessionStorage.setItem('editMenuType', 'popview')
    let config = fromJS(btn.config).toJS()
    window.GLOB.urlFields = []               // url变量
    window.GLOB.customMenu = config          // 保存菜单信息
    this.setState({config: config, oriConfig: fromJS(config).toJS()})
  }
  componentDidMount () {
    MKEmitter.addListener('completeSave', this.completeSave)
    MKEmitter.addListener('triggerMenuSave', this.submitConfig)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('completeSave', this.completeSave)
    MKEmitter.removeListener('triggerMenuSave', this.submitConfig)
  }
  closeView = () => {
    const { oriConfig, config } = this.state
    if (!is(fromJS(oriConfig), fromJS(config))) {
      const _this = this
      confirm({
        title: '配置已修改,放弃保存吗?',
        content: '',
        onOk() {
          _this.props.cancel()
        },
        onCancel() {}
      })
    } else {
      this.props.cancel()
    }
  }
  completeSave = () => {
    this.setState({
      oriConfig: fromJS(this.state.config).toJS(),
      menuloading: false
    })
  }
  submitConfig = () => {
    let config = fromJS(this.state.config).toJS()
    if (config.cacheUseful === 'true' && !config.cacheTime) {
      notification.warning({
        top: 92,
        message: '请完善缓存设置!',
        duration: 5
      })
      return
    }
    if (config.enabled && this.verifyConfig()) {
      config.enabled = false
    }
    config.$tables = Array.from(new Set(config.components[0].$tables || []))
    this.setState({
      config: config,
      menuloading: true
    })
    window.GLOB.customMenu = config
    this.props.save(fromJS(config).toJS())
  }
  onEnabledChange = () => {
    const { config } = this.state
    if (!config.enabled && this.verifyConfig(true)) {
      return
    }
    this.setState({
      config: {...config, enabled: !config.enabled}
    })
  }
  verifyConfig = (show) => {
    const { config } = this.state
    let error = ''
    if (config.components[0].errors) {
      config.components[0].errors.forEach(err => {
        if (err.level !== 0 || error) return
        error = err.detail
      })
    }
    if (show && error) {
      notification.warning({
        top: 92,
        message: error,
        duration: 5
      })
    }
    return error
  }
  // 更新配置信息
  updateConfig = (config) => {
    this.setState({
      config: config
    })
    window.GLOB.customMenu = config
  }
  resetConfig = (config) => {
    this.setState({
      config,
      comloading: true
    }, () => {
      this.setState({
        comloading: false
      })
    })
    window.GLOB.customMenu = config
  }
  /**
   * @description 更新常用表信息,快捷添加后更新配置信息
   */
  updatetable = (config) => {
    this.setState({ config })
    window.GLOB.customMenu = config
  }
  render () {
    const { comloading, config, menuloading } = this.state
    return (
      <div className="pc-poper-view">
        <div className="menu-body">
          <div className="menu-setting">
            <Collapse accordion defaultActiveKey="basedata" bordered={false}>
              {/* 基本信息 */}
              <Panel header="基本信息" key="basedata">
                {/* 表名添加 */}
                <TableComponent config={config} updatetable={this.updatetable}/>
              </Panel>
              {/* 组件添加 */}
              <Panel header="搜索" key="search">
                {Source.searchItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
              </Panel>
              <Panel header="按钮" key="action">
                {Source.popactionItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
              </Panel>
              <Panel header="显示列" key="cols">
                {Source.columnItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
              </Panel>
              <Panel header="页面样式" key="background">
                <BgController config={config} updateConfig={this.updateConfig} />
              </Panel>
            </Collapse>
          </div>
          <div className={'menu-view' + (menuloading ? ' saving' : '')}>
            <Card title={
              <div> {config.MenuName} </div>
            } bordered={false} extra={
              <div>
                <ReplaceField type="custom" config={config} updateConfig={this.resetConfig}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-pop-config" onClick={this.submitConfig} loading={menuloading}>保存</Button>
                <Button type="default" onClick={this.closeView}>返回</Button>
              </div>
            } style={{ width: '100%' }}>
              {!comloading ? <MenuShell menu={config} handleList={this.updateConfig} /> : null}
            </Card>
          </div>
        </div>
      </div>
    )
  }
}
export default PopViewDesign
src/views/tabledesign/popview/index.scss
src/views/tabledesign/source.jsx
@@ -119,6 +119,58 @@
      $init: true
    }
  ],
  popactionItems: [
    {
      type: 'action',
      label: '弹窗(表单)',
      text: '弹窗(表单)',
      value: 'pop',
      $init: true
    },
    {
      type: 'action',
      label: '提示框',
      text: '提示框',
      value: 'prompt',
      $init: true
    },
    {
      type: 'action',
      label: '直接执行',
      text: '直接执行',
      value: 'exec',
      $init: true
    },
    {
      type: 'action',
      label: '导入Excel',
      text: '导入Excel',
      value: 'excelIn',
      class: 'border-dgreen',
      $init: true
    },
    {
      type: 'action',
      label: '导出Excel',
      text: '导出Excel',
      value: 'excelOut',
      $init: true
    },
    {
      type: 'action',
      label: '标签页',
      text: '标签页',
      value: 'tab',
      $init: true
    },
    {
      type: 'action',
      label: '新页面',
      text: '新页面',
      value: 'innerpage',
      $init: true
    }
  ],
  columnItems: [
    {
      type: 'col',