king
2022-07-27 fbf25a99e0bc643be89b0f9dd0efed7867f1490e
2022-07-27
2 文件已重命名
34个文件已修改
4个文件已添加
2732 ■■■■■ 已修改文件
src/api/index.js 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/thawmenu/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/mob.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/model.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/mob.js 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/model.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/carousel/data-card/options.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/edit-table/columns/tableIn/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/sysinterface/settingform/simplescript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/editfirstmenu/dragelement/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/editfirstmenu/dragelement/index.scss 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/editfirstmenu/index.jsx 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/editfirstmenu/index.scss 79 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/index.jsx 48 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/index.scss 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editsecmenu/index.jsx 385 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editsecmenu/index.scss 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editthdmenu/index.jsx 725 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editthdmenu/index.scss 177 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/editthdmenu/menuform/index.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/index.jsx 377 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/menuelement/card.jsx 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/menuelement/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/menuform/index.jsx 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/menuform/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuform/index.jsx 170 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuplus/index.jsx 309 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuplus/index.scss 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuplus/preview/index.jsx 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/sidemenu/thdmenuplus/preview/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js
@@ -140,12 +140,9 @@
   * @description 微信业务请求
   */
  wxNginxRequest (url, method, param) {
    let _url = window.GLOB.location + ':8080/' + url
    let _url = window.GLOB.location + '/' + url
    if (process.env.NODE_ENV === 'production') {
      _url = document.location.origin + ':8080/' + url
    }
    if (/https/.test(_url)) {
      _url = _url.replace(/:8080/g, ':8443')
      _url = document.location.origin + '/' + url
    }
    
    if (param) {
src/components/thawmenu/index.jsx
@@ -53,7 +53,6 @@
        })
      }
    })
    this.setState({visible: true})
  }
  submit = () => {
src/locales/en-US/mob.js
@@ -20,7 +20,6 @@
  'mob.component': '组件',
  'mob.status.open': '启用',
  'mob.status.change': '切换',
  'mob.status.forbidden': '禁用',
  'mob.basemsg': '基本信息',
  'mob.query.delete': '确定删除吗?',
  'mob.logout.hint': '您确定要退出吗?',
src/locales/en-US/model.js
@@ -41,7 +41,6 @@
  'model.menu.level1': 'Level 1 menu',
  'model.menu.level2': 'Level 2 menu',
  'model.menu.level3': 'Level 3 menu',
  'model.menu.resetorder': 'Are you sure to adjust the menu sequence ?',
  'model.menu.basemsg': 'Please complete the basic information !',
  'header.menu.basedata': 'The basic information',
  'header.menu.table.add': 'Add tables',
@@ -150,7 +149,6 @@
  'model.form.color': 'Color',
  'model.query.delete': '确定删除吗?',
  'header.form.status.change': '状态切换',
  'model.status.forbidden': '禁用',
  'model.status.open': '启用',
  'model.form.funcbutton': 'Function button',
  'model.form.execMode': 'Mode',
src/locales/zh-CN/mob.js
@@ -20,7 +20,6 @@
  'mob.component': '组件',
  'mob.status.open': '启用',
  'mob.status.change': '切换',
  'mob.status.forbidden': '禁用',
  'mob.basemsg': '基本信息',
  'mob.query.delete': '确定删除吗?',
  'mob.logout.hint': '您确定要退出吗?',
src/locales/zh-CN/model.js
@@ -41,7 +41,6 @@
  'model.menu.level1': '一级菜单',
  'model.menu.level2': '二级菜单',
  'model.menu.level3': '三级菜单',
  'model.menu.resetorder': '确认调整菜单顺序吗?',
  'model.menu.basemsg': '请完善菜单基本信息!',
  'header.menu.basedata': '基本信息',
  'header.menu.table.add': '添加表名',
@@ -150,7 +149,6 @@
  'model.form.color': '颜色',
  'model.query.delete': '确定删除吗?',
  'header.form.status.change': '状态切换',
  'model.status.forbidden': '禁用',
  'model.status.open': '启用',
  'model.form.funcbutton': '功能按钮',
  'model.form.execMode': '执行方式',
src/menu/components/carousel/data-card/options.jsx
@@ -59,7 +59,10 @@
      required: false,
      options: [
        {value: 'false', label: '否'},
        {value: 'true', label: '是'},
        {value: 'true', label: '是'}
      ],
      controlFields: [
        {field: 'speed', values: ['true']}
      ]
    },
    {
@@ -67,7 +70,7 @@
      field: 'speed',
      label: '时间间隔',
      initval: wrap.speed || 3,
      tooltip: '使用自动切换时有效,默认为3秒',
      tooltip: '默认为3秒',
      min: 1,
      max: 100,
      precision: 0,
src/menu/components/table/edit-table/columns/tableIn/index.jsx
@@ -80,7 +80,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopTwoTone style={{marginLeft: '5px'}} twoToneColor="#ff4d4f" />
            </div>
          ) :
@@ -133,7 +133,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopTwoTone style={{marginLeft: '5px'}} twoToneColor="#ff4d4f" />
            </div>
          ) :
src/menu/components/table/normal-table/columns/editColumn/formconfig.jsx
@@ -154,7 +154,6 @@
      label: Formdict['model.sort'],
      initVal: card.IsSort || (card.isSub ? 'false' : 'true'),
      required: true,
      // forbidden: card.isSub,
      options: [{
        value: 'true',
        text: Formdict['model.true']
src/menu/datasource/verifycard/index.jsx
@@ -127,7 +127,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/menu/sysinterface/settingform/simplescript/index.jsx
@@ -66,7 +66,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopTwoTone style={{marginLeft: '5px'}} twoToneColor="#ff4d4f" />
            </div>
          ) :
src/templates/comtableconfig/index.jsx
@@ -79,9 +79,6 @@
    if (!_LongParam) {
      _config = fromJS(Source.baseConfig).toJS()
      if (!menu.isSubtable) { // 不是选择主子表时,隐藏标签页
        _config.tabgroups = [{ uuid: 'tabs', sublist: [] }]
      }
      _config.isAdd = true
    } else {
      _config = _LongParam
src/templates/sharecomponent/actioncomponent/verifyexcelin/index.jsx
@@ -155,7 +155,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -206,7 +206,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/templates/sharecomponent/actioncomponent/verifyexcelout/index.jsx
@@ -155,7 +155,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
@@ -70,7 +70,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/templates/zshare/customscript/index.jsx
@@ -58,7 +58,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/templates/zshare/verifycard/index.jsx
@@ -108,7 +108,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -144,7 +144,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -218,7 +218,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -270,7 +270,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -339,7 +339,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -406,7 +406,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
@@ -507,7 +507,7 @@
        render: (text, record) => record.status === 'false' ?
          (
            <div style={{color: '#ff4d4f'}}>
              {this.props.dict['model.status.forbidden']}
              禁用
              <StopOutlined style={{marginLeft: '5px'}} />
            </div>
          ) :
src/utils/option.js
@@ -1,7 +1,7 @@
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import nortable from '@/assets/img/normaltable.jpg'
import mainsubtable from '@/assets/img/mainsubtable.jpg'
// import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
import customImg from '@/assets/img/custom.jpg'
@@ -55,14 +55,14 @@
    baseconfig: '',
    isSystem: true
  },
  {
    title: '主子表表格',
    type: 'CommonTable',
    url: mainsubtable,
    baseconfig: '',
    isSystem: true,
    isSubtable: true
  },
  // {
  //   title: '主子表表格',
  //   type: 'CommonTable',
  //   url: mainsubtable,
  //   baseconfig: '',
  //   isSystem: true,
  //   isSubtable: true
  // },
  {
    title: '自定义',
    type: 'CustomPage',
src/views/design/header/editfirstmenu/dragelement/index.jsx
@@ -64,7 +64,7 @@
          findCard={findCard}
        />
      ))}
      <Button type="primary" disabled={!change} onClick={confirm}>保存</Button>
      <Button type="primary" className="mk-save-menu" disabled={!change} onClick={confirm}>保存</Button>
      <Button onClick={cancel}>关闭</Button>
    </div>
  )
src/views/design/header/editfirstmenu/dragelement/index.scss
@@ -12,11 +12,7 @@
    padding: 0 10px;
    height: 26px;
  }
  .ant-btn-primary[disabled] {
    background-color: #f5f5f5 !important;
    border-color: #d9d9d9 !important;
    color: rgba(0, 0, 0, 0.35) !important;
  }
  .btn-group {
    display: inline-block;
  }
src/views/design/header/editfirstmenu/index.jsx
@@ -10,7 +10,7 @@
import MenuForm from './menuform'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import './index.scss'
// import './index.scss'
const { confirm } = Modal
@@ -37,19 +37,20 @@
  editMenuModal = (Menu) => {
    // 菜单编辑:修改
    const menu = fromJS(Menu).toJS()
    if (!is(fromJS(this.state.menulist), fromJS(this.props.menulist))) {
    if (this.state.change) {
      notification.warning({
        top: 92,
        message: '菜单顺序已调整,请保存!',
        duration: 5
      })
    } else {
      this.setState({
        visible: true,
        editMenu: menu.card,
        loading: false
      })
      return
    }
    this.setState({
      visible: true,
      editMenu: menu.card,
      loading: false
    })
  }
  editMemuSubmit = () => {
@@ -82,6 +83,15 @@
  }
  deleteMemu = (item) => {
    if (this.state.change) {
      notification.warning({
        top: 92,
        message: '菜单顺序已调整,请保存!',
        duration: 5
      })
      return
    }
    let _this = this
    confirm({
      title: `确定删除菜单《${item.MenuName}》吗?`,
@@ -173,7 +183,7 @@
    const { menulist, change } = this.state
    return (
      <div className="header-edit-box">
      <>
        <DndProvider backend={HTML5Backend}>
          <DragElement
            change={change}
@@ -199,7 +209,7 @@
            wrappedComponentRef={(inst) => this.editMenuFormRef = inst}
          />
        </Modal>
      </div>
      </>
    )
  }
}
src/views/design/header/editfirstmenu/index.scss
@@ -1,79 +0,0 @@
.header-edit-box {
  .mask {
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    .tipcard {
      position: absolute;
      min-height: 100px;
      font-size: 16px;
      border-radius: 6px;
      background-size: 100% 100%;
      background-repeat: no-repeat;
      padding: 15px;
    }
    .card1 {
      left: 30%;
      top: 20vh;
      width: 230px;
      min-height: 100px;
      color: #000000;
      font-style: oblique;
    }
    .card2 {
      left: 60%;
      top: 20vh;
      width: 230px;
      min-height: 100px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card3 {
      left: 30%;
      top: 50vh;
      width: 230px;
      min-height: 140px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card4 {
      left: 60%;
      top: 50vh;
      width: 230px;
      min-height: 140px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card5 {
      right: 5%;
      top: 20vh;
      width: 130px;
      min-height: 240px;
      color: #000000;
      padding: 40px 15px 10px;
      p {
        margin: 0 0 5px;
      }
      div {
        text-align: center;
        .new-view {
          display: inline-block;
          cursor: pointer;
          color: #fff;
          padding: 2px 10px;
          border-radius: 4px;
          background-color: #1890ff;
          border-color: #1890ff;
          text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
          -webkit-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
          box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
        }
      }
    }
  }
}
src/views/design/header/index.jsx
@@ -1,7 +1,6 @@
import React, {Component} from 'react'
import { withRouter } from 'react-router-dom'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { Dropdown, Menu, Modal, notification, Switch, Button, Popover } from 'antd'
import { MenuFoldOutlined, SettingOutlined, AppstoreOutlined, DownOutlined, HomeOutlined, ApiOutlined, PlusOutlined, SwapOutlined } from '@ant-design/icons'
@@ -53,10 +52,6 @@
  changeMenu (value) {
    // 主菜单切换
    if (this.props.editLevel) {
      // 编辑状态下,不可切换菜单
      return
    }
    if (value.PageParam.OpenType === 'menu') {
      this.props.modifyMainMenu(value)
    } else if (value.PageParam.OpenType === 'outpage') {
@@ -79,12 +74,21 @@
      this.setState({ menulist })
      this.props.modifyMenuTree(menulist)
      if (window.GLOB.systemType !== 'production') { // 非正式系统选择第一项
        this.props.modifyMainMenu(menulist[0] || null)
      } else {
      let mainMenu = menulist[0] || null
      if (this.props.editLevel === 'level1') {
        mainMenu = null
      } else if (this.props.mainMenu && this.props.mainMenu.MenuID) {
        let _menu = menulist.filter(item => item.MenuID === this.props.mainMenu.MenuID)[0]
        mainMenu = _menu || mainMenu
        if (!_menu && (this.props.editLevel === 'level2' || this.props.editLevel === 'level3')) {
          this.props.resetEditLevel(false)
        }
      }
      this.props.modifyMenuTree(menulist)
      this.props.modifyMainMenu(mainMenu)
    } else {
      notification.error({
        top: 92,
@@ -120,7 +124,8 @@
            MenuID: snd.MenuID,
            MenuName: snd.MenuName,
            PageParam: {Icon: 'folder'},
            children: []
            children: [],
            level: 'second'
          }
          if (snd.PageParam) {
@@ -141,7 +146,8 @@
                MenuNo: trd.MenuNo,
                EasyCode: trd.EasyCode,
                type: 'CommonTable',            // 默认值为常用表
                OpenType: 'newtab'              // 打开方式
                OpenType: 'newtab',             // 打开方式
                level: 'third'
              }
  
              if (trd.LinkUrl && iframes.includes(trd.LinkUrl.split('?')[0])) {
@@ -192,11 +198,13 @@
  enterEdit = () => {
    // 进入编辑状态
    this.props.resetEditLevel('level1')
    this.props.modifyMainMenu(null)
  }
  
  exitEdit = () => {
    // 退出编辑状态
    this.props.resetEditLevel(false)
    this.props.modifyMainMenu(this.state.menulist[0] || null)
  }
  
@@ -239,14 +247,6 @@
    this.loadmenu()
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menuTree), fromJS(nextProps.menuTree)) && !is(fromJS(this.state.menulist), fromJS(nextProps.menuTree))) {
      this.setState({
        menulist: nextProps.menuTree
      })
    }
  }
  componentDidMount () {
    if (window.GLOB.systemType !== 'production') {
      setTimeout(() => {
@@ -287,10 +287,6 @@
      this.reload()
    })
    MKEmitter.addListener('mkUpdateMenuList', this.reload)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  /**
@@ -343,9 +339,9 @@
        {/* 进入编辑按钮 */}
        {!editLevel && window.GLOB.systemType !== 'production' && menulist ? <Popover overlayClassName="mk-popover-control-wrap mk-menu-control" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <PlusOutlined onClick={() => this.setState({visible: true, loading: false})} className="mk-edit-menu"/>
            <SwapOutlined onClick={this.enterEdit} className="mk-edit-menu"/>
            <div style={{display: 'inline-block', minWidth: '32px'}}><ThawMenu ParentId="0" Type="10" className="mk-edit-menu"/></div>
            <PlusOutlined onClick={() => this.setState({visible: true, loading: false})}/>
            <SwapOutlined onClick={this.enterEdit}/>
            <div style={{display: 'inline-block', minWidth: '32px'}}><ThawMenu ParentId="0" Type="10"/></div>
          </div>
        } trigger="hover">
          <SettingOutlined className="edit-check"/>
src/views/design/index.scss
@@ -2,6 +2,10 @@
  display: flex;
  flex: auto;
  min-height: 100%;
  .mk-save-menu[disabled] {
    background: #ffffff!important;
  }
}
.mk-design-view {
  #mk-tabview-wrap {
@@ -29,6 +33,10 @@
  .mk-swap {
    transform: rotate(90deg);
  }
  .mk-swap.disabled {
    cursor: not-allowed!important;
    color: #959595;
  }
}
.mk-menu-control.mk-popover-control-wrap {
  padding-bottom: 0px;
src/views/design/sidemenu/editsecmenu/index.jsx
@@ -3,23 +3,15 @@
import { is, fromJS } from 'immutable'
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import { notification, Modal, Button, Spin } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { notification, Modal, Button } from 'antd'
import moment from 'moment'
import TransferForm from '@/templates/zshare/basetransferform'
import Utils from '@/utils/utils.js'
import DragElement from '../menuelement'
import MenuForm from '../menuform'
import Api from '@/api'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import MKEmitter from '@/utils/events.js'
import './index.scss'
import card1 from '@/assets/img/card-bg2.jpg'
import card2 from '@/assets/img/card-bg5.jpg'
import card3 from '@/assets/img/card-bg8.jpg'
import card4 from '@/assets/img/card-bg7.jpg'
import card5 from '@/assets/img/card-bg6.jpg'
const { confirm } = Modal
@@ -28,42 +20,36 @@
    menulist: PropTypes.any,      // 二级菜单列表
    menuTree: PropTypes.array,    // 一级菜单列表
    supMenu: PropTypes.object,    // 二级菜单所对应的一级菜单
    reload: PropTypes.func,       // 刷新二级菜单数据
    exitEdit: PropTypes.func      // 退出编辑
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    menulist: null,        // 菜单列表
    type: '',              // 编辑类型,add or edit
    title: '',             // 模态框标题
    visible: null,         // 模态框是否可见
    formlist: null,        // 表单信息
    editMenu: null,        // 编辑菜单
    thawmenulist: null,    // 已冻结的二级菜单
    thawMvisible: false,   // 解除冻结模态框
    confirmLoading: false, // 提交中。。。
    targetKeys: []         // 解冻菜单列表
    loading: false,        // 提交中。。。
    change: false
  }
  handlePreviewList = (List) => {
    this.setState({
      menulist: List
      menulist: List,
      change: !is(fromJS(List), fromJS(this.props.menulist))
    })
  }
  handleMenu = (menu) => {
    const { dict } = this.state
    // 菜单编辑:修改、删除,如菜单顺序已改变,提示保存菜单顺序
    const _this = this
    if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
    if (this.state.change) {
      notification.warning({
        top: 92,
        message: dict['model.menu.presave'],
        message: '菜单顺序已调整,请保存!',
        duration: 5
      })
    } else if (menu.type === 'close') {
      return
    }
    if (menu.type === 'close') {
      confirm({
        title: `确定删除菜单《${menu.card.MenuName}》吗?`,
        content: '',
@@ -74,7 +60,7 @@
          }
          return Api.getSystemConfig(param).then(res => {
            if (res.status) {
              _this.props.reload()
              MKEmitter.emit('mkUpdateMenuList')
            } else {
              notification.warning({
                top: 92,
@@ -89,14 +75,12 @@
    } else if (menu.type === 'edit') {
      this.setState({
        visible: true,
        title: dict['model.edit'] + dict['model.menu'],
        type: 'edit',
        editMenu: menu.card,
        formlist: [
          { // 父级菜单
            type: 'select',
            key: 'parentId',
            label: dict['model.super'] + dict['model.menu'],
            label: '上级菜单',
            initVal: this.props.supMenu.MenuID,
            required: true,
            options: this.props.menuTree
@@ -104,7 +88,7 @@
          { // 菜单名称
            type: 'text',
            key: 'menuName',
            label: dict['model.menu'] + dict['model.name'],
            label: '菜单名称',
            initVal: menu.card.MenuName,
            required: true,
            readonly: false
@@ -112,7 +96,7 @@
          { // 菜单图标
            type: 'icon',
            key: 'icon',
            label: dict['model.icon'],
            label: '图标',
            initVal: menu.card.PageParam.Icon || 'folder',
            required: true
          }
@@ -122,105 +106,39 @@
  }
  handleSubBtn = (type) => {
    const { dict } = this.state
    // 操作按钮
    if (type === 'add') { // 添加新菜单
      this.setState({
        visible: true,
        title: dict['model.add'] + dict['model.menu'],
        type: 'add',
        formlist: [
          { // 父级菜单
            type: 'select',
            key: 'parentId',
            label: dict['model.super'] + dict['model.menu'],
            initVal: this.props.supMenu.MenuID,
            required: true,
            options: this.props.menuTree
          },
          { // 菜单名称
            type: 'text',
            key: 'menuName',
            label: dict['model.menu'] + dict['model.name'],
            initVal: '',
            required: true,
            readonly: false
          },
          { // 菜单图标
            type: 'icon',
            key: 'icon',
            label: dict['model.icon'],
            initVal: 'folder',
            required: true
          }
        ]
      })
    } else if (type === 'thaw') { // 解冻已有菜单
      this.setState({
        thawMvisible: true,
        targetKeys: []
      })
      Api.getSystemConfig({
        func: 'sPC_Get_FrozenMenu',
        ParentID: this.props.supMenu.MenuID,
        TYPE: 20
      }).then(res => {
        if (res.status) {
          this.setState({
            thawmenulist: res.data.map(menu => {
              return {
                key: menu.MenuID,
                title: menu.MenuName
              }
            })
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    } else if (type === 'confirm') { // 确定时入顺序改变,则提示保存,否则退出编辑
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
        let _this = this
        let param  = {
          func: 'sPC_Menu_SortUpt',
          LText: this.state.menulist.map((item, index) => {
            return 'select \'' + item.MenuID + '\' as Menuid,' + (index + 1) * 10 + ' as sort'
          })
        }
        param.LText = param.LText.join(' union ') // sql拼接
        param.LText = Utils.formatOptions(param.LText) // 关键字符替换,base64加密
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 时间戳
        param.secretkey = Utils.encrypt(param.LText, param.timestamp) // md5密钥
        confirm({
          title: this.state.dict['model.menu.resetorder'],
          content: '',
          onOk() {
            return Api.getSystemConfig(param).then(res => {
              if (res.status) {
                _this.props.reload()
              } else {
                notification.warning({
                  top: 92,
                  message: res.message,
                  duration: 5
                })
              }
            })
          },
          onCancel() {}
    if (type === 'confirm') { // 保存调整后的顺序
      let param  = {
        func: 'sPC_Menu_SortUpt',
        LText: this.state.menulist.map((item, index) => {
          return 'select \'' + item.MenuID + '\' as Menuid,' + (index + 1) * 10 + ' as sort'
        })
      } else {
        this.props.exitEdit()
      }
      param.LText = param.LText.join(' union ') // sql拼接
      param.LText = Utils.formatOptions(param.LText) // 关键字符替换,base64加密
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 时间戳
      param.secretkey = Utils.encrypt(param.LText, param.timestamp) // md5密钥
      confirm({
        title: '确认调整菜单顺序吗?',
        content: '',
        onOk() {
          return Api.getSystemConfig(param).then(res => {
            if (res.status) {
              MKEmitter.emit('mkUpdateMenuList')
            } else {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
          })
        },
        onCancel() {}
      })
    } else if (type === 'close') { // 退出编辑
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
      if (this.state.change) {
        let _this = this
        confirm({
@@ -238,138 +156,45 @@
  }
  memuHandleSubmit = () => {
    if (this.state.type === 'add') { // 新建菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          ParentID: values.parentId,
          MenuID: Utils.getuuid(),
          MenuName: values.menuName,
          PageParam: JSON.stringify({
            Icon: values.icon
    this.menuFormRef.handleConfirm().then(values => {
      let param = {
        func: 'sPC_SndMenu_Upt',
        ParentID: values.parentId,
        MenuID: this.state.editMenu.MenuID,
        MenuName: values.menuName,
        PageParam: JSON.stringify({
          Icon: values.icon
        })
      }
      this.setState({
        loading: true
      })
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          this.setState({
            loading: false,
            visible: false
          })
          MKEmitter.emit('mkUpdateMenuList')
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
        param.func = 'sPC_SndMenu_Add'
        param.Sort = (this.props.menulist.length + 1) * 10
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              visible: false
            })
            this.props.reload()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }, () => {})
    } else if (this.state.type === 'edit') { // 编辑菜单:提交
      this.menuFormRef.handleConfirm().then(values => {
        let param = {
          func: 'sPC_SndMenu_Upt',
          ParentID: values.parentId,
          MenuID: this.state.editMenu.MenuID,
          MenuName: values.menuName,
          PageParam: JSON.stringify({
            Icon: values.icon
          })
        }
        this.setState({
          confirmLoading: true
        })
        Api.getSystemConfig(param).then(res => {
          if (res.status) {
            this.setState({
              confirmLoading: false,
              visible: false
            })
            this.props.reload()
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: res.message,
              duration: 5
            })
          }
        })
      }, () => {})
    }
      })
    }, () => {})
  }
  memuHandleCancel = () => { // 取消操作,关闭模态框
    this.setState({
      visible: false,
      type: '',
      formlist: null,
      editMenu: null
    })
  }
  thawMemuSubmit = () => { // 解冻菜单,提交,存在多个时,循环提交
    const { targetKeys } = this.state
    if (targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: this.state.dict['form.required.select'] + this.state.dict['model.menu'],
        duration: 5
      })
    } else {
      this.setState({
        confirmLoading: true
      })
      let defers = targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.getSystemConfig({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
            if (res.status) {
              resolve('')
            } else {
              resolve(res.message)
            }
          })
        })
      })
      Promise.all(defers).then(res => {
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.error({
            top: 92,
            message: msg,
            duration: 10
          })
        } else {
          this.setState({
            confirmLoading: false,
            thawMvisible: false,
            targetKeys: [],
            thawmenulist: null
          })
          this.props.reload()
        }
      })
    }
  }
  thawMemuCancel = () => { // 解冻菜单取消
    this.setState({
      thawMvisible: false,
      targetKeys: [],
      thawmenulist: null
    })
  }
@@ -382,80 +207,44 @@
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menulist), fromJS(nextProps.menulist))) {
      this.setState({
        menulist: nextProps.menulist
        menulist: nextProps.menulist,
        change: false
      })
    }
  }
  render () {
    const { dict } = this.state
    const { change, loading } = this.state
    return (
      <div className="second-edit-box">
        <div className="mask">
          <div className="tipcard card1" style={{backgroundImage: 'url(' + card1 + ')'}}>
            拖动二级菜单可调整顺序,顺序调整后,请点击确定按钮保存。
          </div>
          <div className="tipcard card2" style={{backgroundImage: 'url(' + card2 + ')'}}>
            点击编辑图标可修改菜单属性,点击删除图标可删除菜单。
          </div>
          <div className="tipcard card3" style={{backgroundImage: 'url(' + card3 + ')'}}>
            点击解除冻结按钮,可还原已删除的二级菜单。
          </div>
          <div className="tipcard card4" style={{backgroundImage: 'url(' + card4 + ')'}}>
            点击添加图标,可新增二级菜单。
          </div>
          <div className="tipcard card5" style={{backgroundImage: 'url(' + card5 + ')'}}>
            <p>编辑状态中,菜单之外区域会锁定,查看系统数据请点击。</p>
            <div>
              <span className="new-view" onClick={() => {window.open('#/main')}} >新页面</span>
            </div>
          </div>
        </div>
      <>
        <DndProvider backend={HTML5Backend}>
          {this.state.menulist && this.state.menulist.length > 0 ? <DragElement
          <DragElement
            list={this.state.menulist}
            handlePreviewList={this.handlePreviewList}
            handleMenu={this.handleMenu}
          /> : null}
          />
        </DndProvider>
        <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
          <PlusOutlined />
        </div>
        <div className="menu-btn">
          <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{dict['model.thaw'] + dict['model.menu']}</Button>
          <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{dict['model.confirm']}</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>{dict['model.close']}</Button>
          <Button type="primary" className="mk-save-menu" disabled={!change} onClick={() => {this.handleSubBtn('confirm')}}>保存</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>关闭</Button>
        </div>
        <Modal
          title={this.state.title}
          title="修改菜单"
          visible={this.state.visible}
          onOk={this.memuHandleSubmit}
          confirmLoading={this.state.confirmLoading}
          confirmLoading={loading}
          onCancel={this.memuHandleCancel}
          destroyOnClose
        >
          {this.state.formlist ?
            <MenuForm
              dict={dict}
              inputSubmit={this.memuHandleSubmit}
              formlist={this.state.formlist}
              wrappedComponentRef={(inst) => this.menuFormRef = inst}
            /> : null}
        </Modal>
        <Modal
          title={dict['model.thaw'] + dict['model.menu']}
          width={600}
          visible={this.state.thawMvisible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
          destroyOnClose
        >
          {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawmenulist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
        </Modal>
      </div>
      </>
    )
  }
}
src/views/design/sidemenu/editsecmenu/index.scss
@@ -1,81 +0,0 @@
.second-edit-box {
  position: relative;
  z-index: 10;
  .mask {
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    .tipcard {
      position: absolute;
      min-height: 100px;
      font-size: 16px;
      border-radius: 6px;
      background-size: 100% 100%;
      background-repeat: no-repeat;
      padding: 15px;
    }
    .card1 {
      left: 30%;
      top: 20vh;
      width: 230px;
      min-height: 100px;
      color: #000000;
      font-style: oblique;
    }
    .card2 {
      left: 60%;
      top: 20vh;
      width: 230px;
      min-height: 100px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card3 {
      left: 30%;
      top: 50vh;
      width: 230px;
      min-height: 140px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card4 {
      left: 60%;
      top: 50vh;
      width: 230px;
      min-height: 140px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card5 {
      right: 5%;
      top: 20vh;
      width: 130px;
      min-height: 240px;
      color: #000000;
      padding: 40px 15px 10px;
      p {
        margin: 0 0 5px;
      }
      div {
        text-align: center;
        .new-view {
          display: inline-block;
          cursor: pointer;
          color: #fff;
          padding: 2px 10px;
          border-radius: 4px;
          background-color: #1890ff;
          border-color: #1890ff;
          text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
          -webkit-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
          box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
        }
      }
    }
  }
}
src/views/design/sidemenu/editthdmenu/index.jsx
@@ -5,34 +5,21 @@
import { DndProvider } from 'react-dnd'
import { withRouter } from 'react-router-dom'
import HTML5Backend from 'react-dnd-html5-backend'
import { notification, Modal, Button, Spin, Col, Card, Tabs, Row, Input } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import { notification, Modal, Button } from 'antd'
import moment from 'moment'
import Api from '@/api'
import { sysTemps } from '@/utils/option.js'
import MKEmitter from '@/utils/events.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
import customImg from '@/assets/img/custom.jpg'
import MkIcon from '@/components/mk-icon'
import Preview from './preview'
import MenuForm from './menuform'
import TransferForm from '@/templates/zshare/basetransferform'
import Utils from '@/utils/utils.js'
import MenuUtils from '@/utils/utils-custom.js'
import DragElement from '../menuelement'
import asyncLoadComponent from '@/utils/asyncLoadComponent'
import './index.scss'
import card1 from '@/assets/img/card-bg2.jpg'
import card2 from '@/assets/img/card-bg5.jpg'
import card3 from '@/assets/img/card-bg8.jpg'
import card4 from '@/assets/img/card-bg7.jpg'
import card5 from '@/assets/img/card-bg6.jpg'
const MenuForm = asyncLoadComponent(() => import('../thdmenuform'))
const ComTableConfig = asyncLoadComponent(() => import('@/templates/comtableconfig'))
const TreePageConfig = asyncLoadComponent(() => import('@/templates/treepageconfig'))
const CalendarPageConfig = asyncLoadComponent(() => import('@/templates/calendarconfig'))
@@ -41,12 +28,9 @@
const SubTable = asyncLoadComponent(() => import('@/templates/subtableconfig'))
const { confirm } = Modal
const { TabPane } = Tabs
const { Search } = Input
class EditMenu extends Component {
  static propTpyes = {
    reload: PropTypes.func,      // 菜单修改后刷新
    menulist: PropTypes.any,     // 三级菜单列表
    exitEdit: PropTypes.func,    // 退出编辑状态
    supMenu: PropTypes.object,   // 对应的上级菜单
@@ -55,19 +39,10 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    thawmenulist: null,     // 已冻结的二级菜单
    type: '',               // 操作类型,新建或编辑菜单
    thawMvisible: false,    // 解除冻结模态框
    confirmLoading: false,  // 提交中。。。
    selectTemp: '',         // 选择模板
    usedTemplates: null,    // 已使用模板列表
    tempSearchKey: '',      // 菜单名称过滤值
    loading: false,         // 编辑菜单或使用已使用模板时,获取配置信息
    preview: null,          // 图片预览url
    pretemplate: null,      // 预览模板
    btnParam: null,         // 编辑按钮的配置信息
    menulist: null,         // 编辑中的菜单
    sysTemplates: sysTemps, // 系统模板
    tabview: '',            // 选择模板窗口(template)、基础表格配置(CommonTable)、表单(Modal)、子表(SubTable)
    editMenu: null,         // 编辑菜单
    editAction: null,       // 编辑按钮
@@ -79,8 +54,8 @@
    btnTab: null,           // 打开新标签或当前页面刷新的按钮
    btnTabConfig: null,     // 打开新标签按钮配置
    handleMVisible: false,  // 添加或修改菜单模态框(角色权限分配等)
    sysMenu: false,         // 添加或编辑菜单(角色权限分配等)
    targetKeys: []          // 解冻菜单列表
    sysMenu: null,          // 添加或编辑菜单(角色权限分配等)
    change: false
  }
  /**
@@ -97,7 +72,8 @@
   */
  handlePreviewList = (List) => {
    this.setState({
      menulist: List
      menulist: List,
      change: !is(fromJS(List), fromJS(this.props.menulist))
    })
  }
@@ -108,15 +84,16 @@
   * 3、菜单编辑,查询菜单配置信息,信息正确,进入对应编辑页面
   */
  handleMenu = (menu) => {
    const _this = this
    if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
    if (this.state.change) {
      notification.warning({
        top: 92,
        message: this.state.dict['model.menu.presave'],
        duration: 5
      })
    } else if (menu.type === 'close') {
      return
    }
    if (menu.type === 'close') {
      confirm({
        title: `确定删除菜单《${menu.card.MenuName}》吗?`,
        content: '',
@@ -127,7 +104,7 @@
          }
          return Api.getSystemConfig(param).then(res => {
            if (res.status) {
              _this.props.reload()
              MKEmitter.emit('mkUpdateMenuList')
            } else {
              notification.warning({
                top: 92,
@@ -142,9 +119,9 @@
    } else if (menu.type === 'edit') {
      let _menu = fromJS(menu.card).toJS()
      if (_menu.PageParam && (_menu.PageParam.Template === 'RolePermission' || _menu.PageParam.Template === 'NewPage')) { // 单页面修改
      if (['RolePermission', 'NewPage'].includes(_menu.PageParam.Template)) { // 单页面修改
        _menu.Template = _menu.PageParam.Template
        _menu.url = _menu.PageParam.url
        _menu.url = _menu.PageParam.url || ''
        _menu.fstMenuId = _menu.FstId
        _menu.supMenuList = this.props.supMenuList
@@ -158,181 +135,103 @@
        return
      }
      // let _param = ''
      // if (card.type === 'CustomPage') {
      //   _param = {
      //     MenuType: 'custom',
      //     MenuId: card.MenuID,
      //     ParentId: card.ParentId,
      //     MenuName: card.MenuName,
      //     MenuNo: card.MenuNo
      //   }
      //   _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
      // }
      // window.open(`#/menudesign/${_param}`)}
      let param = {
        func: 'sPC_Get_LongParam',
        MenuID: _menu.MenuID
      }
      // let param = {
      //   func: 'sPC_Get_LongParam',
      //   MenuID: _menu.MenuID
      // }
      this.setState({
        loading: true
      })
      // this.setState({
      //   loading: true
      // })
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          let _LongParam = ''
          if (res.LongParam) {
            try {
              _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _LongParam = ''
            }
          }
      // Api.getSystemConfig(param).then(res => {
      //   if (res.status) {
      //     let _LongParam = ''
      //     if (res.LongParam) {
      //       try {
      //         _LongParam = JSON.parse(window.decodeURIComponent(window.atob(res.LongParam)))
      //       } catch (e) {
      //         console.warn('Parse Failure')
      //         _LongParam = ''
      //       }
      //     }
          _menu.LongParam = _LongParam
          _menu.fstMenuId = _menu.FstId
          _menu.supMenuList = this.props.supMenuList
          _menu.fstMenuList = this.props.menuTree
          _menu.open_edition = res.open_edition || ''
      //     _menu.LongParam = _LongParam
      //     _menu.fstMenuId = _menu.FstId
      //     _menu.supMenuList = this.props.supMenuList
      //     _menu.fstMenuList = this.props.menuTree
      //     _menu.open_edition = res.open_edition || ''
          // 检测模板是否存在
          let _Template = this.state.sysTemplates.filter(temp => temp.type === _menu.PageParam.Template)
          // 模板不存在时错误提示
          if (_Template.length === 0) {
            notification.warning({
              top: 92,
              message: '菜单模板丢失,请重新选择模板!',
              duration: 5
            })
            this.setState({
              type: 'edit',
              editMenu: _menu,
              loading: false,
              tabview: 'template'
            }, () => {
              document.getElementById('root').style.overflowY = 'hidden'
            })
          } else {
            this.setState({
              type: 'edit',
              editMenu: _menu,
              loading: false,
              tabview: _menu.PageParam.Template
            }, () => {
              document.getElementById('root').style.overflowY = 'hidden'
            })
          }
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
      //     this.setState({
      //       editMenu: _menu,
      //       loading: false,
      //       tabview: _menu.PageParam.Template
      //     }, () => {
      //       document.getElementById('root').style.overflowY = 'hidden'
      //     })
      //   } else {
      //     this.setState({
      //       loading: false
      //     })
      //     notification.warning({
      //       top: 92,
      //       message: res.message,
      //       duration: 5
      //     })
      //   }
      // })
    }
  }
  handleSubBtn = (type) => {
    // 操作按钮:添加、解除冻结、确认及关闭
    if (type === 'add') { // 点击添加时,展开模板
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.presave'],
          duration: 5
    if (type === 'confirm') {
      let param  = {
        func: 'sPC_Menu_SortUpt',
        LText: this.state.menulist.map((item, index) => {
          return 'select \'' + item.MenuID + '\' as Menuid,' + (index + 1) * 10 + ' as sort'
        })
        return
      }
      this.setState({
        tabview: 'template',
        editMenu: {
          MenuID: Utils.getuuid(),
          MenuName: '',
          MenuNo: '',
          type: '',
          PageParam: '',
          LongParam: '',
          isSubtable: '', // 是否为主子表
          ParentId: this.props.supMenu.MenuID,
          supMenuList: this.props.supMenuList,
          fstMenuId: this.props.mainMenu.MenuID,
          fstMenuList: this.props.menuTree,
          menuSort: (this.props.menulist.length + 1) * 10 // 新建菜单设置排序
        }
      }, () => {
        document.getElementById('root').style.overflowY = 'hidden'
      })
    } else if (type === 'thaw') {
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
        notification.warning({
          top: 92,
          message: this.state.dict['model.menu.presave'],
          duration: 5
        })
        return
      }
      this.setState({
        thawMvisible: true,
        targetKeys: []
      })
      Api.getSystemConfig({
        func: 'sPC_Get_FrozenMenu',
        ParentID: this.props.supMenu.MenuID,
        TYPE: 30
      }).then(res => {
        if (res.status) {
          this.setState({
            thawmenulist: res.data.map(menu => {
              return {
                key: menu.MenuID,
                title: menu.MenuName
              }
            })
          })
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    } else if (type === 'confirm') {
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
        let _this = this
        let param  = {
          func: 'sPC_Menu_SortUpt',
          LText: this.state.menulist.map((item, index) => {
            return 'select \'' + item.MenuID + '\' as Menuid,' + (index + 1) * 10 + ' as sort'
          })
        }
      param.LText = param.LText.join(' union ') // sql拼接
      param.LText = Utils.formatOptions(param.LText) // 关键字符替换,base64加密
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 时间戳
      param.secretkey = Utils.encrypt(param.LText, param.timestamp) // md5密钥
        param.LText = param.LText.join(' union ') // sql拼接
        param.LText = Utils.formatOptions(param.LText) // 关键字符替换,base64加密
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') // 时间戳
        param.secretkey = Utils.encrypt(param.LText, param.timestamp) // md5密钥
        confirm({
          title: this.state.dict['model.menu.resetorder'],
          content: '',
          onOk() {
            return Api.getSystemConfig(param).then(res => {
              if (res.status) {
                _this.props.reload()
              } else {
                notification.warning({
                  top: 92,
                  message: res.message,
                  duration: 5
                })
              }
            })
          },
          onCancel() {}
        })
      } else {
        this.props.exitEdit()
      }
      confirm({
        title: '确认调整菜单顺序吗?',
        content: '',
        onOk() {
          return Api.getSystemConfig(param).then(res => {
            if (res.status) {
              MKEmitter.emit('mkUpdateMenuList')
            } else {
              notification.warning({
                top: 92,
                message: res.message,
                duration: 5
              })
            }
          })
        },
        onCancel() {}
      })
    } else if (type === 'close') {
      if (!is(fromJS(this.props.menulist), fromJS(this.state.menulist))) {
      if (this.state.change) {
        let _this = this
        confirm({
@@ -347,248 +246,6 @@
        this.props.exitEdit()
      }
    }
  }
  thawMemuSubmit = () => {
    const { targetKeys } = this.state
    // 三级菜单解除冻结
    if (targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: this.state.dict['form.required.select'] + this.state.dict['model.menu'],
        duration: 5
      })
    } else {
      this.setState({
        confirmLoading: true
      })
      let defers = targetKeys.map(item => {
        return new Promise((resolve) => {
          Api.getSystemConfig({
            func: 'sPC_MainMenu_ReDel',
            MenuID: item
          }).then(res => {
            if (res.status) {
              resolve('')
            } else {
              resolve(res.message)
            }
          })
        })
      })
      Promise.all(defers).then(res => {
        let msg = res.filter(Boolean)[0]
        if (msg) {
          notification.error({
            top: 92,
            message: msg,
            duration: 10
          })
        } else {
          this.setState({
            confirmLoading: false,
            thawMvisible: false,
            targetKeys: [],
            thawmenulist: null
          })
          this.props.reload()
        }
      })
    }
  }
  thawMemuCancel = () => {
    // 解除冻结-取消
    this.setState({
      thawMvisible: false,
      thawmenulist: null,
      targetKeys: []
    })
  }
  previewPicture = (template) => {
    if (template.disabled) return
    // 图片预览
    this.setState({
      preview: template.url,
      pretemplate: template
    })
  }
  cancelPrePicture = () => {
    // 关闭图片预览
    this.setState({
      preview: null
    })
  }
  /**
   * @description 使用模板
   * 1、使用系统模板时,使用系统配置
   * 2、使用已有菜单模板时,获取菜单配置信息,标记为user(复制菜单按钮)
   */
  useTemplate = (template, useType) => {
    let editMenu = fromJS(this.state.editMenu).toJS()
    editMenu.fstMenuId = this.props.mainMenu.MenuID
    editMenu.fstMenuList = this.props.menuTree
    if (useType === 'sys' && (template.type === 'RolePermission' || template.type === 'NewPage')) { // 独立页面
      let _menu = {
        ...editMenu,
        MenuID: Utils.getuuid(),
        MenuName: template.title,
        Template: template.type,
        ParentId: this.props.supMenu.MenuID,
        menuSort: (this.props.menulist.length + 1) * 10,
        isSystem: true
      }
      this.setState({
        handleMVisible: true,
        sysMenu: _menu
      })
      return
    } else if (template.type === 'CustomPage') {
      let _menu = {
        ...editMenu,
        MenuID: Utils.getuuid(),
        MenuName: template.title,
        Template: template.type,
        ParentId: this.props.supMenu.MenuID,
        OriginMenuId: template.uuid || '',
        menuSort: (this.props.menulist.length + 1) * 10,
        isSystem: true
      }
      this.setState({
        handleMVisible: true,
        sysMenu: _menu
      })
      return
    }
    new Promise(resolve => {
      if (useType === 'sys') {
        resolve(true)
      } else {
        let param = {
          func: 'sPC_Get_LongParam',
          MenuID: template.uuid
        }
        this.setState({
          loading: true
        })
        Api.getSystemConfig(param).then(result => {
          if (!result.status) {
            notification.warning({
              top: 92,
              message: result.message,
              duration: 5
            })
            resolve(false)
          } else {
            let _config = ''
            if (result.LongParam) {
              try {
                _config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
                _config.type = 'user'
              } catch (e) {
                console.warn('Parse Failure')
                _config = ''
              }
            }
            if (_config) {
              template.baseconfig = _config
              resolve(true)
            } else {
              notification.warning({
                top: 92,
                message: '模板信息获取失败!',
                duration: 5
              })
              resolve(false)
            }
          }
        })
      }
    }).then(res => {
      if (!res) { // 错误时,重置状态
        this.setState({
          loading: false
        })
        return
      }
      // 选择模板:添加菜单时(不存在menuId)
      let _PageParam = {
        OpenType: editMenu.PageParam ? editMenu.PageParam.OpenType : 'newtab',
        Template: template.type
      }
      this.setState({
        loading: false,
        tabview: template.type,
        editMenu: {
          ...editMenu,
          type: template.type,
          PageParam: _PageParam,
          LongParam: template.baseconfig,
          isSubtable: template.isSubtable
        }
      })
      document.getElementById('root').style.overflowY = 'hidden'
    })
  }
  getUsedTemplate = () => {
    let { sysTemplates } = this.state
    let memberLevel = Utils.getMemberLevel()
    const illust = { // 模板图片,用于已使用模板
      CommonTable: mainsubtable,
      TreePage: treepage,
      CalendarPage: calendar,
      CustomPage: customImg
    }
    Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'menu'}).then(res => {
      let _templates = []
      res.UserTemp.forEach(temp => {
        if (temp.Template === 'NewPage' || temp.Template === 'RolePermission') {
          return
        } else if (temp.Template === 'CustomPage' && memberLevel < 20) {
          temp.disabled = true
          temp.disTitle = '会员等级不够,无开发权限。'
        }
        _templates.push({
          uuid: temp.MenuID,
          title: temp.MenuName,
          type: temp.Template,
          url: illust[temp.Template],
          disabled: temp.disabled || false,
          disTitle: temp.disTitle || ''
        })
      })
      sysTemplates = sysTemplates.map(temp => {
        if (temp.type === 'CustomPage' && memberLevel < 20) {
          temp.disabled = true
          temp.disTitle = '会员等级不够,无开发权限。'
        }
        return temp
      })
      this.setState({
        usedTemplates: _templates,
        sysTemplates: sysTemplates
      })
    })
  }
  exittabview = () => {
@@ -616,17 +273,6 @@
    const { sysMenu } = this.state
    let sysTemplates = fromJS(this.state.sysTemplates).toJS()
    // 角色权限分配模板,只可以添加一次
    // if (sysMenu.isSystem && (sysMenu.Template === 'RolePermission')) {
    //   sysTemplates = sysTemplates.map(temp => {
    //     if (temp.type === sysMenu.type) {
    //       temp.hidden = true
    //     }
    //     return temp
    //   })
    // }
    this.menuFormRef.handleConfirm().then(res => {
      let PageParam = {
        Template: sysMenu.Template,
@@ -653,10 +299,6 @@
        LTexttb: ''
      }
      if (sysMenu.menuSort) { // 菜单新建时设置排序
        param.Sort = sysMenu.menuSort
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
@@ -664,33 +306,29 @@
        confirmLoading: true
      })
      if (sysMenu.Template === 'CustomPage' && sysMenu.OriginMenuId) {
        this.copyMenu(param, sysMenu.OriginMenuId)
      } else {
        Api.getSystemConfig(param).then(response => {
          if (response.status) {
            this.setState({
              sysTemplates: sysTemplates,
              confirmLoading: false,
              handleMVisible: false,
              sysMenu: '',
              tabview: ''
            })
            this.props.reload()
            document.getElementById('root').style.overflowY = 'unset'
          } else {
            this.setState({
              confirmLoading: false
            })
            notification.warning({
              top: 92,
              message: response.message,
              duration: 5
            })
          }
        })
      }
      Api.getSystemConfig(param).then(response => {
        if (response.status) {
          this.setState({
            sysTemplates: sysTemplates,
            confirmLoading: false,
            handleMVisible: false,
            sysMenu: '',
            tabview: ''
          })
          MKEmitter.emit('mkUpdateMenuList')
          document.getElementById('root').style.overflowY = 'unset'
        } else {
          this.setState({
            confirmLoading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
@@ -731,7 +369,7 @@
              tabview: ''
            })
  
            this.props.reload()
            MKEmitter.emit('mkUpdateMenuList')
            document.getElementById('root').style.overflowY = 'unset'
          } else {
            this.setState({
@@ -758,8 +396,6 @@
  }
  UNSAFE_componentWillMount () {
    this.getUsedTemplate()
    this.setState({
      menulist: this.props.menulist
    })
@@ -768,37 +404,17 @@
  UNSAFE_componentWillReceiveProps (nextProps) {
    if (!is(fromJS(this.props.menulist), fromJS(nextProps.menulist))) {
      this.setState({
        menulist: nextProps.menulist
        menulist: nextProps.menulist,
        change: false
      })
    }
  }
  render () {
    const { dict } = this.state
    const { change } = this.state
    return (
      <div className="third-edit-box">
        {!this.state.tabview ?
          <div className="mask">
            <div className="tipcard card1" style={{backgroundImage: 'url(' + card1 + ')'}}>
              拖动三级菜单可调整顺序,顺序调整后,请点击确定按钮保存。
            </div>
            <div className="tipcard card2" style={{backgroundImage: 'url(' + card2 + ')'}}>
              点击编辑图标会根据菜单模板,进入相应的模板编辑页面,点击删除图标可删除菜单。
            </div>
            <div className="tipcard card3" style={{backgroundImage: 'url(' + card3 + ')'}}>
              点击解除冻结按钮,可还原已删除的三级菜单。
            </div>
            <div className="tipcard card4" style={{backgroundImage: 'url(' + card4 + ')'}}>
              点击添加图标,会显示系统模板和已使用模板,选择已使用模板时,会复制已添加菜单的配置信息。
            </div>
            <div className="tipcard card5" style={{backgroundImage: 'url(' + card5 + ')'}}>
              <p>编辑状态中,菜单之外区域会锁定,查看系统数据请点击。</p>
              <div>
                <span className="new-view" onClick={() => {window.open('#/main')}} >新页面</span>
              </div>
            </div>
          </div> : null
        }
        <div className="cus-submenu-title">
          <MkIcon type={this.props.supMenu.PageParam.Icon} />
          <span>{this.props.supMenu.MenuName}</span>
@@ -810,86 +426,29 @@
            handleMenu={this.handleMenu}
          />
        </DndProvider>
        <div className="menu-add" onClick={() => {this.handleSubBtn('add')}}>
          <PlusOutlined />
        </div>
        <div className="menu-btn">
          <Button type="primary" onClick={() => {this.handleSubBtn('thaw')}}>{dict['model.thaw'] + dict['model.menu']}</Button>
          <Button type="primary" onClick={() => {this.handleSubBtn('confirm')}}>{dict['model.confirm']}</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>{dict['model.close']}</Button>
          <Button type="primary" className="mk-save-menu" disabled={!change} onClick={() => {this.handleSubBtn('confirm')}}>保存</Button>
          <Button onClick={() => {this.handleSubBtn('close')}}>关闭</Button>
        </div>
        {this.state.tabview === 'template' ?
          <div className="editboard">
            <div className="workplace">
              <Button className="top-btn mk-yellow" onClick={this.exittabview}>{dict['model.cancel']}</Button>
              {this.state.tabview === 'template' && <Tabs defaultActiveKey="1">
                <TabPane tab="系统模板" key="1">
                  <Row>
                    {this.state.sysTemplates.map((template, index) => {
                      // if (template.hidden) return null
                      return (
                        <Col key={`${index}`} className={template.disabled ? 'disabled' : ''} title={template.disTitle || ''} span={8}>
                          <Card
                            title={template.title}>
                            <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                            <div className="card-operation">
                              <Button type="primary" onClick={() => {this.useTemplate(template, 'sys')}}>使用模板</Button>
                            </div>
                          </Card>
                        </Col>
                      )
                    })}
                  </Row>
                </TabPane>
                <TabPane tab="已使用模板" key="2">
                  <Row>
                    <Col span={8}>
                      <Search placeholder="请输入菜单名称" defaultValue={this.state.tempSearchKey} onSearch={value => {this.setState({tempSearchKey: value})}} enterButton />
                    </Col>
                  </Row>
                  <Row>
                    {this.state.usedTemplates && this.state.usedTemplates.map((template, index) => {
                      if (template.title.toLowerCase().indexOf(this.state.tempSearchKey.toLowerCase()) >= 0) {
                        return (
                          <Col key={template.type + index} className={template.disabled ? 'disabled' : ''} title={template.disTitle || ''} span={6}>
                            <Card
                              title={template.title}>
                              <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                              <div className="card-operation">
                                <Button type="primary" onClick={() => {this.useTemplate(template, 'user')}}>使用模板</Button>
                              </div>
                            </Card>
                          </Col>
                        )
                      } else {
                        return ''
                      }
                    })}
                  </Row>
                </TabPane>
              </Tabs>}
            </div>
          </div> : null
        }
        {this.state.tabview === 'TreePage' ?
          <TreePageConfig
            menu={this.state.editMenu}
            reloadmenu={() => {this.props.reload()}}
            reloadmenu={() => {MKEmitter.emit('mkUpdateMenuList')}}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'CalendarPage' ?
          <CalendarPageConfig
            menu={this.state.editMenu}
            reloadmenu={() => {this.props.reload()}}
            reloadmenu={() => {MKEmitter.emit('mkUpdateMenuList')}}
            handleView={this.handleView}
          /> : null
        }
        {this.state.tabview === 'CommonTable' ?
          <ComTableConfig
            menu={this.state.editMenu}
            reloadmenu={() => {this.props.reload()}}
            reloadmenu={() => {MKEmitter.emit('mkUpdateMenuList')}}
            handleView={this.handleView}
          /> : null
        }
@@ -927,38 +486,22 @@
            handleView={this.handleView}
          /> : null
        }
        {/* 图片预览 */}
        <Preview cancel={this.cancelPrePicture} preview={this.state.preview} template={this.state.pretemplate} confirm={this.useTemplate}/>
        {/* 解冻菜单模态框 */}
        <Modal
          title={dict['model.thaw'] + dict['model.menu']}
          width={600}
          visible={this.state.thawMvisible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
          destroyOnClose
        >
          {!this.state.thawmenulist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawmenulist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
        </Modal>
        {/* 添加系统菜单 */}
        <Modal
          title={this.state.sysMenu && this.state.sysMenu.isSystem ? dict['model.add'] + dict['model.menu'] : dict['model.update'] + dict['model.menu']}
          title="修改菜单"
          visible={this.state.handleMVisible}
          width={600}
          onOk={this.memuSubmit}
          confirmLoading={this.state.confirmLoading}
          confirmLoading={this.state.loading}
          onCancel={() => {this.setState({handleMVisible: false})}}
          destroyOnClose
        >
          <MenuForm
            menu={this.state.sysMenu}
            dict={dict}
            inputSubmit={this.memuSubmit}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />
        </Modal>
        {this.state.loading && <Spin className="loading-thdmenu" size="large" />}
      </div>
    )
  }
src/views/design/sidemenu/editthdmenu/index.scss
@@ -1,83 +1,6 @@
.third-edit-box {
  position: relative;
  z-index: 10;
  .mask {
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    .tipcard {
      position: absolute;
      min-height: 100px;
      font-size: 16px;
      border-radius: 6px;
      background-size: 100% 100%;
      background-repeat: no-repeat;
      padding: 15px;
    }
    .card1 {
      left: 30%;
      top: 20vh;
      width: 250px;
      min-height: 100px;
      color: #000000;
      font-style: oblique;
    }
    .card2 {
      left: 60%;
      top: 20vh;
      width: 250px;
      min-height: 100px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card3 {
      left: 30%;
      top: 50vh;
      width: 250px;
      min-height: 150px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card4 {
      left: 60%;
      top: 50vh;
      width: 250px;
      min-height: 150px;
      color: #000000;
      padding: 20px 30px;
      font-style: oblique;
    }
    .card5 {
      right: 5%;
      top: 20vh;
      width: 130px;
      min-height: 240px;
      color: #000000;
      padding: 40px 15px 10px;
      p {
        margin: 0 0 5px;
      }
      div {
        text-align: center;
        .new-view {
          display: inline-block;
          cursor: pointer;
          color: #fff;
          padding: 2px 10px;
          border-radius: 4px;
          background-color: #1890ff;
          border-color: #1890ff;
          text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
          -webkit-box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
          box-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
        }
      }
    }
  }
  .cus-submenu-title {
    padding: 0px 24px;
    background: #364150;
@@ -92,105 +15,5 @@
    .anticon {
      margin-right: 10px;
    }
  }
  .editboard {
    position: fixed;
    z-index: 1070;
    padding-top: 48px;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 0px;
    background: rgba(0, 0, 0, 0.35);
    .workplace {
      position: relative;
      width: calc(100vw - 235px);
      height: 100%;
      overflow-y: auto;
      left: 235px;
      background: #ffffff;
      .top-btn {
        position: absolute;
        z-index: 1;
        top: 12px;
        right: 20px;
        cursor: pointer;
      }
      .top-btn.submit {
        right: 100px;
      }
      .ant-col {
        padding: 10px;
      }
      .ant-col.disabled {
        cursor: not-allowed;
        .ant-card-head-title {
          color: #959595;
        }
        .card-operation {
          display: none;
        }
        img {
          cursor: not-allowed;
        }
      }
      .ant-card-head-title {
        text-align: center;
      }
      .ant-card-body {
        padding: 2px;
        position: relative;
        text-align: center;
        overflow: hidden;
        .card-operation {
          position: absolute;
          right: 0px;
          top: 0;
          height: 0px;
          overflow: hidden;
          transition: height 0.3s;
          button {
            height: 30px;
            padding: 0 10px;
            margin-top: 5px;
            margin-right: 10px;
            display: none;
          }
        }
      }
      .ant-card-body:hover {
        .card-operation {
          height: 40px;
          button {
            display: inline-block;
          }
        }
      }
      img {
        max-width: 100%;
        cursor: zoom-in;
      }
    }
    .workplace::-webkit-scrollbar {
      width: 7px;
    }
    .workplace::-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);
    }
    .workplace::-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);
    }
  }
  > .loading-thdmenu {
    position: fixed;
    left: calc(50vw - 22px);
    top: calc(50vh - 70px);
    z-index: 1100;
  }
}
src/views/design/sidemenu/editthdmenu/menuform/index.jsx
@@ -8,18 +8,16 @@
class MainSearch extends Component {
  static propTpyes = {
    menu: PropTypes.object,      // 菜单信息
    dict: PropTypes.object,      // 字典项
    supMenuList: PropTypes.any,  // 表格数据
    inputSubmit: PropTypes.func  // 回车提交
  }
  state = {
    menu: null
    supMenuList: []
  }
  UNSAFE_componentWillMount () {
    this.setState({
      menu: this.props.menu
      supMenuList: this.props.menu.supMenuList
    })
  }
@@ -30,9 +28,15 @@
    if (submenu) {
      this.setState({
        menu: {...menu, supMenuList: submenu.children}
        supMenuList: submenu.children
      }, () => {
        this.props.form.setFieldsValue({ParentID: submenu.children[0] ? submenu.children[0].MenuID : ''})
      })
    } else {
      this.setState({
        supMenuList: []
      }, () => {
        this.props.form.setFieldsValue({ParentID: ''})
      })
    }
  }
@@ -74,14 +78,14 @@
    return (
      <Form {...formItemLayout} style={{paddingRight: '20px'}} onKeyDown={this.onEnterSubmit}>
        <Row gutter={24}>
          <Col span={24}>
          <Col span={22}>
            <Form.Item label={'一级菜单'}>
              {getFieldDecorator('fstMenuId', {
                initialValue: menu.fstMenuId,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '上级菜单!'
                    message: '请选择上级菜单!'
                  }
                ]
              })(
@@ -97,14 +101,14 @@
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
          <Col span={22}>
            <Form.Item label={'二级菜单'}>
              {getFieldDecorator('ParentID', {
                initialValue: menu.ParentId,
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.select'] + '上级菜单!'
                    message: '请选择上级菜单!'
                  }
                ]
              })(
@@ -119,40 +123,40 @@
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
          <Col span={22}>
            <Form.Item label={'菜单名称'}>
              {getFieldDecorator('MenuName', {
                initialValue: menu.MenuName || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '菜单名称!'
                    message: '请输入菜单名称!'
                  }
                ]
              })(<Input placeholder="" autoFocus autoComplete="off" />)}
            </Form.Item>
          </Col>
          <Col span={24}>
          <Col span={22}>
            <Form.Item label={'菜单参数'}>
              {getFieldDecorator('MenuNo', {
                initialValue: menu.MenuNo || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '菜单参数!'
                    message: '请输入菜单参数!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" />)}
            </Form.Item>
          </Col>
          {menu.Template === 'NewPage' ? <Col span={24}>
          {menu.Template === 'NewPage' ? <Col span={22}>
            <Form.Item label={'链接地址'}>
              {getFieldDecorator('url', {
                initialValue: menu.url || '',
                rules: [
                  {
                    required: true,
                    message: this.props.dict['form.required.input'] + '页面地址!'
                    message: '请输入页面地址!'
                  },
                  {
                    max: 1024,
src/views/design/sidemenu/index.jsx
@@ -1,12 +1,13 @@
import React, {Component} from 'react'
import { connect } from 'react-redux'
import { is, fromJS } from 'immutable'
import { Menu, notification, Popover, Modal, Spin } from 'antd'
import { EditOutlined, SwapOutlined, PlusOutlined, UnlockOutlined, SettingOutlined } from '@ant-design/icons'
import { Menu, Popover, Modal, notification } from 'antd'
import { SwapOutlined, PlusOutlined, SettingOutlined } from '@ant-design/icons'
import moment from 'moment'
import asyncComponent from '@/utils/asyncComponent'
import { resetEditLevel, modifyMenuTree, modifyMainMenu } from '@/store/action'
import options from '@/store/options.js'
import { resetEditLevel } from '@/store/action'
import Utils from '@/utils/utils.js'
import Api from '@/api'
import MKEmitter from '@/utils/events.js'
import MkIcon from '@/components/mk-icon'
@@ -14,22 +15,27 @@
const EditSecMenu = asyncComponent(() => import('./editsecmenu'))
const EditThdMenu = asyncComponent(() => import('./editthdmenu'))
const TransferForm = asyncComponent(() => import('@/templates/zshare/basetransferform'))
const ThawMenu = asyncComponent(() => import('@/components/thawmenu'))
const AddThdMenu = asyncComponent(() => import('./thdmenuplus'))
const ThdMenuForm = asyncComponent(() => import('./thdmenuform'))
const MenuForm = asyncComponent(() => import('./menuform'))
const { SubMenu } = Menu
class Sidemenu extends Component {
  state = {
    subMenulist: [],         // 二级菜单
    editMenu: null,          // 编辑三级菜单时设置
    rootSubmenuKeys: null,
    openKeys: null,
    preview: null
    preview: null,
    loading: false,
    thdVisible: false,
    sysMenu: null,
    formlist: []
  }
  async loadsubmenu (menu) {
    if (!menu || !menu.MenuID) { // 没有主菜单时,清空下级菜单
      this.setState({
        subMenulist: [],
        rootSubmenuKeys: [],
        openKeys: [],
        editMenu: null
@@ -45,28 +51,14 @@
    }
    this.setState({
      subMenulist: menu.children,
      rootSubmenuKeys: menu.children.map(item => item.MenuID),
      openKeys: openKey ? [openKey] : [],
      editMenu: this.props.editLevel === 'level3' ? menu.children.filter(_menu => _menu.MenuID === this.state.editMenu.MenuID)[0] : null
    })
  }
  changemenu(e, menu) {
    e.preventDefault()
    if (this.props.editLevel !== 'HS') {
      return
    }
    MKEmitter.emit('modifyTabs', menu, 'plus')
  }
  componentDidMount () {
    window.addEventListener('storage', (e) => {
      if (e.key !== 'menuUpdate') return
      this.reload()
    })
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  UNSAFE_componentWillReceiveProps (nextProps) {
@@ -74,10 +66,6 @@
      // 主菜单切换,请求2、3级菜单数据
      this.loadsubmenu(nextProps.mainMenu)
    }
  }
  shouldComponentUpdate(nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  onOpenChange = openKeys => {
@@ -94,6 +82,9 @@
  enterSubEdit = (e) => {
    // 编辑二级菜单
    e.stopPropagation()
    if (this.props.mainMenu.children.length === 0) return
    this.props.resetEditLevel('level2')
  }
@@ -102,110 +93,6 @@
    e.stopPropagation()
    this.props.resetEditLevel('level3')
    this.setState({editMenu: menu})
  }
  reload = () => {
    const { mainMenu } = this.props
    let _param = {func: 's_get_pc_menus', systemType: options.sysType, debug: 'Y'}
    _param.pro_sys = window.GLOB.systemType === 'production' ? 'Y' : ''
    Api.getSystemConfig(_param).then(result => {
      // 登录超时
      if (!result) return
      if (result.status) {
        let res = this.getMenulist(result)
        let _mainMenu = res.menulist.filter(item => item.MenuID === mainMenu.MenuID)[0]
        this.props.modifyMenuTree(res.menulist)
        this.props.modifyMainMenu(_mainMenu || null)
      } else {
        notification.error({
          top: 92,
          message: result.message,
          duration: 10
        })
      }
      this.loadsubmenu(this.props.mainMenu)
    })
  }
  getMenulist = (result) => {
    let iframes = ['Main/Index', 'bda/rdt', 'Home/rdt']
    let menulist = result.fst_menu.map(fst => {
      let fstItem = {
        MenuID: fst.MenuID,
        MenuName: fst.MenuName,
        PageParam: {OpenType: 'menu', linkUrl: ''},
        children: []
      }
      if (fst.PageParam) {
        try {
          fstItem.PageParam = JSON.parse(fst.PageParam)
        } catch (e) {
          fstItem.PageParam = {OpenType: 'menu', linkUrl: ''}
        }
      }
      if (fst.snd_menu) {
        fstItem.children = fst.snd_menu.map(snd => {
          let sndItem = {
            ParentId: fst.MenuID,
            MenuID: snd.MenuID,
            MenuName: snd.MenuName,
            PageParam: {Icon: 'folder'},
            children: []
          }
          if (snd.PageParam) {
            try {
              sndItem.PageParam = JSON.parse(snd.PageParam)
            } catch (e) {
              sndItem.PageParam = {Icon: 'folder'}
            }
          }
          if (snd.trd_menu) {
            sndItem.children = snd.trd_menu.map(trd => {
              let trdItem = {
                FstId: fst.MenuID,
                ParentId: snd.MenuID,
                MenuID: trd.MenuID,
                MenuName: trd.MenuName,
                MenuNo: trd.MenuNo,
                EasyCode: trd.EasyCode,
                type: 'CommonTable',            // 默认值为常用表
                OpenType: 'newtab'              // 打开方式
              }
              if (trd.LinkUrl && iframes.includes(trd.LinkUrl.split('?')[0])) {
                trdItem.type = 'iframe'
                trdItem.LinkUrl = trd.LinkUrl.replace('&amp;', '&')
                trdItem.forbidden = true
              } else {
                try {
                  trdItem.PageParam = trd.PageParam ? JSON.parse(trd.PageParam) : {OpenType: 'newtab'}
                } catch (e) {
                  trdItem.PageParam = {OpenType: 'newtab'}
                }
                trdItem.type = trdItem.PageParam.Template || trdItem.type
                trdItem.OpenType = trdItem.PageParam.OpenType || trdItem.OpenType
                if (trdItem.type === 'CustomPage' && this.props.memberLevel < 20) { // 会员等级大于等于20时,有编辑权限
                  trdItem.forbidden = true
                }
              }
              return trdItem
            })
          }
          return sndItem
        })
      }
      return fstItem
    })
    return { menulist }
  }
  exitEdit = () => {
@@ -226,23 +113,172 @@
      }
      _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
      window.open(`#/menudesign/${_param}`)
    } else {
    } else if (['RolePermission', 'NewPage'].includes(cell.type)) {
      cell.Template = cell.PageParam.Template
      cell.url = cell.PageParam.url || ''
      cell.fstMenuId = cell.FstId
      cell.supMenuList = this.props.mainMenu.children
      cell.fstMenuList = this.props.menuTree
      this.setState({
        thdVisible: true,
        loading: false,
        sysMenu: cell
      })
    }
  }
  addSecMenu = () => {
    this.setState({
      visible: true,
      loading: false,
      formlist: [
        { // 父级菜单
          type: 'select',
          key: 'parentId',
          label: '上级菜单',
          initVal: this.props.mainMenu.MenuID,
          required: true,
          options: this.props.menuTree
        },
        { // 菜单名称
          type: 'text',
          key: 'menuName',
          label: '菜单名称',
          initVal: '',
          required: true,
          readonly: false
        },
        { // 菜单图标
          type: 'icon',
          key: 'icon',
          label: '图标',
          initVal: 'folder',
          required: true
        }
      ]
    })
  }
  secSubmit = () => {
    this.menuFormRef.handleConfirm().then(values => {
      let param = {
        ParentID: values.parentId,
        MenuID: Utils.getuuid(),
        MenuName: values.menuName,
        PageParam: JSON.stringify({
          Icon: values.icon
        })
      }
      param.func = 'sPC_SndMenu_Add'
      param.Sort = (this.props.mainMenu.children.length + 1) * 10
      this.setState({
        loading: true
      })
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          this.setState({
            loading: false,
            visible: false
          })
          MKEmitter.emit('mkUpdateMenuList')
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    })
  }
  /**
   * @description 三级菜单修改
   */
  thdSubmit = () => {
    const { sysMenu } = this.state
    this.menuThdFormRef.handleConfirm().then(res => {
      let PageParam = {
        Template: sysMenu.Template,
        OpenType: 'newtab'
      }
      if (sysMenu.Template === 'NewPage') {
        PageParam.OpenType = 'NewPage'
        PageParam.url = res.url
      }
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: res.fstMenuId,
        SndID: res.ParentID,
        ParentID: res.ParentID,
        MenuID: sysMenu.MenuID,
        MenuNo: res.MenuNo,
        Template: sysMenu.Template,
        MenuName: res.MenuName,
        PageParam: JSON.stringify(PageParam),
        LongParam: '',
        LText: '',
        LTexttb: ''
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      this.setState({
        loading: true
      })
      Api.getSystemConfig(param).then(response => {
        if (response.status) {
          this.setState({
            loading: false,
            thdVisible: false,
            sysMenu: null
          })
          MKEmitter.emit('mkUpdateMenuList')
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
  render () {
    const { mainMenu, editLevel } = this.props
    const { visible } = this.state
    let isnew = true
    const { visible, loading, thdVisible } = this.state
    return (
      <aside className="mk-sys-side-menu ant-menu-dark mk-edit">
        {!(editLevel === 'level2' || editLevel === 'level3') &&
        {editLevel !== 'level2' && editLevel !== 'level3' && mainMenu ?
          <Menu openKeys={this.state.openKeys} onOpenChange={this.onOpenChange} mode="inline" theme="dark">
          {!editLevel && mainMenu ? <li className="sup-menu"><EditOutlined onClick={this.enterSubEdit} className="edit-check"/></li> : null}
          {this.state.subMenulist && this.state.subMenulist.map((item, index) => {
          <li className="sup-menu">
            <Popover overlayClassName="mk-popover-control-wrap mk-menu-control" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <PlusOutlined onClick={this.addSecMenu}/>
                <SwapOutlined onClick={this.enterSubEdit} className={'mk-swap' + (mainMenu.children.length === 0 ? ' disabled' : '')}/>
                <div style={{display: 'inline-block', minWidth: '32px'}}><ThawMenu ParentId={mainMenu.MenuID} Type="20"/></div>
              </div>
            } trigger="hover" placement="top">
              <SettingOutlined className="edit-check"/>
            </Popover>
          </li>
          {mainMenu.children.map((item, index) => {
            return (
              <SubMenu
                key={item.MenuID}
@@ -253,61 +289,72 @@
                  </span>
                }
              >
                {!editLevel ? <li className={'ant-menu-item ' + (item.children.length > 0 ? 'sub-menu' : '')}>
                  {!isnew ? <EditOutlined onClick={(e) => {this.enterThrEdit(e, item)}} className="edit-check"/> :
                <li className={'ant-menu-item ' + (item.children.length > 0 ? 'sub-menu' : '')}>
                  <Popover overlayClassName="mk-popover-control-wrap mk-menu-control" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
                    <div className="mk-popover-control">
                      <PlusOutlined onClick={(e) => {this.enterThrEdit(e, item)}} className="mk-edit-menu"/>
                      <SwapOutlined onClick={(e) => {this.enterThrEdit(e, item)}} className="mk-edit-menu mk-swap"/>
                      <UnlockOutlined onClick={(e) => {this.enterThrEdit(e, item)}} className="mk-edit-menu"/>
                      <div style={{display: 'inline-block', minWidth: '32px'}}><AddThdMenu mainMenu={mainMenu} supMenu={item} menuTree={this.props.menuTree}/></div>
                      <SwapOutlined onClick={(e) => {this.enterThrEdit(e, item)}} className="mk-swap"/>
                      <div style={{display: 'inline-block', minWidth: '32px'}}><ThawMenu ParentId={item.MenuID} Type="30"/></div>
                    </div>
                  } trigger="hover" placement="top">
                    <SettingOutlined className="edit-check"/>
                  </Popover>}
                </li> : null}
                  </Popover>
                </li>
                {item.children.map(cell => {
                  return (
                    <Menu.Item key={cell.MenuID}>
                      {editLevel !== 'HS' ?
                        <span className="editable-menu-item" onDoubleClick={() => this.editmenu(cell)}>{cell.MenuName}</span> :
                        <a href={cell.src} id={cell.MenuID} onClick={(e) => this.changemenu(e, cell)}>{cell.MenuName}</a>
                      }
                      <span className="editable-menu-item" onDoubleClick={(e) => {e.stopPropagation();this.editmenu(cell)}}>{cell.MenuName}</span>
                    </Menu.Item>
                  )
                })}
              </SubMenu>
            )
          })}
        </Menu>}
        {editLevel === 'level2' ?
        </Menu> : null}
        {editLevel === 'level2' && mainMenu ?
          <EditSecMenu
            menulist={this.state.subMenulist}
            menulist={mainMenu.children}
            menuTree={this.props.menuTree}
            supMenu={this.props.mainMenu}
            reload={this.reload}
            exitEdit={this.exitEdit}
          /> : null
        }
        {editLevel === 'level3' && this.state.editMenu ?
        {editLevel === 'level3' && mainMenu && this.state.editMenu ?
          <EditThdMenu
            menulist={this.state.editMenu.children}
            supMenuList={this.state.subMenulist}
            supMenuList={mainMenu.children}
            supMenu={this.state.editMenu}
            reload={this.reload}
            exitEdit={this.exitEdit}
          /> : null
        }
        <Modal
          title="解冻菜单"
          width={600}
          title="添加菜单"
          visible={visible}
          onOk={this.thawMemuSubmit}
          confirmLoading={this.state.confirmLoading}
          onCancel={this.thawMemuCancel}
          onOk={this.secSubmit}
          // confirmLoading={loading}
          onCancel={() => this.setState({visible: false})}
          destroyOnClose
        >
          {!this.state.thawmenulist ? <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" /> :
          <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawmenulist}/>}
          <MenuForm
            inputSubmit={this.secSubmit}
            formlist={this.state.formlist}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />
        </Modal>
        <Modal
          title="修改菜单"
          visible={thdVisible}
          width={600}
          onOk={this.thdSubmit}
          confirmLoading={loading}
          onCancel={() => {this.setState({thdVisible: false})}}
          destroyOnClose
        >
          <ThdMenuForm
            menu={this.state.sysMenu}
            inputSubmit={this.thdSubmit}
            wrappedComponentRef={(inst) => this.menuThdFormRef = inst}
          />
        </Modal>
      </aside>
    )
@@ -324,8 +371,6 @@
const mapDispatchToProps = (dispatch) => {
  return {
    modifyMenuTree: (menuTree) => dispatch(modifyMenuTree(menuTree)),
    modifyMainMenu: (mainMenu) => dispatch(modifyMainMenu(mainMenu)),
    resetEditLevel: (level) => dispatch(resetEditLevel(level))
  }
}
src/views/design/sidemenu/menuelement/card.jsx
@@ -33,30 +33,29 @@
    closeCard(id)
  }
  let _param = ''
  if (card.type === 'CustomPage') {
    _param = {
      MenuType: 'custom',
      MenuId: card.MenuID,
      ParentId: card.ParentId,
      MenuName: card.MenuName,
      MenuNo: card.MenuNo
    }
    _param = window.btoa(window.encodeURIComponent(JSON.stringify(_param)))
  }
  return (
    <div className="side-card" style={{ opacity }}>
      <div ref={node => drag(drop(node))}>
        {card.PageParam && card.PageParam.Icon && <MkIcon type={card.PageParam.Icon} />}
        {card.MenuName}
  if (card.level === 'second') {
    return (
      <div className="side-card" style={{ opacity }}>
        <div ref={node => drag(drop(node))}>
          {card.PageParam && card.PageParam.Icon && <MkIcon type={card.PageParam.Icon} />}
          {card.MenuName}
        </div>
        <EditOutlined className="edit" onClick={edit} />
        <CloseOutlined className="close" onClick={close} />
      </div>
      {/* 自定义模板,在新页面编辑 */}
      {!card.forbidden && card.type !== 'CustomPage' ? <EditOutlined className="edit" onClick={edit} /> : null}
      {!card.forbidden && card.type === 'CustomPage' ? <EditOutlined className="edit" onClick={() => {window.open(`#/menudesign/${_param}`)}}/> : null}
      {card.forbidden && card.type === 'CustomPage' ? <EditOutlined className="edit" style={{color: '#959595', cursor: 'not-allowed'}} title="会员等级不够,无开发权限。"/> : null}
      <CloseOutlined className="close" onClick={close} />
    </div>
  )
    )
  } else {
    return (
      <div className="side-card" style={{ opacity }}>
        <div ref={node => drag(drop(node))}>
          {card.MenuName}
        </div>
        {/* 自定义模板,在新页面编辑 */}
        {!card.forbidden ? <EditOutlined className="edit" onClick={edit} /> : null}
        {card.forbidden && card.type === 'CustomPage' ? <EditOutlined className="edit" style={{color: '#959595', cursor: 'not-allowed'}} title="会员等级不够,无开发权限。"/> : null}
        <CloseOutlined className="close" onClick={close} />
      </div>
    )
  }
}
export default Card
src/views/design/sidemenu/menuelement/index.scss
@@ -15,7 +15,7 @@
}
.side-card {
  position: relative;
  border: 1px dashed gray;
  border: 1px dashed #535353;
  margin-top: 8px;
  height: 40px;
  width: 98%;
src/views/design/sidemenu/menuform/index.jsx
@@ -7,9 +7,8 @@
const MkEditIcon = asyncComponent(() => import('@/components/mkIcon'))
class MainSearch extends Component {
class MainForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,     // 字典项
    formlist: PropTypes.array,
    inputSubmit: PropTypes.func
  }
@@ -48,10 +47,10 @@
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.input'] + item.label + '!'
                    message: '请输入' + item.label + '!'
                  }
                ]
              })(<Input placeholder="" autoFocus={item.key.toLowerCase() === 'menuname'} autoComplete="off" disabled={item.readonly} />)}
              })(<Input placeholder="" autoFocus={item.key.toLowerCase() === 'menuname'} autoComplete="off" disabled={item.readonly} onPressEnter={() => this.props.inputSubmit()}/>)}
            </Form.Item>
          </Col>
        )
@@ -64,7 +63,7 @@
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                    message: '请选择' + item.label + '!'
                  }
                ]
              })(
@@ -93,7 +92,7 @@
                rules: [
                  {
                    required: !!item.required,
                    message: this.props.dict['form.required.select'] + item.label + '!'
                    message: '请选择' + item.label + '!'
                  }
                ]
              })(
@@ -120,13 +119,6 @@
    })
  }
  onEnterSubmit = (e) => {
    // 表单回车提交
    if (e.key !== 'Enter') return
    this.props.inputSubmit && this.props.inputSubmit()
  }
  render() {
    const formItemLayout = {
      labelCol: {
@@ -139,11 +131,11 @@
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form" id="form-box" onKeyDown={this.onEnterSubmit}>
      <Form {...formItemLayout} id="form-box">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
export default Form.create()(MainForm)
src/views/design/sidemenu/menuform/index.scss
@@ -1,17 +1 @@
.ant-advanced-search-form.main-search {
  padding: 0px 24px 20px;
  border-bottom: 1px solid #d9d9d9;
  .ant-form-item {
    display: flex;
    margin-bottom: 10px;
  }
  .ant-form-item-control-wrapper {
    flex: 1;
  }
  .ant-form-item-label {
    width: 100px;
  }
}
.ant-advanced-search-form {
  position: relative;
}
src/views/design/sidemenu/thdmenuform/index.jsx
New file
@@ -0,0 +1,170 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select } from 'antd'
// import './index.scss'
const { TextArea } = Input
class MainSearch extends Component {
  static propTpyes = {
    menu: PropTypes.object,      // 菜单信息
    inputSubmit: PropTypes.func  // 回车提交
  }
  state = {
    supMenuList: []
  }
  UNSAFE_componentWillMount () {
    this.setState({
      supMenuList: fromJS(this.props.menu.supMenuList).toJS()
    })
  }
  changeMenu = (val) => {
    const { menu } = this.props
    let submenu = menu.fstMenuList.filter(item => item.MenuID === val)[0]
    if (submenu) {
      this.setState({
        supMenuList: submenu.children
      }, () => {
        this.props.form.setFieldsValue({ParentID: submenu.children[0] ? submenu.children[0].MenuID : ''})
      })
    } else {
      this.setState({
        supMenuList: []
      }, () => {
        this.props.form.setFieldsValue({ParentID: ''})
      })
    }
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  render() {
    const { menu } = this.props
    const { getFieldDecorator } = this.props.form
    const { supMenuList } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} style={{paddingRight: '20px'}}>
        <Row gutter={24}>
          <Col span={22}>
            <Form.Item label={'一级菜单'}>
              {getFieldDecorator('fstMenuId', {
                initialValue: menu.fstMenuId,
                rules: [
                  {
                    required: true,
                    message: '请选择上级菜单!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                  onChange={this.changeMenu}
                >
                  {menu.fstMenuList.map(option =>
                    <Select.Option key={option.MenuID} value={option.MenuID}>{option.text || option.MenuName}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={22}>
            <Form.Item label={'二级菜单'}>
              {getFieldDecorator('ParentID', {
                initialValue: menu.ParentId,
                rules: [
                  {
                    required: true,
                    message: '请选择上级菜单!'
                  }
                ]
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {supMenuList.map(option =>
                    <Select.Option key={option.MenuID} value={option.MenuID}>{option.text || option.MenuName}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={22}>
            <Form.Item label={'菜单名称'}>
              {getFieldDecorator('MenuName', {
                initialValue: menu.MenuName || '',
                rules: [
                  {
                    required: true,
                    message: '请输入菜单名称!'
                  }
                ]
              })(<Input placeholder="" autoFocus autoComplete="off" onPressEnter={() => this.props.inputSubmit()}/>)}
            </Form.Item>
          </Col>
          <Col span={22}>
            <Form.Item label={'菜单参数'}>
              {getFieldDecorator('MenuNo', {
                initialValue: menu.MenuNo || '',
                rules: [
                  {
                    required: true,
                    message: '请输入菜单参数!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onPressEnter={() => this.props.inputSubmit()}/>)}
            </Form.Item>
          </Col>
          {menu.Template === 'NewPage' ? <Col span={22}>
            <Form.Item label={'链接地址'}>
              {getFieldDecorator('url', {
                initialValue: menu.url || '',
                rules: [
                  {
                    required: true,
                    message: '请输入页面地址!'
                  },
                  {
                    max: 1024,
                    message: '地址最长为1024个字符!'
                  }
                ]
              })(<TextArea rows={2} />)}
            </Form.Item>
          </Col> : null}
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/views/design/sidemenu/thdmenuform/index.scss
src/views/design/sidemenu/thdmenuplus/index.jsx
New file
@@ -0,0 +1,309 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Modal, notification, Col, Card, Tabs, Row, Input, Button } from 'antd'
import { PlusOutlined } from '@ant-design/icons'
import moment from 'moment'
import Api from '@/api'
import { sysTemps } from '@/utils/option.js'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
import Preview from './preview'
import asyncComponent from '@/utils/asyncComponent'
import mainsubtable from '@/assets/img/mainsubtable.jpg'
import treepage from '@/assets/img/treepage.jpg'
import calendar from '@/assets/img/calendar.jpg'
import customImg from '@/assets/img/custom.jpg'
import './index.scss'
const MenuForm = asyncComponent(() => import('../thdmenuform'))
const { TabPane } = Tabs
const { Search } = Input
class ThdMenuAdd extends Component {
  static propTpyes = {
    mainMenu: PropTypes.object,
    supMenu: PropTypes.object,
    menuTree: PropTypes.array,
    Type: PropTypes.string
  }
  state = {
    sysTemplates: [],
    usedTemplates: [],
    tempSearchKey: '',
    addVisible: false,
    preview: null,
    visible: false,
    sysMenu: null,
    loading: false
  }
  UNSAFE_componentWillMount() {
    this.getUsedTemplate()
  }
  getUsedTemplate = () => {
    let { sysTemplates } = this.state
    let memberLevel = Utils.getMemberLevel()
    const illust = { // 模板图片,用于已使用模板
      CommonTable: mainsubtable,
      TreePage: treepage,
      CalendarPage: calendar,
      CustomPage: customImg
    }
    Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'menu'}).then(res => {
      let _templates = []
      res.UserTemp.forEach(temp => {
        if (!['CommonTable', 'TreePage', 'CalendarPage', 'CustomPage'].includes(temp.Template)) {
          return
        } else if (temp.Template === 'CustomPage' && memberLevel < 20) {
          temp.disabled = true
          temp.disTitle = '会员等级不够,无开发权限。'
        }
        _templates.push({
          uuid: temp.MenuID,
          title: temp.MenuName,
          type: temp.Template,
          url: illust[temp.Template],
          disabled: temp.disabled || false,
          disTitle: temp.disTitle || ''
        })
      })
      sysTemplates = sysTemps.map(temp => {
        if (temp.type === 'CustomPage' && memberLevel < 20) {
          temp.disabled = true
          temp.disTitle = '会员等级不够,无开发权限。'
        }
        return temp
      })
      this.setState({
        usedTemplates: _templates,
        sysTemplates: sysTemplates
      })
    })
  }
  trigger = () => {
    this.setState({
      visible: true
    })
    document.getElementById('root').style.overflowY = 'hidden'
  }
  previewPicture = (template) => {
    if (template.disabled) return
    // 图片预览
    this.setState({
      preview: template.url,
      pretemplate: template
    })
  }
  cancelPrePicture = () => {
    // 关闭图片预览
    this.setState({
      preview: null
    })
  }
  // this.setState({
  //   tabview: 'template',
  //   editMenu: {
  //     MenuID: Utils.getuuid(),
  //     MenuName: '',
  //     MenuNo: '',
  //     type: '',
  //     PageParam: '',
  //     LongParam: '',
  //     isSubtable: '', // 是否为主子表
  //     ParentId: this.props.supMenu.MenuID,
  //     supMenuList: this.props.supMenuList,
  //     fstMenuId: this.props.mainMenu.MenuID,
  //     fstMenuList: this.props.menuTree,
  //     menuSort: (this.props.menulist.length + 1) * 10 // 新建菜单设置排序
  //   }
  // }, () => {
  //   document.getElementById('root').style.overflowY = 'hidden'
  // })
  useTemplate = (template) => {
    const { mainMenu, supMenu, menuTree } = this.props
    let sysMenu = {
      MenuID: Utils.getuuid(),
      MenuName: template.title,
      Template: template.type,
      fstMenuId: mainMenu.MenuID,
      ParentId: supMenu.MenuID,
      menuSort: (supMenu.children.length + 1) * 10,
      copyId: template.uuid || '',
      fstMenuList: menuTree,
      supMenuList: mainMenu.children
    }
    this.setState({
      visible: false
    }, () => {
      this.setState({
        addVisible: true,
        sysMenu: sysMenu
      })
      document.getElementById('root').style.overflowY = 'unset'
    })
  }
  memuSubmit = () => {
    const { sysMenu } = this.state
    this.menuFormRef.handleConfirm().then(values => {
      let PageParam = {
        Template: sysMenu.Template,
        OpenType: 'newtab'
      }
      if (sysMenu.Template === 'NewPage') {
        PageParam.OpenType = 'NewPage'
        PageParam.url = values.url
      }
      if (sysMenu.copyId) {
        PageParam.copyMenuId = sysMenu.copyId
      }
      let param = {
        func: 'sPC_TrdMenu_AddUpt',
        FstID: values.fstMenuId,
        SndID: values.ParentID,
        ParentID: values.ParentID,
        MenuID: sysMenu.MenuID,
        MenuNo: values.MenuNo,
        Template: sysMenu.Template,
        MenuName: values.MenuName,
        PageParam: JSON.stringify(PageParam),
        LongParam: '',
        LText: '',
        LTexttb: '',
        Sort: sysMenu.menuSort
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      this.setState({
        loading: true
      })
      Api.getSystemConfig(param).then(response => {
        if (response.status) {
          this.setState({
            loading: false,
            addVisible: false,
            sysMenu: null
          })
          MKEmitter.emit('mkUpdateMenuList')
        } else {
          this.setState({
            loading: false
          })
          notification.warning({
            top: 92,
            message: response.message,
            duration: 5
          })
        }
      })
    })
  }
  render() {
    const { visible, loading, tempSearchKey } = this.state
    return (
      <>
        <PlusOutlined onClick={this.trigger}/>
        <Modal
          className="mk-template-modal"
          visible={visible}
          onOk={this.submit}
          onCancel={() => this.setState({visible: false}, () => {document.getElementById('root').style.overflowY = 'unset'})}
          destroyOnClose
        >
          <Tabs defaultActiveKey="1">
            <TabPane tab="系统模板" key="1">
              <Row>
                {this.state.sysTemplates.map((template, index) => {
                  return (
                    <Col key={`${index}`} className={template.disabled ? 'disabled' : ''} title={template.disTitle || ''} span={8}>
                      <Card
                        title={template.title}>
                        <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                        <div className="card-operation">
                          <Button type="primary" onClick={() => {this.useTemplate(template, 'sys')}}>使用模板</Button>
                        </div>
                      </Card>
                    </Col>
                  )
                })}
              </Row>
            </TabPane>
            <TabPane tab="已使用模板" key="2">
              <Row>
                <Col span={8}>
                  <Search placeholder="请输入菜单名称" defaultValue={''} onSearch={value => {this.setState({tempSearchKey: value})}} enterButton />
                </Col>
              </Row>
              <Row>
                {this.state.usedTemplates.map((template, index) => {
                  if (!tempSearchKey || template.title.toLowerCase().indexOf(tempSearchKey.toLowerCase()) >= 0) {
                    return (
                      <Col key={template.type + index} className={template.disabled ? 'disabled' : ''} title={template.disTitle || ''} span={6}>
                        <Card
                          title={template.title}>
                          <img onClick={() => {this.previewPicture(template)}} src={template.url} alt=""/>
                          <div className="card-operation">
                            <Button type="primary" onClick={() => {this.useTemplate(template, 'user')}}>使用模板</Button>
                          </div>
                        </Card>
                      </Col>
                    )
                  } else {
                    return null
                  }
                })}
              </Row>
            </TabPane>
          </Tabs>
          {/* 图片预览 */}
          <Preview cancel={this.cancelPrePicture} preview={this.state.preview} template={this.state.pretemplate} confirm={this.useTemplate}/>
        </Modal>
        {/* 添加系统菜单 */}
        <Modal
          title="添加菜单"
          visible={this.state.addVisible}
          width={600}
          onOk={this.memuSubmit}
          confirmLoading={loading}
          onCancel={() => {this.setState({addVisible: false})}}
          destroyOnClose
        >
          <MenuForm
            menu={this.state.sysMenu}
            inputSubmit={this.memuSubmit}
            wrappedComponentRef={(inst) => this.menuFormRef = inst}
          />
        </Modal>
      </>
    )
  }
}
export default ThdMenuAdd
src/views/design/sidemenu/thdmenuplus/index.scss
New file
@@ -0,0 +1,137 @@
.editboard {
  position: fixed;
  z-index: 1070;
  padding-top: 48px;
  top: 0px;
  left: 0px;
  right: 0px;
  bottom: 0px;
  background: rgba(0, 0, 0, 0.35);
  .workplace {
    position: relative;
    width: calc(100vw - 235px);
    height: 100%;
    overflow-y: auto;
    left: 235px;
    background: #ffffff;
    .top-btn {
      position: absolute;
      z-index: 1;
      top: 12px;
      right: 20px;
      cursor: pointer;
    }
    .top-btn.submit {
      right: 100px;
    }
  }
  .workplace::-webkit-scrollbar {
    width: 7px;
  }
  .workplace::-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);
  }
  .workplace::-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);
  }
}
.mk-template-modal {
  width: calc(100vw - 235px)!important;
  left: 117px;
  top: 48px;
  padding-bottom: 0px;
  .ant-modal-close {
    .ant-modal-close-x {
      height: 50px;
      line-height: 50px;
    }
  }
  .ant-modal-header {
    display: none;
  }
  .ant-modal-footer {
    display: none;
  }
  .ant-modal-body {
    padding: 0px;
    .ant-tabs-tabpane {
      height: calc(100vh - 110px);
      overflow-y: auto;
      padding: 0 15px 20px 15px;
      .ant-col {
        padding: 10px;
      }
      .ant-col.disabled {
        cursor: not-allowed;
        .ant-card-head-title {
          color: #959595;
        }
        .card-operation {
          display: none;
        }
        img {
          cursor: not-allowed;
        }
      }
      .ant-card-head-title {
        text-align: center;
      }
      .ant-card-body {
        padding: 2px;
        position: relative;
        text-align: center;
        overflow: hidden;
        .card-operation {
          position: absolute;
          right: 0px;
          top: 0;
          height: 0px;
          overflow: hidden;
          transition: height 0.3s;
          button {
            height: 30px;
            padding: 0 10px;
            margin-top: 5px;
            margin-right: 10px;
            display: none;
          }
        }
      }
      .ant-card-body:hover {
        .card-operation {
          height: 40px;
          button {
            display: inline-block;
          }
        }
      }
      img {
        max-width: 100%;
        cursor: zoom-in;
      }
    }
    .ant-tabs-tabpane::-webkit-scrollbar {
      width: 7px;
    }
    .ant-tabs-tabpane::-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-tabs-tabpane::-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);
    }
  }
}
src/views/design/sidemenu/thdmenuplus/preview/index.jsx
src/views/design/sidemenu/thdmenuplus/preview/index.scss