king
2021-04-20 d1657e9835a6b3350dee76956deae3029cfe4b11
2021-04-20
21个文件已修改
7个文件已添加
658 ■■■■ 已修改文件
src/assets/mobimg/navtop-mob.png 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/customscript/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/index.jsx 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/index.scss 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/menusetting/index.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/index.jsx 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/index.scss 52 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/wrapsetting/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modulesource/option.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/index.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/customscript/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editTable/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/mobimg/navtop-mob.png
src/menu/datasource/verifycard/customscript/index.jsx
@@ -220,7 +220,7 @@
          </Col>
          <Col span={24} className="sqlfield">
            <Form.Item label={'可用字段'}>
              id, bid, loginuid, sessionuid, userid, username, fullname, login_city, appkey, time_id, orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}
              id, bid, loginuid, sessionuid, userid, username, fullname, login_city, appkey, time_id, orderBy, pageSize, pageIndex{usefulFields ? ', ' + usefulFields : ''}{window.GLOB.urlFields ? ', ' + window.GLOB.urlFields.join(', ') : ''}
            </Form.Item>
          </Col>
          <Col span={10} style={{width: '43%'}}>
src/menu/datasource/verifycard/index.jsx
@@ -49,6 +49,7 @@
        inputType: 'input',
        editable: true,
        unique: true,
        copy: true,
        width: '28%'
      },
      {
src/mob/components/navbar/normal-navbar/index.jsx
@@ -12,6 +12,7 @@
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
const MenuComponent = asyncIconComponent(() => import('./menusetting'))
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
class NormalNavbar extends Component {
  static propTpyes = {
@@ -34,13 +35,19 @@
        uuid: card.uuid,
        type: card.type,
        floor: card.floor,
        dataName: '',
        format: 'object',   // 组件属性 - 数据格式
        pageable: false,    // 组件属性 - 是否可分页
        switchable: false,  // 组件属性 - 数据是否可切换
        dataName: card.dataName || '',
        width: card.width || 24,
        name: card.name,
        subtype: card.subtype,
        wrap: { name: card.name, width: card.width || 1200 },
        style: { },
        setting: { interType: 'system' },
        wrap: { name: card.name, datatype: 'static', height: 50 },
        style: {borderTopColor: '#bcbcbc', borderTopWidth: '1px', paddingTop: '5px', fontSize: '13px' },
        menus: [],
        columns: [],
        scripts: [],
      }
      if (card.config) {
@@ -99,10 +106,7 @@
    if (comIds[0] !== card.uuid) return
    let _card = {...card}
    if (comIds.length === 1) {
      _card = {...card, style}
    }
    let _card = {...card, style}
    this.setState({
      card: _card
@@ -114,7 +118,7 @@
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid], ['font', 'background', 'shadow'], card.style)
    MKEmitter.emit('changeStyle', [card.uuid], ['font', 'background', 'border', 'padding'], card.style)
  }
  clickComponent = (e) => {
@@ -127,15 +131,15 @@
  changeMenu = (menu) => {
    if (menu.property === 'link') {
      window.open(menu.link)
      return
    } else {
      MKEmitter.emit('changeEditMenu', {
        fixed: menu.property === 'menu',
        MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
        copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
        MenuNo: menu.MenuNo,
        MenuName: menu.name,
      })
    }
    MKEmitter.emit('changeEditMenu', {
      fixed: menu.property === 'menu',
      MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
      copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
      MenuNo: menu.MenuNo,
      MenuName: menu.name,
    })
  }
  render() {
@@ -145,6 +149,7 @@
    if (_style.shadow) {
      _style.boxShadow = '0 0 4px ' + _style.shadow
    }
    _style.height = card.wrap.height
    return (
      <div className="normal-navbar-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
@@ -154,6 +159,8 @@
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <Icon style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
          </div>
        } trigger="hover">
          <Icon type="tool" />
@@ -161,14 +168,14 @@
        <div className="menu">
          {card.menus.map(menu => {
            return (
              <div class="am-tab-bar-tab">
                <div class="am-tab-bar-tab-icon">
                  <span class="am-badge am-tab-bar-tab-badge tab-badge">
                    <Icon type="font-colors" />
                    <sup class="am-badge-text">1</sup>
              <div key={menu.MenuID} className="am-tab-bar-tab" onDoubleClick={() => this.changeMenu(menu)}>
                {menu.icon ? <div className="am-tab-bar-tab-icon">
                  <span className="am-badge am-tab-bar-tab-badge tab-badge">
                    <Icon type={menu.icon} />
                    {menu.tip ? <sup className="am-badge-text"></sup> : null}
                  </span>
                </div>
                <p class="am-tab-bar-tab-title">{menu.name}</p>
                </div> : null}
                <p className="am-tab-bar-tab-title">{menu.name}</p>
              </div>
            )
          })}
src/mob/components/navbar/normal-navbar/index.scss
@@ -8,40 +8,37 @@
  background-position: center center;
  background-repeat: no-repeat;
  background-size: cover;
  min-height: 50px;
  min-height: 30px;
  z-index: 3;
  
  .menu {
    display: block;
    height: 100%;
    display: flex;
    font-size: inherit;
    color: inherit;
    .ant-menu {
      background: transparent;
      line-height: inherit;
      font-size: inherit;
      color: inherit;
      border: 0;
      .ant-menu-item:hover, .ant-menu-item-active {
        color: unset;
    .am-tab-bar-tab {
      position: relative;
      text-align: center;
      flex: 1;
      cursor: pointer;
      .anticon {
        font-size: 150%;
      }
      .ant-menu-item span {
        display: inline-block;
      .am-badge-text {
        position: absolute;
        top: -2px;
        height: 8px;
        width: 8px;
        border-radius: 100%;
        background: #ff5b05;
        z-index: 1;
      }
      p {
        margin-bottom: 0;
      }
    }
    .ant-menu-horizontal > .ant-menu-item:hover, .ant-menu-horizontal > .ant-menu-item-active, .ant-menu-horizontal > .ant-menu-item-open, .ant-menu-horizontal > .ant-menu-item-selected {
      color: unset;
    }
  }
  .card-control {
    position: absolute;
    top: 0px;
    left: 0px;
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
    position: absolute;
    z-index: 2;
@@ -112,22 +109,3 @@
.top-menu-popover {
  padding-top: 0!important;
}
.normal-navbar-submenu {
  .ant-menu-item-group {
    float: left;
  }
  .ant-menu-item {
    height: 32px;
    line-height: 32px;
    span {
      display: inline-block;
      width: 100%;
      height: 100%;
      padding: 0 16px 0 28px;
    }
    padding: 0;
  }
  .ant-menu .ant-menu-item-selected {
    background-color: #ffffff;
  }
}
src/mob/components/navbar/normal-navbar/menusetting/index.jsx
@@ -51,6 +51,7 @@
        >
          <MenuTable
            menus={config.menus}
            cols={config.columns}
            ref={(ref) => { this.mTable = ref }}
          />
        </Modal>
src/mob/components/navbar/normal-navbar/menusetting/menuform/index.jsx
@@ -2,13 +2,15 @@
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Radio, Tooltip, Icon, Select } from 'antd'
import { minkeIconSystem } from '@/utils/option.js'
import './index.scss'
const { TextArea } = Input
class SettingForm extends Component {
  static propTpyes = {
    menu: PropTypes.object,    // 卡片行信息
    menu: PropTypes.object,      // 菜单信息
    cols: PropTypes.array,       // 字段集
    inputSubmit: PropTypes.func  // 回车事件
  }
@@ -69,7 +71,7 @@
  }
  render() {
    const { menu } = this.props
    const { menu, cols } = this.props
    const { getFieldDecorator } = this.props.form
    const { property, appMenus } = this.state
@@ -87,7 +89,7 @@
    return (
      <Form {...formItemLayout}>
        <Row gutter={24}>
          <Col span={22}>
          <Col span={12}>
            <Form.Item label="菜单名称">
              {getFieldDecorator('name', {
                initialValue: menu.name,
@@ -100,7 +102,7 @@
              })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
          <Col span={22}>
          <Col span={12}>
            <Form.Item label="菜单参数">
              {getFieldDecorator('MenuNo', {
                initialValue: menu.MenuNo || '',
@@ -113,23 +115,44 @@
              })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
          <Col span={22}>
          <Col span={12}>
            <Form.Item label="图标">
              {getFieldDecorator('icon', {
                initialValue: menu.icon || ''
              })(
                <Select>
                  {appMenus.map(item => (<Select.Option key={item.MenuID} value={item.MenuID}>{item.MenuName}</Select.Option>))}
                <Select showSearch allowClear>
                  {minkeIconSystem.normal.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                  {minkeIconSystem.trademark.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                  {minkeIconSystem.data.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                  {minkeIconSystem.edit.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                  {minkeIconSystem.hint.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                  {minkeIconSystem.direction.map(icon => <Select.Option key={icon} value={icon}><Icon type={icon} /></Select.Option>)}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={22}>
          <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="绑定提示字段后,会在菜单右上角显示提示信息。注:在添加图标时有效。">
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
                提示
              </Tooltip>
            }>
              {getFieldDecorator('tip', {
                initialValue: menu.tip || ''
              })(
                <Select allowClear>
                  {cols.map(item => <Select.Option key={item.uuid} value={item.field}>{item.label}</Select.Option>)}
                </Select>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="菜单属性">
              {getFieldDecorator('property', {
                initialValue: menu.property || 'menu'
              })(
                <Radio.Group onChange={this.changeProperty}>
                <Radio.Group onChange={this.changeProperty} style={{whiteSpace: 'nowrap'}}>
                  <Radio value="menu">菜单</Radio>
                  <Radio value="link">链接</Radio>
                  <Radio value="linkmenu">关联菜单</Radio>
@@ -137,7 +160,7 @@
              )}
            </Form.Item>
          </Col>
          <Col span={22}>
          <Col span={12}>
            <Form.Item label="隐藏">
              {getFieldDecorator('hidden', {
                initialValue: menu.hidden || 'false'
@@ -149,7 +172,7 @@
              )}
            </Form.Item>
          </Col>
          {property === 'link' ? <Col span={22}>
          {property === 'link' ? <Col span={12}>
            <Form.Item label="链接地址">
              {getFieldDecorator('link', {
                initialValue: menu.link || '',
@@ -160,7 +183,7 @@
              })(<TextArea rows={2} />)}
            </Form.Item>
          </Col> : null}
          {property === 'linkmenu' ? <Col span={22}>
          {property === 'linkmenu' ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="关联当前app中已有的菜单。">
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
@@ -180,7 +203,7 @@
              )}
            </Form.Item>
          </Col> : null}
          {property === 'menu' ? <Col span={22}>
          {property === 'menu' ? <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="复制菜单仅在当前菜单不存在时有效。">
                <Icon type="question-circle" style={{color: '#c49f47', marginRight: '3px'}}/>
src/mob/components/navbar/normal-navbar/menusetting/menutable/index.jsx
@@ -12,7 +12,8 @@
class MenuTable extends Component {
  static propTpyes = {
    menus: PropTypes.object,    // 卡片行信息
    menus: PropTypes.array,     // 卡片行信息
    cols: PropTypes.array,      // 字段集
  }
  state = {
@@ -25,6 +26,9 @@
        const trans = {menu: '菜单', link: '链接', linkmenu: '关联菜单'}
        return trans[text]
      }},
      { title: '图标', dataIndex: 'icon', key: 'icon',  render: (text, record) => {
        return text ? <Icon type={text} /> : ''
      }},
      { title: '是否隐藏', dataIndex: 'hidden', key: 'hidden',  render: (text, record) => {
        const trans = {'true': '是', 'false': '否'}
@@ -151,6 +155,7 @@
  }
  render() {
    const { cols } = this.props
    const { columns, data, visible, editMenu } = this.state
    return (
@@ -165,7 +170,7 @@
        <Modal
          title="编辑"
          visible={visible}
          width={600}
          width={750}
          maskClosable={false}
          onOk={this.menuSubmit}
          onCancel={() => { this.setState({ visible: false }) }}
@@ -173,6 +178,7 @@
        >
          <MenuForm
            menu={editMenu}
            cols={cols}
            inputSubmit={this.menuSubmit}
            wrappedComponentRef={(inst) => this.menuRef = inst}
          />
src/mob/components/navbar/normal-navbar/wrapsetting/index.jsx
@@ -50,7 +50,6 @@
  }
  render () {
    const { config } = this.props
    const { visible, dict, wrap } = this.state
    return (
@@ -58,7 +57,7 @@
        <Icon type="edit" title="编辑" onClick={() => this.editDataSource()} />
        <Modal
          wrapClassName="popview-modal"
          title={config.type === 'table' ? '表格设置' : '卡片设置'}
          title="菜单栏设置"
          visible={visible}
          width={800}
          maskClosable={false}
@@ -70,7 +69,6 @@
          <SettingForm
            dict={dict}
            wrap={wrap}
            config={config}
            inputSubmit={this.verifySubmit}
            wrappedComponentRef={(inst) => this.verifyRef = inst}
          />
src/mob/components/navbar/normal-navbar/wrapsetting/settingform/index.jsx
@@ -1,13 +1,12 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, InputNumber } from 'antd'
import { Form, Row, Col, Input, InputNumber, Tooltip, Icon, Radio } from 'antd'
import './index.scss'
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,      // 字典项
    config: PropTypes.object,    // 卡片行信息
    wrap: PropTypes.object,      // 数据源配置
    inputSubmit: PropTypes.func  // 回车事件
  }
@@ -80,6 +79,23 @@
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="选择静态值,无需配置数据源。">
                  <Icon type="question-circle" />
                  数据来源
                </Tooltip>
              }>
                {getFieldDecorator('datatype', {
                  initialValue: wrap.datatype || 'static'
                })(
                  <Radio.Group>
                    <Radio value="dynamic">动态</Radio>
                    <Radio value="static">静态</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col>
            <Col span={12}>
              <Form.Item label="高度">
                {getFieldDecorator('height', {
                  initialValue: wrap.height || 50,
@@ -89,7 +105,7 @@
                      message: this.props.dict['form.required.input'] + '高度!'
                    }
                  ]
                })(<InputNumber min={50} max={200} precision={0} onPressEnter={this.handleSubmit} />)}
                })(<InputNumber min={30} max={200} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
          </Row>
src/mob/components/topbar/normal-navbar/index.jsx
New file
@@ -0,0 +1,165 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Popover } from 'antd'
import asyncIconComponent from '@/utils/asyncIconComponent'
import MKEmitter from '@/utils/events.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
class NormalNavbar extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
    updateConfig: PropTypes.func,
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    card: null,
    back: false
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    if (card.isNew) {
      let _card = {
        uuid: card.uuid,
        type: card.type,
        floor: card.floor,
        width: card.width || 24,
        subtype: card.subtype,
        wrap: { height: 50, title: 'NavBar' },
        style: {borderBottomColor: '#bcbcbc', borderBottomWidth: '1px', paddingLeft: '10px', paddingRight: '10px', lineHeight: '2.8', fontSize: '18px' },
      }
      if (card.config) {
        let config = fromJS(card.config).toJS()
        _card.wrap = config.wrap
        _card.style = config.style
      }
      this.setState({
        card: _card
      })
      this.props.updateConfig(_card)
    } else {
      this.setState({
        card: fromJS(card).toJS()
      })
    }
  }
  componentDidMount () {
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('submitStyle', this.getStyle)
  }
  /**
   * @description 卡片行外层信息更新(数据源,样式等)
   */
  updateComponent = (component) => {
    this.setState({
      card: component
    })
    component.width = component.wrap.width
    component.name = component.wrap.name
    this.props.updateConfig(component)
  }
  getStyle = (comIds, style) => {
    const { card } = this.state
    if (comIds[0] !== card.uuid) return
    let _card = {...card, style}
    this.setState({
      card: _card
    })
    this.props.updateConfig(_card)
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid], ['font', 'background', 'border', 'padding', 'shadow'], card.style)
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
      MKEmitter.emit('clickComponent', this.state.card)
    }
  }
  changeMenu = (menu) => {
    if (menu.property === 'link') {
      window.open(menu.link)
    } else {
      MKEmitter.emit('changeEditMenu', {
        fixed: menu.property === 'menu',
        MenuID: menu.property === 'linkmenu' ? menu.linkMenuId : menu.MenuID,
        copyMenuId: menu.property === 'menu' ? menu.copyMenuId : '',
        MenuNo: menu.MenuNo,
        MenuName: menu.name,
      })
    }
  }
  render() {
    const { card } = this.state
    let _style = {...card.style}
    if (_style.shadow) {
      _style.boxShadow = '0 0 4px ' + _style.shadow
    }
    _style.height = card.wrap.height
    return (
      <div className="normal-topbar-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">
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <div className="am-navbar">
          <div className="am-navbar-left">
            <Icon type="left" />
          </div>
          <div className="am-navbar-title">{card.wrap.title || ''}</div>
          <div className="am-navbar-right"></div>
        </div>
      </div>
    )
  }
}
export default NormalNavbar
src/mob/components/topbar/normal-navbar/index.scss
New file
@@ -0,0 +1,52 @@
.normal-topbar-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: 30px;
  z-index: 3;
  .anticon-tool {
    position: absolute;
    z-index: 2;
    font-size: 16px;
    right: 1px;
    top: 1px;
    cursor: pointer;
    padding: 5px;
    background: rgba(255, 255, 255, 0.55);
    color: rgba(0, 0, 0, 0.65);
  }
  .am-navbar {
    height: 100%;
    display: flex;
    font-style: inherit;
    font-weight: inherit;
    .am-navbar-left {
      flex: 1;
      text-align: left;
    }
    .am-navbar-title {
      text-align: center;
      font-style: inherit;
      font-weight: inherit;
      flex: 1;
    }
    .am-navbar-right {
      flex: 1;
    }
  }
}
.normal-topbar-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.normal-topbar-edit-box:hover {
  box-shadow: 0px 0px 4px #1890ff;
}
src/mob/components/topbar/normal-navbar/wrapsetting/index.jsx
New file
@@ -0,0 +1,81 @@
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 { visible, dict, wrap } = this.state
    return (
      <div className="model-menu-setting-wrap">
        <Icon type="edit" title="编辑" onClick={() => this.editDataSource()} />
        <Modal
          wrapClassName="popview-modal"
          title="导航栏设置"
          visible={visible}
          width={600}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <SettingForm
            dict={dict}
            wrap={wrap}
            inputSubmit={this.verifySubmit}
            wrappedComponentRef={(inst) => this.verifyRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default DataSource
src/mob/components/topbar/normal-navbar/wrapsetting/index.scss
New file
@@ -0,0 +1,7 @@
.model-menu-setting-wrap {
  display: inline-block;
  >.anticon-edit {
    color: #1890ff;
  }
}
src/mob/components/topbar/normal-navbar/wrapsetting/settingform/index.jsx
New file
@@ -0,0 +1,82 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, InputNumber } from 'antd'
import './index.scss'
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,      // 字典项
    wrap: PropTypes.object,      // 数据源配置
    inputSubmit: PropTypes.func  // 回车事件
  }
  state = {}
  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={22}>
              <Form.Item label="标题">
                {getFieldDecorator('title', {
                  initialValue: wrap.title || ''
                })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
            <Col span={22}>
              <Form.Item label="高度">
                {getFieldDecorator('height', {
                  initialValue: wrap.height || 50,
                  rules: [
                    {
                      required: true,
                      message: this.props.dict['form.required.input'] + '高度!'
                    }
                  ]
                })(<InputNumber min={30} max={200} precision={0} onPressEnter={this.handleSubmit} />)}
              </Form.Item>
            </Col>
          </Row>
        </Form>
      </div>
    )
  }
}
export default Form.create()(SettingForm)
src/mob/components/topbar/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/mob/mobshell/card.jsx
@@ -19,6 +19,7 @@
const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
const NormalLogin = asyncComponent(() => import('@/pc/components/login/normal-login'))
const NormalNavbar = asyncComponent(() => import('@/mob/components/navbar/normal-navbar'))
const NormalTopbar = asyncComponent(() => import('@/mob/components/topbar/normal-navbar'))
const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => {
  const originalIndex = findCard(id).index
@@ -54,7 +55,7 @@
  }
  let col = 'ant-col-' + (card.width || 24)
  if (card.type === 'navbar') {
  if (card.type === 'navbar' || card.type === 'topbar') {
    col = ''
  } else if (card.type === 'login') {
    let height = ''
@@ -103,6 +104,8 @@
      return (<NormalLogin card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'navbar') {
      return (<NormalNavbar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'topbar') {
      return (<NormalTopbar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    }
  }
src/mob/mobshell/index.jsx
@@ -53,7 +53,7 @@
    let uuids = MenuUtils.getDelButtonIds(card)
    confirm({
      title: `确定删除《${card.name}》吗?`,
      title: `确定删除${card.name ? `《${card.name}》` : '组件'}吗?`,
      content: hasComponent ? '当前组件中含有子组件!' : '',
      onOk() {
        MKEmitter.emit('delButtons', uuids)
@@ -99,6 +99,7 @@
        dashboard: '仪表盘',
        form: '表单',
        card: '卡片',
        navbar: '导航栏',
        login: '登录'
      }
      let i = 1
src/mob/modulesource/option.jsx
@@ -19,10 +19,12 @@
import form from '@/assets/mobimg/form.png'
import Login from '@/assets/mobimg/login.png'
import dashboard from '@/assets/mobimg/dashboard.png'
import NavTop from '@/assets/mobimg/navtop-mob.png'
// 组件配置信息
export const menuOptions = [
  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'mobnavbar', title: '导航栏', width: 1200 },
  { type: 'menu', url: NavTop, component: 'topbar', subtype: 'topbar', title: '导航栏' },
  { type: 'menu', url: Navbar, component: 'navbar', subtype: 'tabbar', title: '菜单栏' },
  { 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/templates/sharecomponent/settingcalcomponent/verifycard/index.jsx
@@ -327,6 +327,7 @@
  }
  render() {
    const { config } = this.props
    const { columns, setting, scripts, colColumns, activeKey, loading } = this.state
    return (
@@ -350,7 +351,7 @@
              wrappedComponentRef={(inst) => this.contrastForm = inst}
            />
            <FieldsComponent
              config={{...this.props.config, columns}}
              config={{...config, columns}}
              type="fields"
              updatefield={this.updatefields}
            />
@@ -373,6 +374,7 @@
              dict={this.props.dict}
              setting={setting}
              scripts={scripts}
              urlFields={config.urlFields}
              defaultSql={this.state.defaultsql}
              searches={this.props.searches}
              scriptsChange={this.scriptsChange}
src/templates/sharecomponent/settingcomponent/settingform/index.jsx
@@ -463,6 +463,7 @@
              setting={setting}
              scripts={scripts}
              defaultSql={defaultSql}
              urlFields={config.urlFields}
              searches={this.props.search}
              scriptsChange={this.scriptsChange}
              scriptsUpdate={this.scriptsUpdate}
@@ -480,6 +481,7 @@
              setting={setting}
              scripts={preScripts}
              regoptions={regoptions}
              urlFields={config.urlFields}
              searches={this.props.search}
              scriptsUpdate={this.preScriptsUpdate}
              wrappedComponentRef={(inst) => this.preScriptsForm = inst}
src/templates/sharecomponent/settingcomponent/settingform/simplescript/index.jsx
@@ -20,6 +20,7 @@
    setting: PropTypes.object,      // 设置
    scripts: PropTypes.array,       // 自定义脚本列表
    searches: PropTypes.array,      // 搜索条件
    urlFields: PropTypes.any,       // url变量
    regoptions: PropTypes.any,      // 正则替换
    scriptsChange: PropTypes.func,  // 自定义脚本切换时验证
    scriptsUpdate: PropTypes.func   // 表单
@@ -100,7 +101,7 @@
  }
  UNSAFE_componentWillMount() {
    const { searches, scripts } = this.props
    const { searches, scripts, urlFields } = this.props
    let _usefulFields = []
    let scriptsColumns = fromJS(this.state.scriptsColumns).toJS()
@@ -123,6 +124,11 @@
          _usefulFields.push(item.field)
        }
      })
      if (urlFields) {
        _usefulFields.push(...urlFields)
      }
      _usefulFields = _usefulFields.join(', ')
      scriptsColumns = scriptsColumns.filter(item => {
        if (item.dataIndex === 'sql') {
src/templates/zshare/customscript/index.jsx
@@ -19,6 +19,7 @@
    setting: PropTypes.object,      // 设置
    scripts: PropTypes.array,       // 自定义脚本列表
    searches: PropTypes.array,      // 搜索条件
    urlFields: PropTypes.any,       // url变量
    defaultSql: PropTypes.string,   // 默认sql
    scriptsChange: PropTypes.func,  // 自定义脚本切换时验证
    scriptsUpdate: PropTypes.func   // 表单
@@ -87,7 +88,7 @@
  }
  UNSAFE_componentWillMount() {
    const { searches, scripts } = this.props
    const { searches, scripts, urlFields } = this.props
    let _usefulFields = []
    searches.forEach(item => {
@@ -108,6 +109,10 @@
      }
    })
    if (urlFields) {
      _usefulFields.push(...urlFields)
    }
    this.setState({
      usefulFields: _usefulFields.join(', '),
      scripts: fromJS(scripts).toJS()
src/templates/zshare/editTable/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { DndProvider, DragSource, DropTarget } from 'react-dnd'
import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification, message, Modal } from 'antd'
import { Table, Input, InputNumber, Popconfirm, Form, Icon, Select, Radio, Cascader, notification, message, Modal, Typography } from 'antd'
import Utils from '@/utils/utils.js'
import ColorSketch from '@/mob/colorsketch'
@@ -15,6 +15,7 @@
let eTDict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS
const EditableContext = React.createContext()
let dragingIndex = -1
const { Paragraph } = Typography
class BodyRow extends React.Component {
  render() {
@@ -494,6 +495,9 @@
    }
    
    const columns = this.state.columns.map(col => {
      if (col.copy) {
        col.render = (text) => (<Paragraph copyable>{text}</Paragraph>)
      }
      if (!col.editable) return col
      return {
        ...col,
src/utils/option.js
@@ -758,6 +758,7 @@
    'alipay',
  ],
  normal: [
    'user',
    'account-book',
    'alert',
    'api',
@@ -805,6 +806,7 @@
    'key',
    'man',
    'woman',
    'team',
    'poweroff',
    'search',
    'shopping-cart',
src/views/menudesign/index.jsx
@@ -849,7 +849,7 @@
            error = `组件《${item.name}》未设置数据源!`
          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
            error = `组件《${item.name}》未设置数据源!`
          } else if (!item.setting.primaryKey && MenuType !== 'billPrint') {
          } else if (!item.setting.primaryKey && MenuType !== 'billPrint' && item.subtype !== 'propcard') {
            error = `组件《${item.name}》未设置主键!`
          }
        }
src/views/mobdesign/index.jsx
@@ -1284,15 +1284,18 @@
        } else if (item.type === 'group') {
          check(item.components)
          return
        } else if (item.type === 'navbar' && !item.wrap.MenuNo) {
          error = `导航栏《${item.name}》未设置菜单参数!`
        }
        if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['propcard', 'brafteditor', 'sandbox', 'tabbar'].includes(item.subtype) && item.wrap.datatype === 'static') return
  
        if (item.setting) {
          if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) {
            error = `组件《${item.name}》未设置数据源!`
          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
            error = `组件《${item.name}》未设置数据源!`
          } else if (!item.setting.primaryKey) {
          } else if (!item.setting.primaryKey && !['propcard', 'tabbar'].includes(item.subtype)) {
            error = `组件《${item.name}》未设置主键!`
          }
        }
src/views/pcdesign/index.jsx
@@ -1337,7 +1337,7 @@
            error = `组件《${item.name}》未设置数据源!`
          } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) {
            error = `组件《${item.name}》未设置数据源!`
          } else if (!item.setting.primaryKey) {
          } else if (!item.setting.primaryKey && item.subtype !== 'propcard') {
            error = `组件《${item.name}》未设置主键!`
          }
        }