king
2020-08-20 3683e1475e8d74f690172a468518d88d91a69ccc
2020-08-20
31个文件已修改
7个文件已添加
1395 ■■■■ 已修改文件
package-lock.json 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/table.scss 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/img/custom.jpg 补丁 | 查看 | 原始文档 | blame | 历史
src/components/header/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/sidemenu/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 109 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/en-US/mob.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/mob.js 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/locales/zh-CN/model.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/header/index.jsx 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/header/index.scss 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menuform/index.jsx 225 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/login/mob-login-1/index.jsx 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/header/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/router/index.js 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/calendar/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/commontable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/subtabtable/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/treepage/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/normalTable/index.jsx 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.scss 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/index.scss 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/editthdmenu/index.jsx 44 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/menuconfig/menuelement/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.scss 23 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/tablecomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/tablecomponent/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.scss 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/treepageconfig/index.scss 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils.js 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 394 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.scss 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -3232,6 +3232,11 @@
        }
      }
    },
    "base64-arraybuffer": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz",
      "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ=="
    },
    "base64-js": {
      "version": "1.3.1",
      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
@@ -4337,6 +4342,14 @@
            "uniq": "^1.0.1"
          }
        }
      }
    },
    "css-line-break": {
      "version": "1.1.1",
      "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-1.1.1.tgz",
      "integrity": "sha512-1feNVaM4Fyzdj4mKPIQNL2n70MmuYzAXZ1aytlROFX1JsOo070OsugwGjj7nl6jnDJWHDM8zRZswkmeYVWZJQA==",
      "requires": {
        "base64-arraybuffer": "^0.2.0"
      }
    },
    "css-loader": {
@@ -8681,6 +8694,14 @@
        "util.promisify": "1.0.0"
      }
    },
    "html2canvas": {
      "version": "1.0.0-rc.7",
      "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.0.0-rc.7.tgz",
      "integrity": "sha512-yvPNZGejB2KOyKleZspjK/NruXVQuowu8NnV2HYG7gW7ytzl+umffbtUI62v2dCHQLDdsK6HIDtyJZ0W3neerA==",
      "requires": {
        "css-line-break": "1.1.1"
      }
    },
    "htmlparser2": {
      "version": "3.10.1",
      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
package.json
@@ -42,6 +42,7 @@
    "file-loader": "3.0.1",
    "fs-extra": "7.0.1",
    "html-webpack-plugin": "4.0.0-beta.5",
    "html2canvas": "^1.0.0-rc.7",
    "http-proxy-middleware": "^0.20.0",
    "identity-obj-proxy": "3.0.0",
    "immutability-helper": "^3.0.1",
src/api/index.js
@@ -660,7 +660,7 @@
          values += key + param[key]
        }
      })
      param.sign  = md5(values)
      param.sign = md5(values)
      param.t = new Date().getTime()
      return new Promise(resolve => {
src/assets/css/table.scss
@@ -411,6 +411,9 @@
  }
  // gray
  .background.transparent {
    @include tableBackground(transparent);
  }
  .background.gray-1 {
    @include tableBackground(#f5f5f5);
  }
@@ -832,6 +835,9 @@
  }
  // gray
  .font.transparent {
    color: transparent;
  }
  .font.gray-1 {
    color: #f5f5f5;
  }
src/assets/img/custom.jpg
src/components/header/index.jsx
@@ -744,9 +744,9 @@
        {this.props.editLevel === 'HS' ? <Button className="level4-close" type="primary" onClick={this.exitManage}>退出</Button> : null}
        {/* 进入编辑按钮 */}
        {this.props.editState && !this.props.editLevel ? <Icon onClick={this.enterEdit} className="edit-check" type="edit" /> : null}
        {/* {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
        {this.props.editState && !this.props.editLevel && options.sysType === 'local' && window.GLOB.systemType !== 'production' ?
          <a href="#/mobmanage" target="_blank" className="mobile" type="edit"> 应用管理 <Icon type="arrow-right" /></a> : null
        } */}
        }
        {/* 编辑菜单 */}
        {this.props.editLevel === 'level1' ? <EditMenu menulist={this.state.menulist} reload={this.reload} exitEdit={this.exitEdit}/> : null}
        {/* 头像、用户名 */}
src/components/sidemenu/index.jsx
@@ -109,7 +109,9 @@
        if (item.FunMenu) {
          _smenu.children = item.FunMenu.map(child => {
            let _tmenu = {}
            let _tmenu = {
              ParentId: item.ParentID
            }
            // 打开新页面链接
            _tmenu.src = '#/main/' + window.btoa('mm=' + menu.MenuID + '&sm=' + _smenu.MenuID + '&tm=' + child.MenuID + '&ud=' + msg)
src/index.js
@@ -53,35 +53,35 @@
  .then(config => {
    if (!config) return
    
    window.GLOB = {}
    window.GLOB.appId = config.appId || ''
    window.GLOB.lineColor = config.lineColor || ''
    window.GLOB.filter = config.filter || ''
    let GLOB = {}
    GLOB.appId = config.appId || ''
    GLOB.lineColor = config.lineColor || ''
    GLOB.filter = config.filter || ''
    // 只有业务系统才可以设置为正式系统
    if (options.sysType === 'local' && (config.systemType === 'official' || config.systemType === 'production')) {
      window.GLOB.systemType = 'production'
      GLOB.systemType = 'production'
    } else {
      window.GLOB.systemType = ''
      GLOB.systemType = ''
    }
    if (options.sysType === 'cloud') { // cloud不可设置单点服务器地址,云端appkey为系统设置
      window.GLOB.appkey = options.cakey
      window.GLOB.mainSystemApi = ''
      GLOB.appkey = options.cakey
      GLOB.mainSystemApi = ''
    } else if (options.sysType === 'SSO') { // sso不可设置单点服务器地址
      window.GLOB.mainSystemApi = ''
      GLOB.mainSystemApi = ''
      if (config.appkey === options.cakey) {
        window.GLOB.appkey = ''
        GLOB.appkey = ''
        console.warn('单点系统appkey不可与云端相同')
      } else {
        window.GLOB.appkey = config.appkey
        GLOB.appkey = config.appkey
      }
    } else if (options.sysType === 'local') { // 业务系统
      if (config.appkey === options.cakey) {
        window.GLOB.appkey = ''
        GLOB.appkey = ''
        console.warn('业务系统appkey不可与云端相同')
      } else {
        window.GLOB.appkey = config.appkey
        GLOB.appkey = config.appkey
      }
      if (config.mainSystemApi) {
        let systemApi = config.mainSystemApi
@@ -96,7 +96,7 @@
      
        // // 业务系统连接云端时,格式化处理
        // if (systemApi && systemApi === /^(http|https):\/\/[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62}|(:[0-9]{1,4}))+\.?/ig.exec(options.cloudServiceApi)[0]) {
        //   window.GLOB.dataFormat = true
        //   GLOB.dataFormat = true
        // }
      
        // if (systemApi) {
@@ -107,10 +107,10 @@
        if (systemApi && systemApi.indexOf('cloud.mk9h.cn') > -1) {
          systemApi = ''
        } else if (systemApi && systemApi.indexOf('sso.mk9h.cn') > -1) {
          window.GLOB.dataFormat = true
          GLOB.dataFormat = true
        }
      
        window.GLOB.mainSystemApi = systemApi
        GLOB.mainSystemApi = systemApi
      }
    }
@@ -120,23 +120,23 @@
      try {
        _systemMsg = JSON.parse(window.decodeURIComponent(window.atob(_systemMsg)))
        window.GLOB.platTitle = _systemMsg.platTitle
        window.GLOB.platName = _systemMsg.platName
        window.GLOB.favicon = _systemMsg.favicon
        window.GLOB.loginlogo = _systemMsg.loginlogo
        window.GLOB.copyRight = _systemMsg.copyRight
        window.GLOB.ICP = _systemMsg.ICP
        window.GLOB.bgImage = _systemMsg.bgImage
        window.GLOB.mainlogo = _systemMsg.mainlogo
        window.GLOB.doclogo = _systemMsg.doclogo
        window.GLOB.webSite = _systemMsg.webSite
        window.GLOB.style = _systemMsg.style
        GLOB.platTitle = _systemMsg.platTitle
        GLOB.platName = _systemMsg.platName
        GLOB.favicon = _systemMsg.favicon
        GLOB.loginlogo = _systemMsg.loginlogo
        GLOB.copyRight = _systemMsg.copyRight
        GLOB.ICP = _systemMsg.ICP
        GLOB.bgImage = _systemMsg.bgImage
        GLOB.mainlogo = _systemMsg.mainlogo
        GLOB.doclogo = _systemMsg.doclogo
        GLOB.webSite = _systemMsg.webSite
        GLOB.style = _systemMsg.style
        if (window.GLOB.favicon) {
        if (GLOB.favicon) {
          let link = document.querySelector("link[rel*='icon']") || document.createElement('link')
          link.type = 'image/x-icon'
          link.rel = 'shortcut icon'
          link.href = window.GLOB.favicon
          link.href = GLOB.favicon
          document.getElementsByTagName('head')[0].appendChild(link)
        }
      } catch {
@@ -144,9 +144,9 @@
      }
    }
    document.title = window.GLOB.platTitle || ''
    document.title = GLOB.platTitle || ''
    if (window.GLOB.filter === 'true') {
    if (GLOB.filter === 'true') {
      let html = document.getElementsByTagName('html')[0]
      
      if (html) {
@@ -156,25 +156,54 @@
    if (process.env.NODE_ENV === 'production') { // 用于校验是否存在开发权限
      let _service = window.location.href.replace(/\/index.html(.*)|\/#(.*)/ig, '').replace(new RegExp(document.location.origin + '/?', 'ig'), '')
      window.GLOB.linkurl = window.location.href.split('#')[0]
      if (!/index.html/ig.test(window.GLOB.linkurl)) {
        window.GLOB.linkurl = window.GLOB.linkurl + 'index.html'
      GLOB.linkurl = window.location.href.split('#')[0]
      if (!/index.html/ig.test(GLOB.linkurl)) {
        GLOB.linkurl = GLOB.linkurl + 'index.html'
      }
      window.GLOB.service = _service ? _service + '/' : ''
      GLOB.service = _service ? _service + '/' : ''
    } else {
      window.GLOB.linkurl = ''
      window.GLOB.location = 'http://qingqiumarket.cn/'
      window.GLOB.service = 'mkwms/'
      GLOB.linkurl = ''
      GLOB.location = 'http://qingqiumarket.cn/'
      GLOB.service = 'mkwms/'
    }
    const option = {
      white: 'mk-white'
    }
    if (window.GLOB.style && option[window.GLOB.style]) {
      document.getElementById('root').className = option[window.GLOB.style]
    if (GLOB.style && option[GLOB.style]) {
      document.getElementById('root').className = option[GLOB.style]
    }
    Object.defineProperty(GLOB, 'appId', {
      writable: false,
      value: GLOB.appId
    })
    Object.defineProperty(GLOB, 'appkey', {
      writable: false,
      value: GLOB.appkey
    })
    Object.defineProperty(GLOB, 'systemType', {
      writable: false,
      value: GLOB.systemType
    })
    Object.defineProperty(GLOB, 'mainSystemApi', {
      writable: false,
      value: GLOB.mainSystemApi
    })
    Object.defineProperty(GLOB, 'linkurl', {
      writable: false,
      value: GLOB.linkurl
    })
    Object.defineProperty(GLOB, 'dataFormat', {
      writable: false,
      value: GLOB.dataFormat
    })
    Object.defineProperty(window, 'GLOB', {
      writable: false,
      value: GLOB
    })
    render(Route)
  })
src/locales/en-US/mob.js
@@ -4,12 +4,21 @@
  'mob.submit': '提交',
  'mob.cancel': '取消',
  'mob.edit': '编辑',
  'mob.header.logout': '退出',
  'mob.logout': '退出',
  'mob.name': '名称',
  'mob.param': '参数',
  'mob.menu': '菜单',
  'mob.menu.first': '一级',
  'mob.menu.second': '二级',
  'mob.menu.opentype': '打开方式',
  'mob.menu.easycode': '助记码',
  'mob.component': '组件',
  'mob.status.open': '启用',
  'mob.status.change': '切换',
  'mob.status.forbidden': '禁用',
  'mob.basemsg': '基本信息',
  'mob.query.delete': '确定删除吗?',
  'mob.header.logout.hint': '您确定要退出吗?',
  'mob.logout.hint': '您确定要退出吗?',
  'mob.required.input': '请输入',
  'mob.required.select': '请选择',
}
src/locales/zh-CN/mob.js
@@ -4,12 +4,21 @@
  'mob.submit': '提交',
  'mob.cancel': '取消',
  'mob.edit': '编辑',
  'mob.header.logout': '退出',
  'mob.logout': '退出',
  'mob.name': '名称',
  'mob.param': '参数',
  'mob.menu': '菜单',
  'mob.menu.first': '一级',
  'mob.menu.second': '二级',
  'mob.menu.opentype': '打开方式',
  'mob.menu.easycode': '助记码',
  'mob.component': '组件',
  'mob.status.open': '启用',
  'mob.status.change': '切换',
  'mob.status.forbidden': '禁用',
  'mob.basemsg': '基本信息',
  'mob.query.delete': '确定删除吗?',
  'mob.header.logout.hint': '您确定要退出吗?',
  'mob.logout.hint': '您确定要退出吗?',
  'mob.required.input': '请输入',
  'mob.required.select': '请选择',
}
src/locales/zh-CN/model.js
@@ -257,7 +257,7 @@
  'form.required.input': '请输入',
  'form.required.select': '请选择',
  'form.required.add': '请添加',
  'model.tooltip.table.guide': '此处可以添加页面配置相关的常用表,可通过工具栏中的添加按钮,可批量添加表格相关字段。',
  'model.tooltip.table.guide': '添加页面配置相关的常用表,可通过常用表字段批量添加搜索条件、显示列、数据源字段集。',
  'model.tooltip.search.guide': '在左侧工具栏《搜索》中,选择对应搜索框拖至此处添加;或点击按钮《添加搜索条件》批量添加,选择批量添加时,需提前选择使用表。',
  'model.tooltip.action.guide': '在左侧工具栏《按钮》中,选择对应类型的按钮拖至此处添加,如选择按钮类型为表单、新标签页等含有配置页面的按钮,可在左侧工具栏-按钮-可配置按钮处,点击按钮完成相关配置。注:当设置按钮显示位置为表格时,显示列会增加操作列。',
  'model.tooltip.column.guide': '在左侧工具栏《显示列》中,选择对应类型的显示列拖至此处添加;或点击《添加显示列》按钮批量添加,选择批量添加时,需提前选择使用表。注:添加合并列时,需设置可选列。',
src/menu/header/index.jsx
New file
@@ -0,0 +1,121 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import {Dropdown, Menu, Icon, Modal, Tooltip, Button } from 'antd'
import { logout } from '@/store/action'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import avatar from '@/assets/img/avatar.jpg'
import './index.scss'
const { confirm } = Modal
class MobHeader extends Component {
  static propTpyes = {
    saveIng: PropTypes.any,
    triggerSave: PropTypes.func,
    closeView: PropTypes.func
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    logourl: window.GLOB.mainlogo,
    avatar: sessionStorage.getItem('CloudAvatar') || avatar,
    userName: sessionStorage.getItem('CloudUserName')
  }
  logout = () => {
    // 退出登录
    let _this = this
    confirm({
      title: this.state.dict['mob.logout.hint'],
      content: '',
      okText: this.state.dict['mob.confirm'],
      cancelText: this.state.dict['mob.cancel'],
      onOk() {
        sessionStorage.clear()
        _this.props.logout()
        _this.props.history.replace('/login')
      },
      onCancel() {}
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  // componentDidMount () {
  //   this.getImage()
  // }
  // getImage = () => {
  //   const { logourl } = this.state
  //   const _this = this
  //   let xhr = new XMLHttpRequest()
  //   xhr.open('get', logourl, true)
  //   xhr.responseType = 'blob'
  //   xhr.onload = function () {
  //     if (this.status === 200) {
  //       // document.getElementById(imgId).src =  URL.createObjectURL(this.response)
  //       _this.setState({
  //         logourl: URL.createObjectURL(this.response)
  //       })
  //     }
  //   }
  //   xhr.send(null)
  // }
  render () {
    return (
      <header className="mob-header-container">
        <div className="header-logo"><img src={this.state.logourl} alt=""/></div>
        <Menu
          mode="inline"
          theme="dark"
          inlineCollapsed={this.state.collapsed}
        >
          <Menu.Item key="1">
            <Tooltip placement="bottom" title="关闭">
              <Icon type="close" onClick={this.props.closeView} />
            </Tooltip>
          </Menu.Item>
          <Menu.Item key="2">
            <Tooltip placement="bottom" title="保存">
              <Button icon="save" loading={this.props.saveIng} onClick={this.props.triggerSave}></Button>
            </Tooltip>
          </Menu.Item>
        </Menu>
        <Dropdown className="header-setting" overlay={
          <Menu>
            <Menu.Item key="2" onClick={this.logout}>{this.state.dict['mob.logout']}</Menu.Item>
          </Menu>
        }>
          <div>
            <img src={this.state.avatar} alt=""/>
            <span>
              <span className="username">{this.state.userName}</span> <Icon type="down" />
            </span>
          </div>
        </Dropdown>
      </header>
    )
  }
}
const mapStateToProps = () => {
  return {}
}
const mapDispatchToProps = (dispatch) => {
  return {
    logout: () => dispatch(logout())
  }
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MobHeader))
src/menu/header/index.scss
New file
@@ -0,0 +1,94 @@
.mob-header-container {
  width: 100%;
  height: 48px;
  padding-right: 320px;
  color: rgba(255, 255, 255, 0.65);
  position: fixed;
  top: 0px;
  z-index: 10;
  background: #001529;
  border-bottom: 1px solid #000;
  .header-logo {
    float: left;
    width: 180px;
    line-height: 48px;
    text-align: center;
    padding-left: 5px;
    box-sizing: border-box;
    opacity: 1;
    img {
      max-width: 100%;
      max-height: 40px;
    }
  }
  .header-setting {
    float: right;
    line-height: 48px;
    margin-right: 10px;
    img {
      width: 29px;
      height: 29px;
      border-radius: 30px;
      margin-right: 7px;
    }
    span {
      color: #ffffff;
      font-size: 0.95rem;
      .username {
        display: inline-block;
        height: 30px;
        max-width: 95px;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
    }
  }
  .mob-manage-title {
    position: absolute;
    left: calc(50vw - 45px);
    color: #ffffff;
    font-size: 16px;
    line-height: 48px;
    letter-spacing: 2px;
  }
  >.ant-menu {
    float: left;
    width: unset;
    .ant-menu-item {
      margin-bottom: 0;
      float: left;
      width: unset;
      cursor: default;
      .anticon-arrow-left {
        height: 24px;
        cursor: pointer;
      }
      .ant-btn {
        color: #fff;
        width: unset;
        cursor: pointer;
        height: 37px;
        background: transparent;
        border: 0;
        .anticon-save {
          margin-right: 0;
        }
      }
      .ant-btn[ant-click-animating-without-extra-node="true"]::after {
        display: none!important;
      }
      .ant-btn::before {
        display: none!important;
      }
    }
    .ant-menu-item.ant-menu-item-selected {
      background-color: transparent;
    }
    .ant-menu-item:not(:last-child) {
      border-right: 1px solid #353535;
    }
  }
}
src/menu/menuform/index.jsx
New file
@@ -0,0 +1,225 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Select, notification } from 'antd'
import Api from '@/api'
// import { formRule } from '@/utils/option.js'
import './index.scss'
class MainSearch extends Component {
  static propTpyes = {
    dict: PropTypes.object, // 字典项
    config: PropTypes.object,
    MenuId: PropTypes.string,
    MenuName: PropTypes.string,
    MenuNo: PropTypes.string,
    parentId: PropTypes.string,
    updateConfig: PropTypes.func
  }
  state = {
    fstMenuId: '',
    menulist: [],
    smenulist: []
  }
  UNSAFE_componentWillMount () {
    const { parentId } = this.props
    let param = {
      func: 's_Get_FSMenusForOpen',
      SndMenuID: parentId,
      TYPE: 20,
      TypeCharOne: 'PC'
    }
    Api.getSystemConfig(param).then(result => {
      if (result.status) {
        let menulist = result.data.map(smenu => {
          let _smenu = {
            value: smenu.FstID,
            text: smenu.FstName,
            options: smenu.SndData.map(menu => {
              return {
                value: menu.SndID,
                text: menu.SndName,
              }
            })
          }
          return _smenu
        })
        let smenulist = []
        menulist.forEach(item => {
          if (item.value === result.FstIDSeleted) {
            smenulist = item.options
          }
        })
        this.setState({
          fstMenuId: result.FstIDSeleted,
          menulist,
          smenulist
        }, () => {
          this.props.form.setFieldsValue({
            fstMenuId: result.FstIDSeleted,
            parentId: parentId
          })
        })
      } else {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    const { config } = this.props
    if (!config && nextProps.config) {
      this.props.form.setFieldsValue({easyCode: nextProps.config.easyCode})
    }
  }
  // 一二级菜单切换
  selectChange = (key, value) => {
    const { config } = this.props
    const { menulist } = this.state
    if (key === 'fstMenuId') {
      let smenulist = []
      menulist.forEach(item => {
        if (item.value === value) {
          smenulist = item.options
        }
      })
      this.setState({
        smenulist
      }, () => {
        let _id = smenulist[0] ? smenulist[0].value : ''
        this.props.form.setFieldsValue({parentId: _id})
      })
      this.props.updateConfig({...config, fstMenuId: value})
    } else if (key === 'parentId') {
      this.props.updateConfig({...config, parentId: value})
    }
  }
  // 菜单名称
  changeName = (e) => {
    this.props.updateConfig({...this.props.config, MenuName: e.target.value})
  }
  // 菜单参数
  changeNo = (e) => {
    this.props.updateConfig({...this.props.config, MenuNo: e.target.value})
  }
  // 助记码
  changeEasyCode = (e) => {
    this.props.updateConfig({...this.props.config, easyCode: e.target.value})
  }
  render() {
    const { dict, MenuName, MenuNo } = this.props
    const { menulist, smenulist } = this.state
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form">
        <Row>
          <Col span={24}>
            <Form.Item label={dict['mob.menu.first'] + dict['mob.menu']}>
              {getFieldDecorator('fstMenuId', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: dict['mob.required.select'] + dict['mob.menu.first'] + dict['mob.menu'] + '!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.selectChange('fstMenuId', value)}}>
                  {menulist.map(option =>
                    <Select.Option key={option.value} value={option.value}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['mob.menu.second'] + dict['mob.menu']}>
              {getFieldDecorator('parentId', {
                initialValue: '',
                rules: [
                  {
                    required: true,
                    message: dict['mob.required.select'] + dict['mob.menu.second'] + dict['mob.menu'] + '!'
                  }
                ]
              })(
                <Select onChange={(value) => {this.selectChange('parentId', value)}}>
                  {smenulist.map(option =>
                    <Select.Option key={option.value} value={option.value}>
                      {option.text}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['mob.menu'] + dict['mob.name']}>
              {getFieldDecorator('MenuName', {
                initialValue: MenuName,
                rules: [
                  {
                    required: true,
                    message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.name'] + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeName}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['mob.menu'] + dict['mob.param']}>
              {getFieldDecorator('MenuNo', {
                initialValue: MenuNo,
                rules: [
                  {
                    required: true,
                    message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.param'] + '!'
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onChange={this.changeNo}/>)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label={dict['mob.menu.easycode']}>
              {getFieldDecorator('easyCode', {
                initialValue: ''
              })(<Input placeholder="" autoComplete="off" onChange={this.changeEasyCode}/>)}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(MainSearch)
src/menu/menuform/index.scss
src/mob/components/login/mob-login-1/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { InputItem, Icon, Checkbox, List, Button } from 'antd-mobile'
import { createForm } from 'rc-form'
// import { createForm } from 'rc-form'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
@@ -135,7 +135,7 @@
  render () {
    const { card, editId } = this.props
    const { getFieldProps } = this.props.form
    // const { getFieldProps } = this.props.form
    const { rember } = this.state
    if (!card.box) return null
@@ -181,11 +181,8 @@
          {card.title.content}
        </div> : null}
        <InputItem
          placeholder="UserName"
          placeholder={"UserName"}
          prefixListCls="mk-login-item am-list"
          {...getFieldProps('userName', {
            initialValue: 'admin',
          })}
          disabled={true}
        >
          <Icon type="check-circle-o" />
@@ -193,9 +190,6 @@
        <InputItem
          placeholder="Password"
          prefixListCls="mk-login-item am-list"
          {...getFieldProps('password', {
            initialValue: '123456',
          })}
          type={'password'}
          disabled={true}
        >
@@ -230,4 +224,5 @@
  }
}
export default createForm()(MobLogin)
// export default createForm()(MobLogin)
export default MobLogin
src/mob/header/index.jsx
@@ -32,7 +32,7 @@
    // 退出登录
    let _this = this
    confirm({
      title: this.state.dict['mob.header.logout.hint'],
      title: this.state.dict['mob.logout.hint'],
      content: '',
      okText: this.state.dict['mob.confirm'],
      cancelText: this.state.dict['mob.cancel'],
@@ -80,7 +80,7 @@
        }
        <Dropdown className="header-setting" overlay={
          <Menu>
            <Menu.Item key="2" onClick={this.logout}>{this.state.dict['mob.header.logout']}</Menu.Item>
            <Menu.Item key="2" onClick={this.logout}>{this.state.dict['mob.logout']}</Menu.Item>
          </Menu>
        }>
          <div>
src/router/index.js
@@ -11,6 +11,7 @@
const NotFound = asyncComponent(() => import('@/views/404'))
const MobManage = asyncLoadComponent(() => import('@/views/mobmanage'))
const MobDesign = asyncLoadComponent(() => import('@/views/mobdesign'))
const MenuDesign = asyncLoadComponent(() => import('@/views/menudesign'))
const PrintT = asyncLoadComponent(() => import('@/views/printTemplate'))
const routers = [
@@ -21,12 +22,13 @@
  {path: '/main', name: 'main', component: Main, auth: true},
  {path: '/mobmanage', name: 'mobmanage', component: MobManage, auth: true},
  {path: '/mobdesign/:appId/:appType/:appCode/:appName', name: 'mobdesign', component: MobDesign, auth: true},
  {path: '/menudesign/:MenuId/:ParentId/:MenuName/:MenuNo', name: 'menudesign', component: MenuDesign, auth: true},
  {path: '/main/:param', name: 'pmain', component: Main, auth: true}
]
export default class RouteConfig extends Component {
  controlRoute (item, props) {
    if (!item.auth) { // 不需要授权,直接跳转(登录页)
    if (!item.auth) {            // 不需要授权,直接跳转(登录页)
      return (<item.component {...props}/>)
    }
src/tabviews/calendar/index.jsx
@@ -368,7 +368,7 @@
    }
    // 测试系统打印查询语句
    if (options.sysType === 'local' && !window.GLOB.systemType) {
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
src/tabviews/commontable/index.jsx
@@ -736,7 +736,7 @@
    }
    // 测试系统打印查询语句
    if (options.sysType === 'local' && !window.GLOB.systemType) {
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
src/tabviews/subtable/index.jsx
@@ -611,7 +611,7 @@
    }
    // 测试系统打印查询语句
    if (options.sysType === 'local' && !window.GLOB.systemType) {
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
src/tabviews/subtabtable/index.jsx
@@ -512,7 +512,7 @@
    }
    
    // 测试系统打印查询语句
    if (options.sysType === 'local' && !window.GLOB.systemType) {
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
src/tabviews/treepage/index.jsx
@@ -539,7 +539,7 @@
    }
    
    // 测试系统打印查询语句
    if (options.sysType === 'local' && !window.GLOB.systemType) {
    if ((options.sysType === 'local' && !window.GLOB.systemType) || window.debugger === true) {
      param.custom_script &&  console.log(`${LText ? '' : '/*不执行默认sql*/\n'}${param.custom_script}`)
      LText &&  console.log(LText)
    }
src/tabviews/zshare/normalTable/index.jsx
@@ -512,8 +512,11 @@
      let contents = []
      let images = []
      item.subColumn.forEach(col => {
      item.subColumn.forEach((col, index) => {
        if (!col.field || !record.hasOwnProperty(col.field)) return
        if (index) {
          col.Align = 'right'
        }
        
        if (col.type === 'number') {
          let content = ''
@@ -558,7 +561,7 @@
            content = md5(content)
          }
          contents.push(content)
          contents.push({content, align: col.Align})
        } else if (col.type === 'picture') {
          let photos = []
          try {
@@ -568,7 +571,7 @@
          }
          photos.forEach(photo => {
            images.push({url: photo, scale: col.scale === 'true', maxHeight: col.maxHeight || 128})
            images.push({url: photo, align: col.Align, scale: col.scale === 'true', maxHeight: col.maxHeight || 128})
          })
        } else if (col.type === 'text') {
          let content = record[col.field]
@@ -601,7 +604,7 @@
            content = md5(content)
          }
          contents.push(content)
          contents.push({content, align: col.Align})
        } else if (col.type === 'link') {
          let content = col.nameField ? record[col.nameField] : ''
          let _href = record[col.field] || ''
@@ -631,7 +634,7 @@
          content = _href ? <a href={_href} target="_blank" rel="noopener noreferrer">{content}</a> : null
          contents.push(content)
          contents.push({content, align: col.Align})
        } else {
          let content = record[col.field]
@@ -643,7 +646,7 @@
            content = md5(content)
          }
          contents.push(content)
          contents.push({content, align: col.Align})
        }
      })
@@ -663,8 +666,8 @@
  getCospanContent = (type, contents, images) => {
    if (type === 'vertical') {
      return contents.map((content, index) => {
        return (<p key={index}>{content}</p>)
      return contents.map((cont, index) => {
        return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
      })
    } else if (type === 'horizontal') {
      return contents.map((content, index) => {
@@ -674,18 +677,18 @@
      return (
        <div className="content-fence">
          <div className="content-fence-left">
            {contents.map((content, index) => {
            {contents.map((cont, index) => {
              if (index % 2 === 0) {
                return (<p key={index}>{content}</p>)
                return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
              } else {
                return ''
              }
            })}
          </div>
          <div className="content-fence-right">
            {contents.map((content, index) => {
            {contents.map((cont, index) => {
              if (index % 2 === 1) {
                return (<p key={index}>{content}</p>)
                return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
              } else {
                return ''
              }
@@ -696,7 +699,7 @@
    } else if (type === 'topPicBottomText') {
      return (
        <div className="content-fence">
          <div className="content-fence-top">
          <div className="content-fence-top" style={images[0] ? {textAlign: images[0].align} : null}>
            {images.map((_img, index) => {
              if (!_img.url) return ''
              if (_img.scale) {
@@ -707,8 +710,8 @@
            })}
          </div>
          <div className="content-fence-bottom">
            {contents.map((content, index) => {
              return (<p key={index}>{content}</p>)
            {contents.map((cont, index) => {
              return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
            })}
          </div>
        </div>
@@ -716,7 +719,7 @@
    } else if (type === 'leftPicRightText') {
      return (
        <div className="content-fence">
          <div className="content-fence-left">
          <div className="content-fence-left" style={images[0] ? {textAlign: images[0].align} : null}>
            {images.map((_img, index) => {
              if (!_img.url) return ''
              if (_img.scale) {
@@ -727,8 +730,8 @@
            })}
          </div>
          <div className="content-fence-right">
            {contents.map((content, index) => {
              return (<p key={index}>{content}</p>)
            {contents.map((cont, index) => {
              return (<p key={index} style={{textAlign: cont.align}}>{cont.content}</p>)
            })}
          </div>
        </div>
src/templates/comtableconfig/index.scss
@@ -110,30 +110,22 @@
      min-width: 65px;
    }
  }
  .tools:hover {
  .tools {
    overflow-y: auto;
  }
  .tools::-webkit-scrollbar {
    width: 7px;
    width: 4px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
    background: rgba(0, 0, 0, 0.08);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-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);
  }
  .setting {
    position: relative;
src/templates/formtabconfig/index.scss
@@ -13,7 +13,7 @@
    background: #ffffff;
    border-right: 1px solid #d9d9d9;
    height: 100%;
    overflow-y: hidden;
    overflow-y: auto;
    padding-bottom: 30px;
    .ant-collapse-item {
      position: relative;
@@ -100,30 +100,19 @@
      min-width: 65px;
    }
  }
  .tools:hover {
    overflow-y: auto;
  }
  .tools::-webkit-scrollbar {
    width: 7px;
    width: 4px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
    background: rgba(0, 0, 0, 0.08);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-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);
  }
  .setting {
    position: relative;
src/templates/menuconfig/editthdmenu/index.jsx
@@ -13,6 +13,7 @@
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 Preview from './preview'
import MenuForm from './menuform'
@@ -38,12 +39,6 @@
const { confirm } = Modal
const { TabPane } = Tabs
const { Search } = Input
const illust = { // 模板图片,用于已使用模板
  CommonTable: mainsubtable,
  TreePage: treepage,
  CalendarPage: calendar
}
class EditMenu extends Component {
  static propTpyes = {
@@ -136,7 +131,7 @@
        onCancel() {}
      })
    } else if (menu.type === 'edit') {
      let _menu = JSON.parse(JSON.stringify(menu.card))
      let _menu = fromJS(menu.card).toJS()
      delete _menu.id
      delete _menu.src
@@ -439,7 +434,7 @@
   * 2、使用已有菜单模板时,获取菜单配置信息,标记为user(复制菜单按钮)
   */
  useTemplate = (template, useType) => {
    let editMenu = JSON.parse(JSON.stringify(this.state.editMenu))
    let editMenu = fromJS(this.state.editMenu).toJS()
    if (!this.state.fstMenuId) {
      notification.warning({
@@ -455,7 +450,7 @@
      editMenu.fstMenuList = this.state.fstMenuList
    }
    if (useType === 'sys' && template.type === 'RolePermission') { // 独立页面
    if (useType === 'sys' && (template.type === 'RolePermission' || template.type === 'CustomPage')) { // 独立页面
      let _menu = {
        ...editMenu,
        MenuID: Utils.getuuid(),
@@ -533,7 +528,7 @@
      this.setState({
        loading: false,
        tabview: template.type,
        tabview: template.type === 'CustomPage' ? '' : template.type,
        optionLibs: new Map(), // 新建时,初始化下拉选项库
        editMenu: {
          ...editMenu,
@@ -543,12 +538,34 @@
          isSubtable: template.isSubtable
        }
      })
      if (template.type === 'CustomPage') { // 使用自定义的已有菜单
        // let _menu = {
        //   ...editMenu,
        //   MenuID: Utils.getuuid(),
        //   MenuName: template.title,
        //   Template: template.type,
        //   ParentID: this.props.supMenu.MenuID,
        // }
        // this.setState({
        //   handleMVisible: true,
        //   sysMenu: _menu
        // })
        return
      }
      document.getElementById('root').style.overflowY = 'hidden'
    })
  }
  getUsedTemplate = () => {
    let { sysTemplates } = this.state
    const illust = { // 模板图片,用于已使用模板
      CommonTable: mainsubtable,
      TreePage: treepage,
      CalendarPage: calendar,
      CustomPage: customImg
    }
    Api.getSystemConfig({func: 'sPC_Get_UserTemp', TypeCharTwo: 'menu'}).then(res => {
      let _templates = []
@@ -608,9 +625,10 @@
   */
  memuSubmit = () => {
    const { sysMenu } = this.state
    let sysTemplates = JSON.parse(JSON.stringify(this.state.sysTemplates))
    let sysTemplates = fromJS(this.state.sysTemplates).toJS()
    if (sysMenu.isSystem) {
    // 角色权限分配模板,只可以添加一次
    if (sysMenu.isSystem && sysMenu.Template === 'RolePermission') {
      sysTemplates = sysTemplates.map(temp => {
        if (temp.type === sysMenu.type) {
          temp.hidden = true
@@ -709,7 +727,7 @@
            return _smenu
          })
        }, () => {
          let _menu = JSON.parse(JSON.stringify(this.state.editMenu))
          let _menu = this.state.editMenu ? fromJS(this.state.editMenu).toJS() : null
  
          if (!_menu || !_menu.loadingFstMenuId) {
            return
src/templates/menuconfig/menuelement/card.jsx
@@ -31,13 +31,16 @@
  const close = () => {
    closeCard(id)
  }
  return (
    <div className="side-card" style={{ opacity }}>
      <div ref={node => drag(drop(node))}>
        {card.PageParam && card.PageParam.Icon && <Icon type={card.PageParam.Icon} />}
        {card.text}
      </div>
      {!card.forbidden ? <Icon className="edit" type="edit" onClick={edit} /> : null}
      {/* 自定义模板,在新页面编辑 */}
      {!card.forbidden && card.type !== 'CustomPage' ? <Icon className="edit" type="edit" onClick={edit} /> : null}
      {card.type === 'CustomPage' ? <a href={`#/menudesign/${card.MenuID}/${card.ParentId}/${card.MenuName}/${card.MenuNo}`} target="_blank" rel="noopener noreferrer"><Icon className="edit" type="edit" /></a> : null}
      <Icon className="close" type="close" onClick={close} />
    </div>
  )
src/templates/modalconfig/index.scss
@@ -13,7 +13,7 @@
    background: #ffffff;
    border-right: 1px solid #d9d9d9;
    height: 100%;
    overflow-y: hidden;
    overflow-y: auto;
    padding-bottom: 30px;
    .ant-collapse-item {
      border: 0;
@@ -88,30 +88,19 @@
      }
    }
  }
  .tools:hover {
    overflow-y: auto;
  }
  .tools::-webkit-scrollbar {
    width: 7px;
    width: 4px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
    background: rgba(0, 0, 0, 0.08);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-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);
  }
  .setting {
    position: relative;
src/templates/sharecomponent/tablecomponent/index.jsx
@@ -264,7 +264,7 @@
          value={dict['header.menu.table.placeholder']}
          onChange={this.onTableChange}
          showArrow={false}
          getPopupContainer={() => document.getElementById(containerId)}
          getPopupContainer={() => containerId ? document.getElementById(containerId) : document.body}
          filterOption={(input, option) => {
            return option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0 ||
              option.props.value.toLowerCase().indexOf(input.toLowerCase()) >= 0
src/templates/sharecomponent/tablecomponent/index.scss
@@ -4,4 +4,8 @@
      opacity: 0.4!important;
    }
  }
  .anticon-question-circle {
    color: #c49f47;
    margin-right: 3px;
  }
}
src/templates/subtableconfig/index.scss
@@ -99,31 +99,24 @@
      min-width: 65px;
    }
  }
  .tools:hover {
  .tools {
    overflow-y: auto;
  }
  .tools::-webkit-scrollbar {
    width: 7px;
    width: 4px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
    background: rgba(0, 0, 0, 0.08);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    border: 1px solid rgba(0, 0, 0, 0.07);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05);
    border: 1px solid rgba(0, 0, 0, 0.07);
  }
  .setting {
    position: relative;
    width: calc(100vw - 235px);
src/templates/treepageconfig/index.scss
@@ -90,30 +90,22 @@
      min-width: 65px;
    }
  }
  .tools:hover {
  .tools {
    overflow-y: auto;
  }
  .tools::-webkit-scrollbar {
    width: 7px;
    width: 4px;
  }
  .tools::-webkit-scrollbar-thumb {
    border-radius: 5px;
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08);
    background: rgba(0, 0, 0, 0.08);
  }
  .tools::-webkit-scrollbar-track {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0);
    border-radius: 3px;
    border: 1px solid rgba(0, 0, 0, 0);
    background: rgba(0, 0, 0, 0);
  }
  .tools:hover::-webkit-scrollbar-thumb {
    box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.13);
    background: rgba(0, 0, 0, 0.13);
  }
  .tools:hover::-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);
  }
  .setting {
    position: relative;
src/utils/option.js
@@ -4,6 +4,7 @@
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 rolemanage from '@/assets/img/rolemanage.jpg'
const _dict =  sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
@@ -74,6 +75,13 @@
    title: '日历',
    type: 'CalendarPage',
    url: calendar,
    baseconfig: '',
    isSystem: true
  },
  {
    title: '自定义',
    type: 'CustomPage',
    url: customImg,
    baseconfig: '',
    isSystem: true
  },
@@ -442,6 +450,7 @@
  'magenta-8': '#9e1068',
  'magenta-9': '#780650',
  'magenta-10': '#520339',
  'transparent': 'transparent',
  'gray-1': '#f5f5f5',
  'gray-2': '#f0f0f0',
  'gray-3': '#d9d9d9',
@@ -591,6 +600,7 @@
    value: 'Gray',
    label: '中性色',
    children: [
      { value: 'transparent', label: 'transparent' },
      { value: 'gray-2', label: 'gray-2' },
      { value: 'gray-4', label: 'gray-4' },
      { value: 'gray-6', label: 'gray-6' },
src/utils/utils.js
@@ -948,8 +948,7 @@
        
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
      // if (window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') {
      if (window.GLOB.systemType !== 'production') {
      if ((window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') || window.debugger === true) {
        let fsql = `
        ${_sql}
        ${_sqlInsert}
@@ -1582,8 +1581,7 @@
    _sql += `
        aaa: select @ErrorCode as ErrorCode,@retmsg as retmsg`
    // if (window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') {
    if (window.GLOB.systemType !== 'production') {
    if ((window.GLOB.systemType !== 'production' && options.sysType !== 'cloud') || window.debugger === true) {
      _sql = _sql.replace(/\n\s{8}/ig, '\n')
      console.log(_sql)
    }
src/views/menudesign/index.jsx
New file
@@ -0,0 +1,394 @@
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { DndProvider } from 'react-dnd'
import { is, fromJS } from 'immutable'
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { Icon, notification, Modal, Collapse } from 'antd'
import html2canvas from 'html2canvas'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
// const { TabPane } = Tabs
const { Panel } = Collapse
const { confirm } = Modal
const Header = asyncComponent(() => import('@/menu/header'))
const MenuForm = asyncComponent(() => import('@/menu/menuform'))
// const Controller = asyncComponent(() => import('@/mob/controller'))
const SourceWrap = asyncComponent(() => import('@/mob/modelsource'))
// const DataSource = asyncComponent(() => import('@/mob/datasource'))
const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent'))
class Mobile extends Component {
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    MenuId: this.props.match.params.MenuId,
    activeKey: 'basedata',
    oriConfig: null,
    parentId: '',
    openEdition: '',
    saveIng: false,
    config: null,
    editElem: null
  }
  UNSAFE_componentWillMount() {
    this.getMenuParam()
    // this.testFunc()
  }
  /**
   * @description 组件销毁,清除state更新
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  closeView = () => {
    const { oriConfig, config } = this.state
    const _this = this
    if (!is(fromJS(oriConfig), fromJS(config))) {
      confirm({
        title: '配置已修改,放弃保存吗?',
        content: '',
        okText: _this.state.dict['mob.confirm'],
        cancelText: _this.state.dict['mob.cancel'],
        onOk() {
          window.close()
        },
        onCancel() {}
      })
    } else {
      window.close()
    }
  }
  triggerSave = () => {
    const { config, openEdition, parentId } = this.state
    this.setState({
      saveIng: true
    })
    let param = {
      func: 'sPC_TrdMenu_AddUpt',
      ParentID: parentId,
      MenuID: config.uuid,
      MenuNo: config.MenuNo,
      EasyCode: '',
      Template: '',
      MenuName: '',
      PageParam: '',
      LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(config))),
      // LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`),
      // LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`),
      TypeCharOne: 'mob'
    }
    let _LText = ''
    // _LText = _LText.join(' union all ')
    let _LTexttb = ''
    // _LTexttb = _LTexttb.join(' union all ')
    param.LText = Utils.formatOptions(_LText)
    param.LTexttb = Utils.formatOptions(_LTexttb)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    if (openEdition) { // 版本管理
      param.open_edition = openEdition
    }
    Api.getSystemConfig(param).then(response => {
      if (response.status) {
        this.setState({
          oriConfig: fromJS(config).toJS(),
          openEdition: response.open_edition || '',
          saveIng: false
        })
      } else {
        notification.warning({
          top: 92,
          message: response.message,
          duration: 5
        })
      }
    })
  }
  testFunc = () => {
    let datas = [{
      name: 'a',
      arr_field: 'MapCode,Country',
      par_tablename: '',
      type: '',
      primaryKey: 'MapCode',
      foreign_key: '',
      sql: `select MapCode,Country from @tc1`,
      script: `declare @tc1 table (MapCode nvarchar(50),Country nvarchar(50)) insert into @tc1 (MapCode,Country) select MapCode,Country from sMap where Province=''`
    }, {
      name: 'b',
      arr_field: 'MapCode,Province,ParMapCode',
      par_tablename: 'a',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Province,ParMapCode from @tc2`,
      script: `declare @tc2 table (MapCode nvarchar(50),Province nvarchar(50),ParMapCode nvarchar(50)) insert into @tc2 (MapCode,Province,ParMapCode) select MapCode,Province,ParMapCode from sMap where Province!='' and City=''`
    }, {
      name: 'c',
      arr_field: 'MapCode,City,ParMapCode',
      par_tablename: 'b',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,City,ParMapCode from @tc3`,
      script: `declare @tc3 table (MapCode nvarchar(50),City nvarchar(50),ParMapCode nvarchar(50)) insert into @tc3 (MapCode,City,ParMapCode) select MapCode,City,ParMapCode from sMap where City!='' and Area=''`
    }, {
      name: 'd',
      arr_field: 'MapCode,Area,ParMapCode',
      par_tablename: 'c',
      type: 'array',
      primaryKey: 'MapCode',
      foreign_key: 'ParMapCode',
      sql: `select MapCode,Area,ParMapCode from sMap where Area!=''`,
      script: ``
    }]
    let LText = datas.map((item, index) => {
      // item.par_tablename = ''
      // item.foreign_key = ''
      let _orderBy = 'MapCode desc'
      let _search = ''
      let _sql = `select top 1000 ${item.arr_field} from (select ${item.arr_field} ,ROW_NUMBER() over(order by ${_orderBy}) as rows from (${item.sql}) tb ${_search}) tmptable order by tmptable.rows `
      return `Select '${item.name}' as tablename,'${window.btoa(window.encodeURIComponent(_sql))}' as LText,'${window.btoa(window.encodeURIComponent(item.script))}' as Lcustomize,'${item.type}' as table_type,'${item.primaryKey}' as primary_key,'${item.par_tablename}' as par_tablename,'${item.foreign_key}' as foreign_key,'${index}' as Sort`
    })
    let LText_field = []
    datas.forEach(item => {
      item.arr_field.split(',').forEach(cell => {
        LText_field.push(`Select '${item.name}' as tablename,'${cell}' as fieldname,'nvarchar(50)' as field_type`)
      })
    })
    let param = {
      func: 'sPC_Get_structured_data',
      LText: LText.join(' union all '),
      LText_field: LText_field.join(' union all ')
    }
    param.LText = Utils.formatOptions(param.LText)
    param.LText_field = Utils.formatOptions(param.LText_field)
    param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') + '.000'
    param.secretkey = Utils.encrypt(param.LText, param.timestamp)
    Api.getLocalConfig(param)
  }
  getMenuParam = () => {
    Api.getSystemConfig({
      func: 'sPC_Get_LongParam',
      MenuID: this.props.match.params.MenuId
    }).then(result => {
      if (result.status) {
        let config = null
        if (result.LongParam) {
          try {
            config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam)))
          } catch (e) {
            console.warn('Parse Failure')
            config = null
          }
        }
        if (!config) {
          config = {
            version: 1.0,
            uuid: this.props.match.params.MenuId,
            Template: 'CustomPage',
            easyCode: '',
            enabled: false,
            MenuName: this.props.match.params.MenuName,
            MenuNo: this.props.match.params.MenuNo,
            tables: [],
            components: []
          }
        }
        this.setState({
          oriConfig: config,
          config: fromJS(config).toJS(),
          openEdition: result.open_edition || '',
        })
      } else {
        notification.warning({
          top: 92,
          message: result.message,
          duration: 5
        })
      }
    })
  }
  deleteCard = (id) => {
    let _this = this
    let config = fromJS(this.state.config).toJS()
    confirm({
      title: '确定删除元素吗?',
      content: '',
      okText: this.state.dict['mob.confirm'],
      cancelText: this.state.dict['mob.cancel'],
      onOk() {
        config.components = config.components.filter(item => item.uuid !== id)
        _this.setState({
          config: config
        })
      },
      onCancel() {}
    })
  }
  editCard = (element) => {
    this.setState({
      editElem: element
    })
  }
  updateStyle = (proper) => {
    const { config } = this.state
    config.components = config.components.map(component => {
      if (component.uuid === proper.componentId) {
        Object.keys(component).forEach(key => {
          let _uuid = component[key].uuid
          if (_uuid && (_uuid === proper.uuid || _uuid === proper.classId)) {
            if (component[key].substyle) {
            } else {
              component[key].style = {...component[key].style, ...proper.style}
              // eslint-disable-next-line
              for (let index in component[key].style) {
                if (component[key].style[index] === '') {
                  delete component[key].style[index]
                }
              }
            }
          }
        })
      }
      return component
    })
    this.setState({config})
  }
  updateConfig = (config) => {
    this.setState({
      config: config
    })
  }
  updatetable = (config) => {
    // this.setState({
    //   config: config
    // })
  }
  save = () => {
    html2canvas(document.getElementById('view')).then(canvas => {
      let imgUri = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream'); // 获取生成的图片的url
      window.location.href = imgUri; // 下载图片
    })
  }
  render () {
    const { activeKey, saveIng, dict, MenuId, config } = this.state
    return (
      <div className="pc-menu-view" id="view">
        <Header view="design" closeView={this.closeView} triggerSave={this.triggerSave} saveIng={saveIng} />
        <DndProvider backend={HTML5Backend}>
          <div className="menu-body">
            <div className="menu-setting">
              <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}>
                {/* 基本信息 */}
                <Panel header={dict['mob.basemsg']} key="basedata">
                  {/* 菜单信息 */}
                  <MenuForm
                    dict={dict}
                    config={config}
                    MenuId={MenuId}
                    parentId={this.props.match.params.ParentId}
                    MenuName={this.props.match.params.MenuName}
                    MenuNo={this.props.match.params.MenuNo}
                    updateConfig={this.updateConfig}
                  />
                  {/* 表名添加 */}
                  {config ? <TableComponent
                    config={config}
                    // containerId="main-basedata"
                    updatetable={this.updatetable}
                  /> : null}
                </Panel>
                {/* 搜索条件添加 */}
                {/* <Panel header={dict['mob.component']} key="component">
                  <div className="search-element">
                    {Source.searchItems.map((item, index) => (<SourceElement key={index} content={item}/>))}
                  </div>
                  <FieldsComponent
                    config={config}
                    type="search"
                    tableFields={this.state.tableFields}
                    updatefield={this.updateconfig}
                  />
                </Panel> */}
              </Collapse>
              {/* <Tabs defaultActiveKey="1" animated={false} size="small">
                <TabPane tab="配置" key="1">
                  <Controller editElem={editElem} updateStyle={this.updateStyle} />
                </TabPane>
                <TabPane tab="数据源" key="2">
                  <DataSource config={config} updateConfig={this.updateConfig} />
                </TabPane>
              </Tabs> */}
            </div>
            <div className="menu-tool">
              <div className="menu-tool-content">
                <div className="plus-content">
                  <Icon type="plus-circle" />添 加 组 件
                </div>
                <div className="useable-component">
                  <SourceWrap appType="Menu" />
                </div>
              </div>
              <div className="menu-tool-other"></div>
            </div>
          </div>
        </DndProvider>
      </div>
    )
  }
}
const mapStateToProps = () => {
  return {}
}
const mapDispatchToProps = () => {
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(Mobile)
src/views/menudesign/index.scss
New file
@@ -0,0 +1,134 @@
.pc-menu-view {
  background: #000;
  min-height: 100vh;
  .menu-body {
    width: 100vw;
    height: 100vh;
    overflow-x: hidden;
    position: relative;
    background: #ffffff;
    padding: 50px 300px 0px 40px;
    .menu-tool {
      position: fixed;
      left: 0;
      top: 48px;
      height: 100%;
      width: 40px;
      background: #262626;
      box-shadow: 2px 0px 2px #000;
      .menu-tool-content {
        width: 100%;
        .plus-content {
          position: relative;
          color: #ffffff;
          width: 100%;
          display: flex;
          align-items: center;
          writing-mode: tb-rl;
          padding: 16px 0;
          border-bottom: 1px solid #000;
          cursor: pointer;
          z-index: 10;
          background: #202735;
          i {
            margin-bottom: 5px;
            margin-left: 2px;
          }
        }
        .useable-component {
          position: absolute;
          width: 305px;
          top: 0;
          bottom: 0;
          left: -340px;
          background: #fff;
          opacity: 0;
          transition: left 0.3s linear 0.1s, opacity 0.3s linear 0.1s;
          overflow-y: auto;
        }
      }
      .menu-tool-content:hover {
        .useable-component {
          opacity: 1;
          left: 40px;
        }
      }
      .menu-tool-other {
        position: relative;
        z-index: 10;
        height: 1000px;
        background: #202735;
      }
    }
    .menu-setting {
      position: fixed;
      left: 0;
      top: 48px;
      z-index: 10;
      height: 100%;
      width: 300px;
      background: #ffffff;
      box-shadow: 0px 2px 5px #bcbcbc;
      > .ant-collapse {
        .ant-collapse-item.ant-collapse-item-active {
          border-bottom: 1px solid #d9d9d9;
        }
        .ant-collapse-header {
          padding: 11px 16px 10px 40px;
          border-bottom: 1px solid #d9d9d9;
          background: #1890ff;
          color: #ffffff;
        }
        .ant-collapse-content-box {
          .ant-form-item {
            margin-bottom: 10px;
          }
        }
      }
      >.ant-tabs {
        >.ant-tabs-bar {
          border-bottom: 1px solid #181F29;
          margin-bottom: 0px;
          min-height: 48px;
          .ant-tabs-tab {
            padding: 14px 16px;
            color: rgba(255, 255, 255, 0.85);
          }
          .ant-tabs-tab-active.ant-tabs-tab {
            color: #1890ff;
          }
        }
      }
    }
  }
  .flex-container {
    margin: 0 15px;
  }
  .flex-container .inline {
    width: 80px!important;
    margin: 9px 9px 9px 0;
  }
  .flex-container .small {
    height: 20px!important;
    line-height: 20px!important;
  }
  .sub-title {
    color: #888;
    font-size: 14px;
    padding: 30px 0 18px 0;
  }
  .placeholder {
    background-color: #ebebef;
    color: #bbb;
    text-align: center;
    height: 30px;
    line-height: 30px;
    width: 100%;
  }
}
src/views/mobdesign/index.jsx
@@ -241,7 +241,7 @@
            <div className="mob-tool">
              <div className="mob-tool-content">
                <div className="plus-content">
                  <Icon type="plus-circle" />添 加 内 容
                  <Icon type="plus-circle" />添 加 组 件
                </div>
                <div className="useable-component">
                  <SourceWrap appType={appType} />