king
2021-03-03 6c56a138c17dc9aff9d175d20645eb176d2e024b
2021-03-03
12个文件已修改
14个文件已添加
1356 ■■■■ 已修改文件
package.json 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/navbar.png 补丁 | 查看 | 原始文档 | blame | 历史
src/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/antv-tabs/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/tablabelform/index.jsx 31 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.jsx 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/index.jsx 322 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/index.scss 39 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/index.jsx 73 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx 133 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/menusetting/menutable/index.scss 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/wrapsetting/index.jsx 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/wrapsetting/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx 137 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/card.jsx 90 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/index.jsx 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/index.scss 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/modulesource/option.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package.json
@@ -188,7 +188,7 @@
      ]
    ]
  },
  "homepage": "./build",
  "homepage": ".",
  "devDependencies": {
    "typescript": "^4.0.2"
  }
src/assets/mobimg/navbar.png
src/index.js
@@ -60,7 +60,7 @@
// 测试系统文件置于admin中
// fetch(process.env.NODE_ENV === 'production' ? '../options.json' : './options.json')
fetch('./options.json')
fetch('../options.json')
  .then(response => response.json())
  .catch(() => {
    document.getElementById('root').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh;">系统配置信息获取失败,请联系管理员!</div>'
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -266,7 +266,7 @@
        this.props.form.setFieldsValue(_fieldval)
      })
    } else if (key === 'funcType') {
      let _options = this.getOptions(this.state.openType, this.state.interType, value, card.pageTemplate, procMode)
      let _options = this.getOptions(openType, this.state.interType, value, card.pageTemplate, procMode)
      let _fieldval = {}
      this.setState({
@@ -330,10 +330,9 @@
      })
    } else if (key === 'pageTemplate') {
      let _fieldval = {}
      let _options = this.getOptions(this.state.openType, this.state.interType, this.state.funcType, value, procMode)
      let _options = this.getOptions(openType, this.state.interType, this.state.funcType, value, procMode)
      this.setState({
        openType: value,
        formlist: this.state.formlist.map(item => {
          item.hidden = !_options.includes(item.key)
src/menu/components/tabs/antv-tabs/index.jsx
@@ -216,6 +216,7 @@
    this.tabLabelRef.handleConfirm().then(res => {
      editab.label = res.label
      editab.icon = res.icon
      editab.blacklist = res.blacklist
      if (editab.uuid) {
        tabs.subtabs = tabs.subtabs.map(t => {
src/menu/components/tabs/tablabelform/index.jsx
@@ -12,10 +12,21 @@
    inputSubmit: PropTypes.func    // 回车事件
  }
  state = {}
  state = {roleList: []}
  UNSAFE_componentWillMount () {
    let roleList = sessionStorage.getItem('sysRoles')
    if (roleList) {
      try {
        roleList = JSON.parse(roleList)
      } catch {
        roleList = []
      }
    } else {
      roleList = []
    }
    this.setState({roleList})
  }
  handleConfirm = () => {
@@ -42,6 +53,7 @@
  render() {
    const { tab } = this.props
    const { getFieldDecorator } = this.props.form
    const { roleList } = this.state
    const formItemLayout = {
      labelCol: {
@@ -85,6 +97,23 @@
              )}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label="黑名单">
              {getFieldDecorator('blacklist', {
                initialValue: tab.blacklist || []
              })(
                <Select
                  showSearch
                  mode="multiple"
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  {roleList.map(option =>
                    <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
src/menu/stylecontroller/index.jsx
@@ -268,6 +268,15 @@
    this.updateStyle(_style)
  }
  changeWidth = (val) => {
    let _val = val
    if (_val === '0px') {
      _val = 'auto'
    }
    this.updateStyle({width: _val})
  }
  changeHeight = (val) => {
    let _val = val
    if (_val === '0px') {
@@ -313,6 +322,17 @@
        <div className="menu-style-controller">
          <Form {...formItemLayout}>
            {card ? <Collapse expandIconPosition="right" destroyInactivePanel={true} defaultActiveKey={options[0]}>
              {options.includes('width') ? <Panel header="宽度" key="width">
                <Col span={24}>
                  <Form.Item
                    colon={false}
                    label={<Icon title="宽度" type="column-width" />}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.width || ''} options={['px']} onChange={this.changeWidth}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
              {options.includes('height') ? <Panel header="高度" key="height">
                <Col span={24}>
                  <Form.Item
src/pc/components/navbar/normal-navbar/index.jsx
@@ -1,31 +1,25 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { is, fromJS } from 'immutable'
import { Icon, Popover, Modal, Pagination, notification } from 'antd'
import { Icon, Popover } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
// import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
const CardComponent = asyncComponent(() => import('../cardcomponent'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const MenuComponent = asyncIconComponent(() => import('./menusetting'))
// const CardComponent = asyncComponent(() => import('../cardcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
const { confirm } = Modal
// const { confirm } = Modal
class DataCardEditComponent extends Component {
class NormalNavbar extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
@@ -46,36 +40,15 @@
        uuid: card.uuid,
        type: card.type,
        floor: card.floor,
        tabId: card.tabId || '',
        parentId: card.parentId || '',
        format: 'array',   // 组件属性 - 数据格式
        pageable: true,    // 组件属性 - 是否可分页
        switchable: true,  // 组件属性 - 数据是否可切换
        dataName: card.dataName || '',
        width: card.width || 24,
        name: card.name,
        subtype: card.subtype,
        setting: { interType: 'system' },
        wrap: { name: card.name, width: card.width || 24, title: '', pagestyle: 'page', switch: 'false' },
        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
        columns: [],
        scripts: [],
        action: [],
        search: [],
        btnlog: [],
        subcards: [{
          uuid: Utils.getuuid(),
          setting: { width: 6, type: 'simple'},
          style: {
            borderWidth: '1px', borderColor: '#e8e8e8',
            paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px',
            marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
          },
          backStyle: {},
          elements: [],
          backElements: []
        }]
        wrap: { name: card.name, width: card.width || 1200 },
        logoStyle: { width: '100px' },
        style: { },
        links: [],
        menus: [],
      }
      if (card.config) {
@@ -84,28 +57,6 @@
        _card.wrap = config.wrap
        _card.wrap.name = card.name
        _card.style = config.style
        _card.headerStyle = config.headerStyle
        _card.subcards = config.subcards.map(scard => {
          scard.uuid = Utils.getuuid()
          scard.elements = scard.elements.map(elem => {
            elem.uuid = Utils.getuuid()
            return elem
          })
          scard.backElements = scard.backElements.map(elem => {
            elem.uuid = Utils.getuuid()
            return elem
          })
          return scard
        })
        _card.action = config.action.map(col => {
          col.uuid = Utils.getuuid()
          return col
        })
        _card.search = config.search.map(col => {
          col.uuid = Utils.getuuid()
          return col
        })
      }
      this.setState({
@@ -113,9 +64,6 @@
      })
      this.props.updateConfig(_card)
    } else {
      card.action = card.action || [] // 兼容
      card.search = card.search || [] // 兼容
      this.setState({
        card: fromJS(card).toJS()
      })
@@ -124,12 +72,10 @@
  componentDidMount () {
    MKEmitter.addListener('submitStyle', this.getStyle)
    MKEmitter.addListener('submitModal', this.handleSave)
    MKEmitter.addListener('logButton', this.logButton)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState)) || (!this.props.menu && nextProps.menu)
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
@@ -140,22 +86,6 @@
      return
    }
    MKEmitter.removeListener('submitStyle', this.getStyle)
    MKEmitter.removeListener('submitModal', this.handleSave)
    MKEmitter.removeListener('logButton', this.logButton)
  }
  logButton = (id, item) => {
    const { card } = this.state
    if (id !== card.uuid) return
    let btnlog = card.btnlog || []
    btnlog.push(item)
    this.setState({
      card: {...card, btnlog}
    })
    this.props.updateConfig({...card, btnlog})
  }
  
  /**
@@ -188,54 +118,17 @@
    this.props.updateConfig(card)
  }
  /**
   * @description 单个卡片信息更新
   */
  deleteCard = (cell) => {
    let card = fromJS(this.state.card).toJS()
    let _this = this
    confirm({
      content: '确定删除卡片吗?',
      onOk() {
        card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
        let uuids = []
        cell.elements && cell.elements.forEach(c => {
          if (c.eleType === 'button') {
            uuids.push(c.uuid)
          }
        })
        cell.backElements && cell.backElements.forEach(c => {
          if (c.eleType === 'button') {
            uuids.push(c.uuid)
          }
        })
        MKEmitter.emit('delButtons', uuids)
        if (card.btnlog) {
          card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid)
        }
        _this.setState({card})
        _this.props.updateConfig(card)
      },
      onCancel() {}
    })
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
  }
  getStyle = (comIds, style) => {
    const { card } = this.state
    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
    if (comIds[0] !== card.uuid) return
    let _card = {...card, style}
    let _card = {...card}
    if (comIds.length === 1) {
      _card = {...card, style}
    } else if (comIds[1] === 'logo') {
      _card = {...card, logoStyle: style}
    }
    this.setState({
      card: _card
@@ -244,134 +137,16 @@
    this.props.updateConfig(_card)
  }
  addSearch = () => {
  changeStyle = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = 'label'
    newcard.type = 'select'
    newcard.resourceType = '0'
    newcard.options = []
    newcard.setAll = 'false'
    newcard.orderType = 'asc'
    newcard.display = 'dropdown'
    newcard.match = '='
    // 注册事件-添加搜索
    MKEmitter.emit('addSearch', card.uuid, newcard)
    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'shadow'], card.style)
  }
  addButton = () => {
  changeLogoStyle = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = 'label'
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'pop'
    newcard.icon = ''
    newcard.class = 'green'
    newcard.intertype = card.setting.interType || 'system'
    newcard.innerFunc = card.setting.innerFunc || ''
    newcard.sysInterface = card.setting.sysInterface || ''
    newcard.outerFunc = card.setting.outerFunc || ''
    newcard.interface = card.setting.interface || ''
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.verify = null
    newcard.show = 'button'
    newcard.btnstyle = {marginRight: '15px'}
    // 注册事件-添加按钮
    MKEmitter.emit('addButton', card.uuid, newcard)
  }
  setSubConfig = (item) => {
    const { card } = this.state
    let btn = fromJS(item).toJS()
    if (btn.OpenType === 'pop' || btn.execMode === 'pop') {
      if (!btn.modal) {
        btn.modal = {
          setting: { title: btn.label, width: 60, cols: '2', container: 'view', focus: '', finish: 'close', clickouter: 'unclose', display: 'modal' },
          tables: [],
          groups: [],
          fields: []
        }
      }
      MKEmitter.emit('changeModal', card, btn)
    } else if (btn.OpenType === 'popview') {
      MKEmitter.emit('changePopview', card, btn)
    }
  }
  handleSave = (_cards, btn, modal) => {
    let card = fromJS(this.state.card).toJS()
    if (card.uuid !== _cards.uuid) return
    let _index = card.action.findIndex(cell => cell.uuid === btn.uuid)
    if (_index === -1) return
    card.action = card.action.map(cell => {
      if (cell.uuid === btn.uuid) {
        cell.modal = modal
      }
      return cell
    })
    this.setState({card})
    this.props.updateConfig(card)
  }
  handleLog = (type, logs, item) => {
    let card = fromJS(this.state.card).toJS()
    if (type === 'revert') {
      let done = false
      if (item.$parentId) {
        card.subcards.forEach(col => {
          if (item.$parentId === col.uuid) {
            if (item.$side !== 'back') {
              col.elements = col.elements ? [...col.elements, item] : [item]
            } else {
              col.backElements = col.backElements ? [...col.backElements, item] : [item]
            }
            done = true
          }
        })
      }
      if (!done) {
        card.action = card.action ? [...card.action, item] : [item]
      }
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '恢复成功!',
        duration: 2
      })
    } else {
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '清除成功!',
        duration: 2
      })
    }
    MKEmitter.emit('changeStyle', [card.uuid, 'logo'], ['width', 'margin'], card.logoStyle)
  }
  clickComponent = (e) => {
@@ -384,54 +159,39 @@
  render() {
    const { card } = this.state
    let offset = 0
    if (card.wrap.cardFloat && card.wrap.cardFloat !== 'left') {
      let _width = 0
      card.subcards.forEach(card => {
        _width += card.setting.width
      })
      offset = _width < 24 ? 24 - _width : 0
      if (card.wrap.cardFloat === 'center') {
        offset = Math.floor(offset / 2)
      }
    let _style = {...card.style}
    if (_style.shadow) {
      _style.boxShadow = '0 0 4px ' + _style.shadow
    }
    return (
      <div className="menu-data-card-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
        <NormalHeader defaultshow="hidden" config={card} updateComponent={this.updateComponent}/>
      <div className="normal-navbar-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <MenuComponent config={card} updateConfig={this.updateComponent} />
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="datacard" card={card}/>
            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
            <CopyComponent type="normalnarbar" card={card}/>
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <UserComponent config={card}/>
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            <SettingComponent config={card} updateConfig={this.updateComponent} />
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <ActionComponent config={card} setSubConfig={this.setSubConfig} updateaction={this.updateComponent}/>
        {card.subcards.map((subcard, index) => (<CardComponent key={subcard.uuid} offset={!index ? offset : 0} cards={card} card={subcard} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))}
        <div style={{clear: 'both'}}></div>
        {card.wrap.pagestyle !== 'switch' && card.setting.laypage === 'true' ? <Pagination total={85} size="small" showTotal={total => `共 ${total} 条`} pageSize={20} defaultCurrent={1}/> : null}
        <div className="navbar-wrap" style={{width: card.wrap.width + 'px', height: card.wrap.height + 'px', lineHeight: card.wrap.height + 'px'}}>
          {card.wrap.logo ? <Popover overlayClassName="mk-popover-control-wrap top-menu-popover" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
            <div className="mk-popover-control">
              <Icon className="style" title="调整样式" onClick={this.changeLogoStyle} type="font-colors" />
            </div>
          } trigger="hover">
            <div className="logo" style={card.logoStyle}><img src={card.wrap.logo} alt=""/></div>
          </Popover> : null}
          <div className="menu">sdf</div>
          <div className="link">asdfds</div>
        </div>
      </div>
    )
  }
}
const mapStateToProps = (state) => {
  return {
    menu: state.customMenu
  }
}
const mapDispatchToProps = () => {
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(DataCardEditComponent)
export default NormalNavbar
src/pc/components/navbar/normal-navbar/index.scss
@@ -1,12 +1,36 @@
.menu-data-card-edit-box {
  position: relative;
.normal-navbar-edit-box {
  position: fixed;
  top: 0px;
  left: 0px;
  width: 100%;
  box-sizing: border-box;
  background: #ffffff;
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 20px;
  min-height: 50px;
  z-index: 2;
  
  .navbar-wrap {
    margin: 0 auto;
    display: flex;
    .logo {
      display: inline-block;
      img {
        max-width: 100%;
        max-height: 100%;
      }
    }
    .menu {
      flex: 1;
      display: inline-block;
    }
    .link {
      flex: 1;
      display: inline-block;
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
@@ -21,7 +45,7 @@
    position: absolute;
    z-index: 2;
    font-size: 16px;
    right: 1px;
    right: 25px;
    top: 1px;
    cursor: pointer;
    padding: 5px;
@@ -76,12 +100,15 @@
    }
  }
}
.menu-data-card-edit-box::after {
.normal-navbar-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.menu-data-card-edit-box:hover {
.normal-navbar-edit-box:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
.top-menu-popover {
  padding-top: 0!important;
}
src/pc/components/navbar/normal-navbar/menusetting/index.jsx
New file
@@ -0,0 +1,73 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Modal } from 'antd'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import MenuTable from './menutable'
import './index.scss'
class DataSource extends Component {
  static propTpyes = {
    config: PropTypes.any,
    updateConfig: PropTypes.func
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    visible: false
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    this.setState({menus: fromJS(config.menus).toJS()})
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  verifySubmit = () => {
    // const { config } = this.props
    // this.verifyRef.handleConfirm().then(res => {
    //   this.setState({
    //     wrap: res,
    //     visible: false
    //   })
    //   this.props.updateConfig({...config, wrap: res})
    // })
  }
  render () {
    const { config } = this.props
    const { visible, dict } = this.state
    return (
      <div className="model-menu-setting-wrap">
        <Icon type="menu" title="菜单" onClick={() => this.setState({ visible: true })}/>
        <Modal
          wrapClassName="popview-modal"
          title="菜单编辑"
          visible={visible}
          width={800}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <MenuTable
            menus={config.menus}
            ref={(ref) => { this.mTable = ref }}
          />
        </Modal>
      </div>
    )
  }
}
export default DataSource
src/pc/components/navbar/normal-navbar/menusetting/index.scss
New file
@@ -0,0 +1,7 @@
.model-menu-setting-wrap {
  display: inline-block;
  >.anticon-edit {
    color: #1890ff;
  }
}
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.jsx
New file
@@ -0,0 +1,133 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Radio, Tooltip, Icon } from 'antd'
import './index.scss'
const { TextArea } = Input
class SettingForm extends Component {
  static propTpyes = {
    menu: PropTypes.object,    // 卡片行信息
    inputSubmit: PropTypes.func  // 回车事件
  }
  state = {
    property: this.props.menu.property || 'menu'
  }
  UNSAFE_componentWillMount () {
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  changeProperty = (e) => {
    let val = e.target.value
    this.setState({property: val})
  }
  render() {
    const { menu } = this.props
    const { getFieldDecorator } = this.props.form
    const { property } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout}>
        <Row gutter={24}>
          <Col span={24}>
            <Form.Item label="菜单名称">
              {getFieldDecorator('name', {
                initialValue: menu.name,
                rules: [
                  {
                    required: true,
                    message: '请输入菜单名称!'
                  }
                ]
              })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
          <Col span={24}>
            <Form.Item label="属性">
              {getFieldDecorator('property', {
                initialValue: menu.property || 'menu'
              })(
                <Radio.Group onChange={this.changeProperty}>
                  <Radio value="menu">菜单</Radio>
                  <Radio value="link">链接</Radio>
                  <Radio value="classify">分类</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          {property === 'link' ? <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="链接至当前系统的菜单时,可以使用 $ + 菜单ID,例如:$dsdffowejdsfi。">
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
                链接地址
              </Tooltip>
            }>
              {getFieldDecorator('link', {
                initialValue: menu.link || '',
                rules: [
                  {
                    required: true,
                    message: '请输入链接地址!'
                  }
                ]
              })(<TextArea rows={2} />)}
            </Form.Item>
          </Col> : null}
          {property === 'menu' ? <Col span={24}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="复制其他菜单时,请填写对应的菜单ID。">
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
                复制菜单
              </Tooltip>
            }>
              {getFieldDecorator('copyMenu', {
                initialValue: menu.copyMenu || ''
              })(
                <Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />
              )}
            </Form.Item>
          </Col> : null}
        </Row>
      </Form>
    )
  }
}
export default Form.create()(SettingForm)
src/pc/components/navbar/normal-navbar/menusetting/menuform/index.scss
src/pc/components/navbar/normal-navbar/menusetting/menutable/index.jsx
New file
@@ -0,0 +1,168 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Table, Button, Modal } from 'antd'
import MenuForm from '../menuform'
import Utils from '@/utils/utils.js'
import './index.scss'
class SubTable extends Component {
  static propTpyes = {
    menus: PropTypes.object,    // 卡片行信息
  }
  state = {
    data: [],
    columns: [
      { title: 'Date', dataIndex: 'date', key: 'date' },
      { title: 'Name', dataIndex: 'name', key: 'name' },
      {
        title: 'Status',
        key: 'state',
        render: () => (
          <span>
            Finished
          </span>
        ),
      },
      { title: 'Upgrade Status', dataIndex: 'upgradeNum', key: 'upgradeNum' },
      {
        title: 'Action',
        dataIndex: 'operation',
        key: 'operation',
        render: () => (
          <span className="table-operation">
            <a href>Pause</a>
            <a href>Stop</a>
          </span>
        ),
      },
    ]
  }
  UNSAFE_componentWillMount () {
    // const { data } = this.props
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  render() {
    const { columns, data } = this.state
    return (
      <Table
        className="components-table-demo-nested"
        columns={columns}
        dataSource={data}
      />
    )
  }
}
class MenuTable extends Component {
  static propTpyes = {
    menus: PropTypes.object,    // 卡片行信息
  }
  state = {
    data: [],
    editMenu: null,
    columns: [
      { title: '菜单名称', dataIndex: 'name', key: 'name' },
      { title: '属性', dataIndex: 'property', key: 'property',  render: text => {
        if (text === 'menu') {
          return '菜单'
        } else {
          return '分类'
        }
      }},
      { title: 'Action', key: 'operation', render: () => <a href="#d">Publish</a> },
    ]
  }
  UNSAFE_componentWillMount () {
    const { menus } = this.props
    this.setState({data: fromJS(menus).toJS()})
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  plusMenu = () => {
    let _menu = {
      name: '菜单',
      property: 'classify',
      level: 1,
      children: []
    }
    this.setState({editMenu: _menu, visible: true})
  }
  menuSubmit = () => {
    const { editMenu, data } = this.state
    this.menuRef.handleConfirm().then(res => {
      let _menu = {...editMenu, ...res}
      if (!_menu.uuid) {
        _menu.uuid = Utils.getuuid()
        this.setState({data: [...data, _menu]})
      } else {
        this.setState({data: data.map(item => {
          if (item.uuid === _menu.uuid) {
            return _menu
          } else {
            return item
          }
        })})
      }
    })
  }
  render() {
    const { columns, data, visible, editMenu } = this.state
    return (
      <div className="menu-control-wrap">
        <Button className="menu-plus mk-green" onClick={this.plusMenu}>添加</Button>
        <Table
          className="components-table-demo-nested"
          columns={columns}
          expandedRowRender={<SubTable />}
          dataSource={data}
        />
        <Modal
          title="编辑"
          visible={visible}
          width={600}
          maskClosable={false}
          onOk={this.menuSubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <MenuForm
            menu={editMenu}
            inputSubmit={this.menuSubmit}
            wrappedComponentRef={(inst) => this.menuRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default MenuTable
src/pc/components/navbar/normal-navbar/menusetting/menutable/index.scss
New file
@@ -0,0 +1,10 @@
.menu-control-wrap {
  position: relative;
  .menu-plus {
    float: right;
    position: relative;
    z-index: 1;
    margin-bottom: 5px;
  }
}
src/pc/components/navbar/normal-navbar/wrapsetting/index.jsx
New file
@@ -0,0 +1,83 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Modal } from 'antd'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import SettingForm from './settingform'
import './index.scss'
class DataSource extends Component {
  static propTpyes = {
    config: PropTypes.any,
    updateConfig: PropTypes.func
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    visible: false,
    wrap: null
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    this.setState({wrap: fromJS(config.wrap).toJS()})
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
  }
  editDataSource = () => {
    this.setState({
      visible: true
    })
  }
  verifySubmit = () => {
    const { config } = this.props
    this.verifyRef.handleConfirm().then(res => {
      this.setState({
        wrap: res,
        visible: false
      })
      this.props.updateConfig({...config, wrap: res})
    })
  }
  render () {
    const { config } = this.props
    const { visible, dict, wrap } = this.state
    return (
      <div className="model-menu-setting-wrap">
        <Icon type="edit" title="编辑" onClick={() => this.editDataSource()} />
        <Modal
          wrapClassName="popview-modal"
          title={config.type === 'table' ? '表格设置' : '卡片设置'}
          visible={visible}
          width={800}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <SettingForm
            dict={dict}
            wrap={wrap}
            config={config}
            inputSubmit={this.verifySubmit}
            wrappedComponentRef={(inst) => this.verifyRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default DataSource
src/pc/components/navbar/normal-navbar/wrapsetting/index.scss
New file
@@ -0,0 +1,7 @@
.model-menu-setting-wrap {
  display: inline-block;
  >.anticon-edit {
    color: #1890ff;
  }
}
src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
New file
@@ -0,0 +1,137 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Tooltip, Icon, InputNumber } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,      // 字典项
    config: PropTypes.object,    // 卡片行信息
    wrap: PropTypes.object,      // 数据源配置
    inputSubmit: PropTypes.func  // 回车事件
  }
  state = {
    roleList: []
  }
  UNSAFE_componentWillMount () {
    let roleList = sessionStorage.getItem('sysRoles')
    if (roleList) {
      try {
        roleList = JSON.parse(roleList)
      } catch {
        roleList = []
      }
    } else {
      roleList = []
    }
    this.setState({roleList})
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (!err) {
          resolve(values)
        } else {
          reject(err)
        }
      })
    })
  }
  handleSubmit = (e) => {
    e.preventDefault()
    if (this.props.inputSubmit) {
      this.props.inputSubmit()
    }
  }
  render() {
    const { wrap } = this.props
    const { getFieldDecorator } = this.props.form
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <div className="model-menu-setting-form">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            <Col span={12}>
              <Form.Item label="导航栏名称">
                {getFieldDecorator('name', {
                  initialValue: wrap.name,
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '导航栏名称!'
                    }
                  ]
                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="导航栏主体内容宽度(包括logo、菜单、链接等)。">
                  <Icon type="question-circle" />
                  宽度
                </Tooltip>
              }>
                {getFieldDecorator('width', {
                  initialValue: wrap.width || 1200,
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '宽度!'
                    }
                  ]
                })(<InputNumber min={400} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label="高度">
                {getFieldDecorator('height', {
                  initialValue: wrap.height || 50,
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '高度!'
                    }
                  ]
                })(<InputNumber min={50} max={200} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label="logo">
                {getFieldDecorator('logo', {
                  initialValue: wrap.logo
                })(
                  <SourceComponent type="image" />
                )}
              </Form.Item>
            </Col>
          </Row>
        </Form>
      </div>
    )
  }
}
export default Form.create()(SettingForm)
src/pc/components/navbar/normal-navbar/wrapsetting/settingform/index.scss
New file
@@ -0,0 +1,11 @@
.model-menu-setting-form {
  position: relative;
  .anticon-question-circle {
    color: #c49f47;
    margin-right: 3px;
  }
  .ant-input-number {
    width: 100%;
  }
}
src/pc/menushell/card.jsx
New file
@@ -0,0 +1,90 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar'))
const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search'))
const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie'))
const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs'))
const DataCard = asyncComponent(() => import('@/menu/components/card/data-card'))
const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card'))
const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
const NormalNavbar = asyncComponent(() => import('@/pc/components/navbar/normal-navbar'))
const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'menu', id, originalIndex, floor: card.floor },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'menu',
    canDrop: () => true,
    drop: (item) => {
      const { id: draggedId, originalIndex, floor } = item
      if (originalIndex === undefined) {
        item.dropTargetId = id
      } else if (draggedId && floor === card.floor) {
        if (draggedId === id) return
        const { index: originIndex } = findCard(draggedId)
        if (originIndex === -1) return
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    }
  })
  let style = { opacity: 1}
  if (isDragging) {
    style = { opacity: 0.3}
  }
  let col = ' ant-col ant-col-' + (card.width || 24)
  if (card.type === 'navbar') {
    col = ''
  }
  const getCardComponent = () => {
    if (card.type === 'bar' || card.type === 'line') {
      return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'navbar') {
      return (<NormalNavbar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'search') {
      return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'pie') {
      return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'tabs') {
      return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'card' && card.subtype === 'datacard') {
      return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'card' && card.subtype === 'propcard') {
      return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'table' && card.subtype === 'tablecard') {
      return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'table' && card.subtype === 'normaltable') {
      return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'group' && card.subtype === 'normalgroup') {
      return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'editor') {
      return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'code') {
      return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
  return (
    <div className={`mk-component-card ${col}`} ref={node => drag(drop(node))} style={style}>
      {getCardComponent()}
    </div>
  )
}
export default Card
src/pc/menushell/index.jsx
New file
@@ -0,0 +1,165 @@
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import { Empty, notification, Modal } from 'antd'
import Utils from '@/utils/utils.js'
import MKEmitter from '@/utils/events.js'
import MenuUtils from '@/menu/utils/menuUtils.js'
import Card from './card'
import './index.scss'
const { confirm } = Modal
const Container = ({menu, handleList }) => {
  const [cards, setCards] = useState(menu.components)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList({...menu, components: _cards})
  }
  if (!is(fromJS(cards), fromJS(menu.components))) {
    setCards(menu.components)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  const updateConfig = (element) => {
    handleList({...menu, components: cards.map(item => item.uuid === element.uuid ? element : item)})
  }
  const deleteCard = (id) => {
    const { card } = findCard(id)
    let hasComponent = false
    if (card.type === 'tabs') {
      card.subtabs.forEach(tab => {
        if (tab.components.length > 0) {
          hasComponent = true
        }
      })
    }
    let uuids = MenuUtils.getDelButtonIds(card)
    confirm({
      title: `确定删除《${card.name}》吗?`,
      content: hasComponent ? '当前组件中含有子组件!' : '',
      onOk() {
        MKEmitter.emit('delButtons', uuids)
        handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)})
      },
      onCancel() {}
    })
  }
  const [, drop] = useDrop({
    accept: 'menu',
    drop(item) {
      if (item.hasOwnProperty('originalIndex') || item.added) {
        delete item.added // 删除组件添加标记
        return
      }
      if (item.component === 'search') { // 搜索组件不可重复添加
        if (cards.filter(card => card.type === 'search').length > 0) {
          notification.warning({
            top: 92,
            message: '搜索条件不可重复添加!',
            duration: 5
          })
          return
        }
      } else if (item.component === 'navbar') {
        if (cards.filter(card => card.type === 'navbar').length > 0) {
          notification.warning({
            top: 92,
            message: '导航栏不可重复添加!',
            duration: 5
          })
          return
        }
      }
      let name = ''
      let names = {
        bar: '柱状图',
        line: '折线图',
        tabs: '标签组',
        pie: '饼图',
        search: '搜索',
        table: '表格',
        group: '分组',
        editor: '富文本',
        code: '自定义',
        navbar: '导航栏',
        card: '卡片'
      }
      let i = 1
      while (!name && names[item.component]) {
        let _name = names[item.component] + i
        if (menu.components.filter(com => com.name === _name).length === 0) {
          name = _name
        }
        i++
      }
      let newcard = {
        uuid: Utils.getuuid(),
        type: item.component,
        subtype: item.subtype,
        config: item.config,
        width: item.width || 24,
        dataName: Utils.getdataName(),
        name: name,
        floor: 1,   // 组件的层级
        isNew: true // 新添加标志,用于初始化
      }
      let targetId = ''
      if (item.dropTargetId) {
        targetId = item.dropTargetId
        delete item.dropTargetId
      } else if (cards.length > 0) {
        targetId = cards.slice(-1)[0].uuid
      }
      const { index: overIndex } = findCard(`${targetId}`)
      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
      handleList({...menu, components: _cards})
    }
  })
  return (
    <div ref={drop} className="menu-shell-inner" id="menu-shell-inner" style={menu.style}>
      <div className="ant-row">
        {cards.map(card => (
          <Card
            id={card.uuid}
            key={card.uuid}
            card={card}
            moveCard={moveCard}
            delCard={deleteCard}
            findCard={findCard}
            updateConfig={updateConfig}
          />
        ))}
      </div>
      {cards.length === 0 ?
        <Empty description="请添加组件" /> : null
      }
    </div>
  )
}
export default Container
src/pc/menushell/index.scss
New file
@@ -0,0 +1,23 @@
.menu-shell-inner {
  min-height: calc(100vh - 100px);
  width: 100%;
  background-size: 100%;
  .anticon {
    cursor: unset;
  }
  .mk-component-card {
    position: relative;
  }
  >.ant-empty {
    padding-top: 150px;
  }
  .anticon-tool {
    color: rgba(0, 0, 0, 0.55);
  }
  .anticon-tool:hover {
    color: #1890ff;
  }
}
src/pc/modulesource/option.jsx
@@ -14,9 +14,11 @@
import Pie1 from '@/assets/mobimg/ring.png'
import Pie2 from '@/assets/mobimg/nightingale.png'
import Mainsearch from '@/assets/mobimg/mainsearch.png'
import Navbar from '@/assets/mobimg/navbar.png'
// 组件配置信息
export const menuOptions = [
  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'navbar', title: '导航栏', width: 1200 },
  { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '标签页', width: 24 },
  { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '搜索条件', width: 24 },
  { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '数据卡', width: 24 },
src/tabviews/custom/index.jsx
@@ -414,6 +414,16 @@
          return false
        }
        item.subtabs = item.subtabs.filter(tab => {
          if (
            tab.blacklist && tab.blacklist.length > 0 &&
            tab.blacklist.filter(v => roleId.indexOf(v) > -1).length > 0
          ) {
            return false
          }
          return true
        })
        item.subtabs = item.subtabs.map(tab => {
          tab.components = this.filterComponent(tab.components, roleId, permAction, permMenus)
          return tab
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
@@ -415,14 +415,14 @@
      <div className="modal-menu-setting-script">
        <Form {...formItemLayout}>
          <Row gutter={24}>
            <Col span={8}>
              <Form.Item label={'回调表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
            <Col span={4}>
              <Form.Item labelCol={{span: 17}} wrapperCol={{span: 7}} label={'回调表名'} style={{whiteSpace: 'nowrap', margin: 0}}>
                {setting.cbTable}
              </Form.Item>
            </Col>
            <Col span={16}>
              <Form.Item label={'报错字段'} style={{margin: 0}}>
                ErrorCode, retmsg
            <Col span={20}>
              <Form.Item labelCol={{span: 4}} wrapperCol={{span: 20}} label={'报错字段'} style={{margin: 0}}>
                ErrorCode(增加后缀NT表示数据不回滚,如ENT、NNT、FNT、NMNT), retmsg
              </Form.Item>
            </Col>
            {usefulFields ? <Col span={24} className="sqlfield">
src/views/pcdesign/index.jsx
@@ -5,10 +5,8 @@
import moment from 'moment'
import HTML5Backend from 'react-dnd-html5-backend'
import { ConfigProvider, notification, Modal, Collapse, Switch, Button, Icon } from 'antd'
// import html2canvas from 'html2canvas'
import Api from '@/api'
// import options from '@/store/options.js'
import Utils from '@/utils/utils.js'
import zhCN from '@/locales/zh-CN/mob.js'
import enUS from '@/locales/en-US/mob.js'
@@ -25,7 +23,7 @@
const { confirm } = Modal
const MenuForm = asyncComponent(() => import('./menuform'))
const MenuShell = asyncComponent(() => import('@/menu/menushell'))
const MenuShell = asyncComponent(() => import('@/pc/menushell'))
const SourceWrap = asyncComponent(() => import('@/pc/modulesource'))
const BgController = asyncComponent(() => import('@/pc/bgcontroller'))
const PasteController = asyncComponent(() => import('@/menu/pastecontroller'))
@@ -40,6 +38,7 @@
sessionStorage.setItem('isEditState', 'true')
sessionStorage.setItem('editMenuType', 'menu') // 编辑菜单类型
sessionStorage.setItem('appType', 'pc')        // 应用类型
document.body.className = ''
window.GLOB.UserComponentMap = new Map() // 缓存用户自定义组件