From ca788834ea15d6dd43bf0923757ca1d46d00ebc4 Mon Sep 17 00:00:00 2001
From: king <18310653075@163.com>
Date: 星期一, 12 七月 2021 23:17:26 +0800
Subject: [PATCH] 2021-07-12

---
 src/menu/datasource/verifycard/settingform/index.scss                |    8 
 src/menu/components/card/balcony/index.jsx                           |  300 +++++++++++++++
 src/utils/utils-datamanage.js                                        |    2 
 src/menu/components/card/balcony/wrapsetting/settingform/index.scss  |   36 +
 src/menu/components/share/styleInput/index.scss                      |   11 
 src/menu/components/card/balcony/wrapsetting/settingform/index.jsx   |  301 +++++++++++++++
 src/menu/components/share/styleInput/index.jsx                       |  117 ++++++
 src/menu/datasource/verifycard/settingform/index.jsx                 |   25 +
 src/utils/utils-custom.js                                            |   74 +++
 src/menu/components/card/balcony/wrapsetting/index.scss              |    7 
 src/menu/pastecontroller/index.jsx                                   |    2 
 src/menu/components/card/balcony/index.scss                          |   77 ++++
 src/tabviews/custom/index.jsx                                        |    4 
 src/menu/components/card/balcony/wrapsetting/index.jsx               |   83 ++++
 src/menu/components/card/data-card/wrapsetting/settingform/index.jsx |   27 +
 src/menu/menushell/card.jsx                                          |    3 
 src/menu/components/card/data-card/wrapsetting/index.jsx             |    4 
 src/menu/menushell/index.jsx                                         |    1 
 src/menu/popview/index.jsx                                           |    2 
 src/menu/modulesource/option.jsx                                     |    1 
 20 files changed, 1,065 insertions(+), 20 deletions(-)

diff --git a/src/menu/components/card/balcony/index.jsx b/src/menu/components/card/balcony/index.jsx
new file mode 100644
index 0000000..acb1fd6
--- /dev/null
+++ b/src/menu/components/card/balcony/index.jsx
@@ -0,0 +1,300 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Icon, Popover, Modal } from 'antd'
+
+import asyncComponent from '@/utils/asyncComponent'
+import asyncIconComponent from '@/utils/asyncIconComponent'
+import { resetStyle } from '@/utils/utils-custom.js'
+import MKEmitter from '@/utils/events.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 CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
+const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
+const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
+const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent'))
+const ClockComponent = asyncIconComponent(() => import('@/menu/components/share/clockcomponent'))
+const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
+
+const { confirm } = Modal
+
+class BalconyEditComponent 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 ismob = sessionStorage.getItem('appType') === 'mob'
+      let _card = {
+        uuid: card.uuid,
+        type: card.type,
+        floor: card.floor,
+        tabId: card.tabId || '',
+        parentId: card.parentId || '',
+        format: 'object',   // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡
+        pageable: false,    // 缁勪欢灞炴�� - 鏄惁鍙垎椤�
+        switchable: false,  // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹�
+        dataName: card.dataName || '',
+        width: card.width || 24,
+        name: card.name,
+        subtype: card.subtype,
+        setting: { interType: 'system' },
+        wrap: { name: card.name, width: card.width || 24, linkType: 'static', position: 'relative', datatype: 'static' },
+        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
+        columns: [],
+        scripts: [],
+        elements: [],
+      }
+
+      if (card.config) {
+        let config = fromJS(card.config).toJS()
+
+        _card.wrap = config.wrap
+        _card.wrap.name = card.name
+        _card.style = config.style
+
+        _card.elements = _card.elements.map(elem => {
+          elem.uuid = Utils.getuuid()
+          return elem
+        })
+      }
+      this.setState({
+        card: _card
+      })
+      this.props.updateConfig(_card)
+    } else {
+      this.setState({
+        card: fromJS(card).toJS()
+      })
+    }
+  }
+
+  componentDidMount () {
+    MKEmitter.addListener('submitStyle', this.getStyle)
+    MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle)
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+    MKEmitter.removeListener('submitStyle', this.getStyle)
+    MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle)
+  }
+
+  updateComponentStyle = (parentId, keys, style) => {
+    const { card } = this.state
+
+    if (card.uuid !== parentId) return
+
+    let subcards = card.subcards.map(item => {
+      if (keys.includes(item.uuid)) {
+        item.style = {...item.style, ...style}
+      }
+      return item
+    })
+
+    this.setState({card: {...card, subcards: []}}, () => {
+      this.updateComponent({...card, subcards: subcards})
+    })
+  }
+
+  /**
+   * @description 鍗$墖琛屽灞備俊鎭洿鏂帮紙鏁版嵁婧愶紝鏍峰紡绛夛級
+   */
+  updateComponent = (component) => {
+    this.setState({
+      card: component
+    })
+
+    component.width = component.wrap.width
+    component.name = component.wrap.name
+
+    this.props.updateConfig(component)
+  }
+
+  /**
+   * @description 鍗曚釜鍗$墖淇℃伅鏇存柊
+   */
+  updateCard = (cell) => {
+    let card = fromJS(this.state.card).toJS()
+
+    card.subcards = card.subcards.map(item => {
+      if (item.uuid === cell.uuid) return cell
+      return item
+    })
+
+    this.setState({card})
+
+    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)
+
+        _this.setState({card})
+        _this.props.updateConfig(card)
+      },
+      onCancel() {}
+    })
+  }
+
+  changeStyle = () => {
+    const { card } = this.state
+
+    MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin'], card.style)
+  }
+
+  getStyle = (comIds, style) => {
+    const { card } = this.state
+
+    if (comIds.length !== 1 || comIds[0] !== card.uuid) return
+
+    let _card = {...card, style}
+
+    this.setState({
+      card: _card
+    })
+    
+    this.props.updateConfig(_card)
+  }
+
+  addCard = () => {
+    let card = fromJS(this.state.card).toJS()
+
+    let newcard = {
+      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: []
+    }
+
+    if (card.subcards.length > 0) {
+      newcard = fromJS(card.subcards.slice(-1)[0]).toJS()
+      newcard.uuid = Utils.getuuid()
+      newcard.elements = newcard.elements.map(elem => {
+        elem.uuid = Utils.getuuid()
+        return elem
+      })
+      newcard.backElements = newcard.backElements.map(elem => {
+        elem.uuid = Utils.getuuid()
+        return elem
+      })
+    }
+
+    card.subcards.push(newcard)
+    
+    this.setState({card})
+    this.props.updateConfig(card)
+  }
+
+  move = (item, direction) => {
+    let card = fromJS(this.state.card).toJS()
+
+    let dragIndex = card.subcards.findIndex(c => c.uuid === item.uuid)
+    let hoverIndex = null
+
+    if (direction === 'left') {
+      hoverIndex = dragIndex - 1
+    } else {
+      hoverIndex = dragIndex + 1
+    }
+
+    if (hoverIndex === -1 || hoverIndex === card.subcards.length) return 
+
+    card.subcards.splice(hoverIndex, 0, ...card.subcards.splice(dragIndex, 1))
+
+    this.setState({card})
+    this.props.updateConfig(card)
+  }
+
+  clickComponent = (e) => {
+    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
+      e.stopPropagation()
+      MKEmitter.emit('clickComponent', this.state.card)
+    }
+  }
+
+  render() {
+    const { card } = this.state
+
+    let _style = resetStyle(card.style)
+
+    return (
+      <div className="menu-balcony-edit-box" style={_style} onClick={this.clickComponent} id={card.uuid}>
+        <NormalHeader defaultshow="hidden" config={card} updateComponent={this.updateComponent}/>
+        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
+          <div className="mk-popover-control">
+            <Icon className="plus" title="娣诲姞鍏冪礌" onClick={this.addElement} type="plus" />
+            <Icon className="plus" title="娣诲姞鎸夐挳" onClick={this.addButton} type="plus-square" />
+            <WrapComponent config={card} updateConfig={this.updateComponent} />
+            <CopyComponent type="balcony" card={card}/>
+            <PasteComponent config={card} options={['cardcell']} updateConfig={this.updateComponent} />
+            <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors" />
+            <ClockComponent config={card} updateConfig={this.updateComponent}/>
+            <UserComponent config={card}/>
+            <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" />
+        </Popover>
+        <CardCellComponent cards={card} cardCell={card} elements={card.elements} updateElement={this.updateCard}/>
+      </div>
+    )
+  }
+}
+
+export default BalconyEditComponent
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/index.scss b/src/menu/components/card/balcony/index.scss
new file mode 100644
index 0000000..1e071bd
--- /dev/null
+++ b/src/menu/components/card/balcony/index.scss
@@ -0,0 +1,77 @@
+.menu-balcony-edit-box {
+  position: relative;
+  box-sizing: border-box;
+  background: #ffffff;
+  background-position: center center;
+  background-repeat: no-repeat;
+  background-size: cover;
+  min-height: 30px;
+  
+  .card-control {
+    position: absolute;
+    top: 0px;
+    left: 0px;
+    .anticon-tool {
+      right: auto;
+      left: 1px;
+      padding: 1px;
+    }
+  }
+  .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);
+  }
+
+  .card-item {
+    overflow: hidden;
+    position: relative;
+    background-color: #ffffff;
+    background-position: center center;
+    background-repeat: no-repeat;
+    background-size: cover;
+    min-height: 20px;
+  }
+  
+  .card-item:hover {
+    box-shadow: 0px 0px 2px #1890ff;
+  }
+
+  .model-menu-card-cell-list .card-detail-row > .anticon-plus {
+    position: absolute;
+    right: -30px;
+    font-size: 16px;
+  }
+  .model-menu-action-list {
+    line-height: 40px;
+    .ant-row > .anticon-plus {
+      position: absolute;
+      right: -30px;
+      font-size: 16px;
+    }
+  }
+  .card-add-button {
+    text-align: right;
+    clear: left;
+    .anticon-plus {
+      font-size: 20px;
+      color: #26C281;
+      padding: 5px;
+      margin-right: 10px;
+    }
+  }
+}
+.menu-balcony-edit-box::after {
+  display: block;
+  content: ' ';
+  clear: both;
+}
+.menu-balcony-edit-box:hover {
+  z-index: 1;
+  box-shadow: 0px 0px 4px #1890ff;
+}
diff --git a/src/menu/components/card/balcony/wrapsetting/index.jsx b/src/menu/components/card/balcony/wrapsetting/index.jsx
new file mode 100644
index 0000000..a8332db
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/index.jsx
@@ -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 BalconyWrapSetting 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="鍗$墖璁剧疆"
+          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 BalconyWrapSetting
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/index.scss b/src/menu/components/card/balcony/wrapsetting/index.scss
new file mode 100644
index 0000000..04372e6
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/index.scss
@@ -0,0 +1,7 @@
+.model-menu-setting-wrap {
+  display: inline-block;
+
+  >.anticon-edit {
+    color: #1890ff;
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx b/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx
new file mode 100644
index 0000000..3cc7bf6
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/settingform/index.jsx
@@ -0,0 +1,301 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { fromJS } from 'immutable'
+import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select, Cascader } from 'antd'
+
+import MenuUtils from '@/utils/utils-custom.js'
+import StyleInput from '@/menu/components/share/styleInput'
+import './index.scss'
+
+class SettingForm extends Component {
+  static propTpyes = {
+    dict: PropTypes.object,
+    config: PropTypes.object,
+    wrap: PropTypes.object,
+    inputSubmit: PropTypes.func
+  }
+
+  state = {
+    roleList: [],
+    modules: [],
+    supmodules: [],
+    appType: sessionStorage.getItem('appType'),
+    linkType: this.props.wrap.linkType,
+    position: this.props.wrap.position,
+  }
+
+  UNSAFE_componentWillMount () {
+    let roleList = sessionStorage.getItem('sysRoles')
+    if (roleList) {
+      try {
+        roleList = JSON.parse(roleList)
+      } catch {
+        roleList = []
+      }
+    } else {
+      roleList = []
+    }
+
+    let menu = fromJS(window.GLOB.customMenu).toJS()
+
+    let modules = MenuUtils.getLinkModules(menu.components)
+    if (!modules) {
+      modules = []
+    }
+
+    let _menu = fromJS(window.GLOB.customMenu).toJS()
+
+    let supmodules = MenuUtils.getSupModules(_menu.components, '')
+    if (!supmodules) {
+      supmodules = []
+    }
+
+    this.setState({roleList, modules, supmodules})
+  }
+
+  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 { roleList, modules, supmodules, linkType, position } = this.state
+
+    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={
+                <Tooltip placement="topLeft" title="鐢ㄤ簬缁勪欢闂寸殑鍖哄垎銆�">
+                  <Icon type="question-circle" />
+                  缁勪欢鍚嶇О
+                </Tooltip>
+              }>
+                {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="鏍呮牸甯冨眬锛屾瘡琛岀瓑鍒嗕负24鍒椼��">
+                  <Icon type="question-circle" />
+                  瀹藉害
+                </Tooltip>
+              }>
+                {getFieldDecorator('width', {
+                  initialValue: wrap.width || 24,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.input'] + '瀹藉害!'
+                    }
+                  ]
+                })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="閫夋嫨闈欐�佸�硷紝鏃犻渶閰嶇疆鏁版嵁婧愩��">
+                  <Icon type="question-circle" />
+                  鏁版嵁鏉ユ簮
+                </Tooltip>
+              }>
+                {getFieldDecorator('datatype', {
+                  initialValue: wrap.datatype || 'dynamic'
+                })(
+                  <Radio.Group>
+                    <Radio value="dynamic">鍔ㄦ��</Radio>
+                    <Radio value="static">闈欐��</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="缁勪欢涓庡叾浠栫粍浠朵箣闂寸殑鎺у埗绫诲瀷锛岀嫭绔嬭〃绀轰笌鍏朵粬娌℃湁鍏宠仈銆�">
+                  <Icon type="question-circle" />
+                  鍙楁帶绫诲瀷
+                </Tooltip>
+              }>
+                {getFieldDecorator('linkType', {
+                  initialValue: wrap.linkType || 'static'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({linkType: e.target.value})}>
+                    <Radio value="static">鐙珛</Radio>
+                    <Radio value="sync">鍚屾</Radio>
+                    <Radio value="sup">涓婄骇</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {linkType === 'sup' ? <Col span={12}>
+              <Form.Item label="涓婄骇缁勪欢">
+                {getFieldDecorator('supModule', {
+                  initialValue: wrap.supModule,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '涓婄骇缁勪欢!'
+                    }
+                  ]
+                })(
+                  <Cascader options={supmodules} expandTrigger="hover" placeholder="" />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {linkType === 'sync' ? <Col span={12}>
+              <Form.Item label="鍚屾缁勪欢">
+                {getFieldDecorator('syncModule', {
+                  initialValue: wrap.syncModule,
+                  rules: [
+                    {
+                      required: true,
+                      message: this.props.dict['form.required.select'] + '鍚屾缁勪欢!'
+                    }
+                  ]
+                })(
+                  <Cascader options={modules} expandTrigger="hover" placeholder="" />
+                )}
+              </Form.Item>
+            </Col> : null}
+            {linkType === 'sync' ? <Col span={12}>
+              <Form.Item label="鍏ㄩ��">
+                {getFieldDecorator('checkAll', {
+                  initialValue: wrap.checkAll || 'hidden'
+                })(
+                  <Radio.Group>
+                    <Radio key="hidden" value="hidden"> 闅愯棌 </Radio>
+                    <Radio key="show" value="show"> 鏄剧ず </Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label={
+                <Tooltip placement="topLeft" title="浣跨敤鍥哄畾瀹氫綅鏃讹紝璇峰湪娴嬭瘯鐜涓煡鐪嬪畾浣嶆晥鏋溿��">
+                  <Icon type="question-circle" />
+                  浣嶇疆
+                </Tooltip>
+              }>
+                {getFieldDecorator('position', {
+                  initialValue: wrap.position || 'relative'
+                })(
+                  <Radio.Group onChange={(e) => this.setState({position: e.target.value})}>
+                    <Radio value="relative">鐩稿瀹氫綅</Radio>
+                    <Radio value="fixed">鍥哄畾瀹氫綅</Radio>
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col>
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濅笂">
+                {getFieldDecorator('top', {
+                  initialValue: wrap.top || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濆彸">
+                {getFieldDecorator('right', {
+                  initialValue: wrap.right || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濅笅">
+                {getFieldDecorator('bottom', {
+                  initialValue: wrap.bottom || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="璺濆乏">
+                {getFieldDecorator('left', {
+                  initialValue: wrap.left || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="瀹為檯瀹藉害">
+                {getFieldDecorator('realwidth', {
+                  initialValue: wrap.realwidth || ''
+                })(<StyleInput options={['px', 'vh', 'vw', '%']} />)}
+              </Form.Item>
+            </Col> : null}
+            {position === 'fixed' ? <Col span={12}>
+              <Form.Item label="鍙樻崲">
+                {getFieldDecorator('transform', {
+                  initialValue: wrap.transform || ''
+                })(
+                  <Select>
+                    <Select.Option key='1' value={''}>鏃�</Select.Option>
+                    <Select.Option key='2' value={'translateY(-50%)'}>涓婄Щ50%</Select.Option>
+                    <Select.Option key='3' value={'translateY(50%)'}>涓嬬Щ50%</Select.Option>
+                    <Select.Option key='5' value={'translateX(-50%)'}>宸︾Щ50%</Select.Option>
+                    <Select.Option key='4' value={'translateX(50%)'}>鍙崇Щ50%</Select.Option>
+                  </Select>
+                )}
+              </Form.Item>
+            </Col> : null}
+            <Col span={12}>
+              <Form.Item label="榛戝悕鍗�">
+                {getFieldDecorator('blacklist', {
+                  initialValue: wrap.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>
+      </div>
+    )
+  }
+}
+
+export default Form.create()(SettingForm)
\ No newline at end of file
diff --git a/src/menu/components/card/balcony/wrapsetting/settingform/index.scss b/src/menu/components/card/balcony/wrapsetting/settingform/index.scss
new file mode 100644
index 0000000..9644e12
--- /dev/null
+++ b/src/menu/components/card/balcony/wrapsetting/settingform/index.scss
@@ -0,0 +1,36 @@
+.model-menu-setting-form {
+  position: relative;
+
+  .anticon-question-circle {
+    color: #c49f47;
+    margin-right: 3px;
+  }
+  .ant-input-number {
+    width: 100%;
+  }
+  .css {
+    padding-top: 10px;
+    .css-class {
+      position: absolute;
+      right: 13px;
+      top: -15px;
+      z-index: 1;
+      button {
+        height: 25px;
+      }
+    }
+    .ant-form-item {
+      margin-bottom: 0;
+    }
+    .ant-form-item-label {
+      width: 16%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 84%;
+      .code-mirror-wrap .code-mirror-area .CodeMirror {
+        height: 100px;
+        min-height: 100px;
+      }
+    }
+  }
+}
\ No newline at end of file
diff --git a/src/menu/components/card/data-card/wrapsetting/index.jsx b/src/menu/components/card/data-card/wrapsetting/index.jsx
index 81346a6..8877617 100644
--- a/src/menu/components/card/data-card/wrapsetting/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/index.jsx
@@ -8,7 +8,7 @@
 import SettingForm from './settingform'
 import './index.scss'
 
-class DataSource extends Component {
+class CardWrapSetting extends Component {
   static propTpyes = {
     config: PropTypes.any,
     updateConfig: PropTypes.func
@@ -80,4 +80,4 @@
   }
 }
 
-export default DataSource
\ No newline at end of file
+export default CardWrapSetting
\ No newline at end of file
diff --git a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
index 3465f70..d1c8eb0 100644
--- a/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
+++ b/src/menu/components/card/data-card/wrapsetting/settingform/index.jsx
@@ -6,15 +6,16 @@
 
 class SettingForm extends Component {
   static propTpyes = {
-    dict: PropTypes.object,      // 瀛楀吀椤�
-    config: PropTypes.object,    // 鍗$墖琛屼俊鎭�
-    wrap: PropTypes.object,      // 鏁版嵁婧愰厤缃�
-    inputSubmit: PropTypes.func  // 鍥炶溅浜嬩欢
+    dict: PropTypes.object,
+    config: PropTypes.object,
+    wrap: PropTypes.object,
+    inputSubmit: PropTypes.func
   }
 
   state = {
     roleList: [],
     appType: sessionStorage.getItem('appType'),
+    cardType: this.props.wrap.cardType,
     MenuType: ''
   }
 
@@ -63,7 +64,7 @@
   render() {
     const { wrap, config } = this.props
     const { getFieldDecorator } = this.props.form
-    const { roleList, MenuType, appType } = this.state
+    const { roleList, MenuType, appType, cardType } = this.state
 
     const formItemLayout = {
       labelCol: {
@@ -163,10 +164,22 @@
                 {getFieldDecorator('cardType', {
                   initialValue: wrap.cardType || ''
                 })(
-                  <Radio.Group style={{whiteSpace: 'nowrap'}}>
+                  <Radio.Group style={{whiteSpace: 'nowrap'}} onChange={(e) => this.setState({cardType: e.target.value})}>
                     <Radio key="" value=""> 涓嶅彲閫� </Radio>
                     <Radio key="radio" value={'radio'}> 鍗曢�� </Radio>
                     {config.subtype !== 'propcard' ? <Radio key="checkbox" value={'checkbox'}> 澶氶�� </Radio> : null}
+                  </Radio.Group>
+                )}
+              </Form.Item>
+            </Col> : null}
+            {config.subtype === 'datacard' && appType === 'mob' && cardType === 'checkbox' ? <Col span={12}>
+              <Form.Item label="鍏ㄩ��">
+                {getFieldDecorator('checkAll', {
+                  initialValue: wrap.checkAll || 'hidden'
+                })(
+                  <Radio.Group>
+                    <Radio key="hidden" value="hidden"> 闅愯棌 </Radio>
+                    <Radio key="show" value="show"> 鏄剧ず </Radio>
                   </Radio.Group>
                 )}
               </Form.Item>
@@ -189,7 +202,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.subtype !== 'tablecard' ? <Col span={12}>
+            {config.subtype !== 'tablecard' && appType !== 'mob' ? <Col span={12}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title="榧犳爣鎮诞浜庡崱鐗囦笂鏂规椂锛屽崱鐗囨斁澶�1.05鍊嶃��">
                   <Icon type="question-circle" />
diff --git a/src/menu/components/share/styleInput/index.jsx b/src/menu/components/share/styleInput/index.jsx
new file mode 100644
index 0000000..4233217
--- /dev/null
+++ b/src/menu/components/share/styleInput/index.jsx
@@ -0,0 +1,117 @@
+import React, {Component} from 'react'
+import PropTypes from 'prop-types'
+import { is, fromJS } from 'immutable'
+import { Select, Input } from 'antd'
+
+import './index.scss'
+
+const { Option } = Select
+
+class StyleInput extends Component {
+  static propTpyes = {
+    defaultValue: PropTypes.any,
+    options: PropTypes.any,
+    value: PropTypes.any,
+    onChange: PropTypes.func,
+  }
+
+  state = {
+    value: '',
+    unit: '',
+    options: null
+  }
+
+  UNSAFE_componentWillMount () {
+    const { value, options } = this.props
+
+    let val = ''
+    let unit = ''
+
+    if (value !== undefined) {
+      val = value
+    }
+
+    unit = options[0]
+
+    if (val) {
+      if (val.indexOf('px') > -1) {
+        unit = 'px'
+      } else if (val.indexOf('%') > -1) {
+        unit = '%'
+      } else if (val.indexOf('vw') > -1) {
+        unit = 'vw'
+      } else if (val.indexOf('vh') > -1) {
+        unit = 'vh'
+      }
+    }
+
+    let _val = parseFloat(val)
+
+    if (isNaN(_val)) {
+      _val = ''
+    }
+
+    this.setState({value: _val, options: options, unit})
+  }
+
+  shouldComponentUpdate (nextProps, nextState) {
+    return !is(fromJS(this.state), fromJS(nextState))
+  }
+
+  /**
+   * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆
+   */
+  componentWillUnmount () {
+    this.setState = () => {
+      return
+    }
+  }
+
+  changeValue = (e) => {
+    const { unit } = this.state
+    let val = e.target.value
+
+    if (/\d+\.$/.test(val)) {
+      this.setState({
+        value: val
+      })
+      return
+    }
+    let _val = parseFloat(val)
+    
+    if (isNaN(_val)) {
+      _val = ''
+    }
+
+    this.setState({
+      value: _val,
+    })
+
+    this.props.onChange(_val ? `${_val}${unit}` : '')
+  }
+
+  changeUnit = (val) => {
+    const { value } = this.state
+
+    this.setState({unit: val})
+    this.props.onChange(value ? `${value}${val}` : '')
+  }
+
+  render () {
+    const { value, options, unit } = this.state
+
+    return (
+      <div className="style-input-wrap">
+        <Input value={value} addonAfter={
+          options.length > 1 ?
+          <Select value={unit} onChange={this.changeUnit}>
+            {options.map(item => <Option key={item} value={item}>{item}</Option>)}
+          </Select> :
+          <div className="single-unit">{unit}</div>
+        } onChange={this.changeValue}/>
+      </div>
+    )
+  }
+}
+
+export default StyleInput
\ No newline at end of file
diff --git a/src/menu/components/share/styleInput/index.scss b/src/menu/components/share/styleInput/index.scss
new file mode 100644
index 0000000..b058a37
--- /dev/null
+++ b/src/menu/components/share/styleInput/index.scss
@@ -0,0 +1,11 @@
+.style-input-wrap {
+  line-height: 32px;
+  .ant-select {
+    width: 60px!important;
+  }
+  .single-unit {
+    width: 38px;
+    text-align: left;
+    color: rgba(255, 255, 255, 0.65);
+  }
+}
diff --git a/src/menu/datasource/verifycard/settingform/index.jsx b/src/menu/datasource/verifycard/settingform/index.jsx
index dc66b36..d7916a3 100644
--- a/src/menu/datasource/verifycard/settingform/index.jsx
+++ b/src/menu/datasource/verifycard/settingform/index.jsx
@@ -8,6 +8,8 @@
 import CodeMirror from '@/templates/zshare/codemirror'
 import './index.scss'
 
+const { TextArea } = Input
+
 class SettingForm extends Component {
   static propTpyes = {
     dict: PropTypes.object,       // 瀛楀吀椤�
@@ -249,7 +251,7 @@
                 })(<Input placeholder={''} autoComplete="off" />)}
               </Form.Item>
             </Col> : null}
-            {interType === 'outer' ? <Col span={8}>
+            {interType === 'outer' ? <Col className="outer-interface" span={24}>
               <Form.Item label="鎺ュ彛鍦板潃">
                 {getFieldDecorator('interface', {
                   initialValue: setting.interface || '',
@@ -259,7 +261,18 @@
                       message: this.props.dict['form.required.input'] + '鎺ュ彛鍦板潃!'
                     }
                   ]
-                })(<Input placeholder={''} autoComplete="off" />)}
+                })(<TextArea rows={2}/>)}
+              </Form.Item>
+            </Col> : null}
+            {interType === 'outer' ? <Col className="outer-interface" span={24}>
+              <Form.Item label={<Tooltip placement="topLeft" title="姝e紡绯荤粺鎺ュ彛鍦板潃锛屼负绌烘椂浣跨敤鎺ュ彛鍦板潃">
+                  <Icon type="question-circle" />
+                  姝e紡鍦板潃
+                </Tooltip>
+              }>
+                {getFieldDecorator('proInterface', {
+                  initialValue: setting.proInterface || ''
+                })(<TextArea rows={2}/>)}
               </Form.Item>
             </Col> : null}
             {interType === 'outer' ? <Col span={8}>
@@ -340,7 +353,7 @@
                 </Radio.Group>)}
               </Form.Item>
             </Col> : null}
-            {config.type !== 'navbar' ? <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'璇ョ粍浠跺鏋滃彈鍏朵粬缁勪欢鎺у埗锛岃閫夐」鐩稿簲鐨勭粍浠讹紝娌℃湁鏃堕�夆�滄棤鈥濄��'}>
                   <Icon type="question-circle" />
@@ -408,7 +421,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.type !== 'navbar' ? <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'浼樺厛浣跨敤鍚岀骇鐨勬悳绱㈡潯浠剁粍浠讹紝鍚岀骇鎼滅储涓嶅瓨鍦ㄦ椂锛屼緷娆″悜涓婇�夊彇锛屼笌褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵竴鍚岀敤浣滄暟鎹繃婊わ紙褰撳墠缁勪欢鐨勬悳绱㈡潯浠朵紭鍏堬級銆�'}>
                   <Icon type="question-circle" />
@@ -425,7 +438,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.type !== 'navbar' && useMSearch === 'true' ? <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' && useMSearch === 'true' ? <Col span={8}>
               <Form.Item label={
                 <Tooltip placement="topLeft" title={'澶栧眰鎼滅储鏉′欢鏀瑰彉鏃讹紝鏄惁鍒锋柊褰撳墠缁勪欢鏁版嵁銆�'}>
                   <Icon type="question-circle" />
@@ -442,7 +455,7 @@
                 )}
               </Form.Item>
             </Col> : null}
-            {config.type !== 'navbar' ? <Col span={8}>
+            {config.type !== 'navbar' && config.type !== 'balcony' ? <Col span={8}>
               <Form.Item label="鍒濆鍖栨暟鎹�">
                 {getFieldDecorator('onload', {
                   initialValue: setting.onload || 'true'
diff --git a/src/menu/datasource/verifycard/settingform/index.scss b/src/menu/datasource/verifycard/settingform/index.scss
index 5bd14b5..d0943f6 100644
--- a/src/menu/datasource/verifycard/settingform/index.scss
+++ b/src/menu/datasource/verifycard/settingform/index.scss
@@ -24,4 +24,12 @@
   .ant-radio-group {
     white-space: nowrap;
   }
+  .outer-interface {
+    .ant-form-item-label {
+      width: 10.5%;
+    }
+    .ant-form-item-control-wrapper {
+      width: 89.5%;
+    }
+  }
 }
\ No newline at end of file
diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx
index a482a9d..b12b583 100644
--- a/src/menu/menushell/card.jsx
+++ b/src/menu/menushell/card.jsx
@@ -12,6 +12,7 @@
 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 Balcony = asyncComponent(() => import('@/menu/components/card/balcony'))
 const NormalTree = asyncComponent(() => import('@/menu/components/tree/antd-tree'))
 const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
 const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
@@ -90,6 +91,8 @@
       return (<BraftEditor card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     } else if (card.type === 'code') {
       return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
+    } else if (card.type === 'balcony') {
+      return (<Balcony card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
     }
   }
   return (
diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx
index b1427ac..308e390 100644
--- a/src/menu/menushell/index.jsx
+++ b/src/menu/menushell/index.jsx
@@ -100,6 +100,7 @@
         dashboard: '浠〃鐩�',
         scatter: '鏁g偣鍥�',
         tree: '鏍戝舰鍒楄〃',
+        balcony: '娴姩鍗�',
         card: '鍗$墖'
       }
       let i = 1
diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx
index 99e6ef6..e9e1833 100644
--- a/src/menu/modulesource/option.jsx
+++ b/src/menu/modulesource/option.jsx
@@ -29,6 +29,7 @@
   { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '鏁版嵁鍗�', width: 24 },
   { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '灞炴�у崱', width: 24 },
+  { type: 'menu', url: card2, component: 'balcony', subtype: 'balcony', title: '鍙诞鍔ㄥ崱', width: 24 },
   { type: 'menu', url: form, component: 'form', subtype: 'stepform', title: '琛ㄥ崟', width: 24 },
   { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24, forbid: ['billPrint'] },
   { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24, forbid: ['billPrint'] },
diff --git a/src/menu/pastecontroller/index.jsx b/src/menu/pastecontroller/index.jsx
index 8283c68..7b3153c 100644
--- a/src/menu/pastecontroller/index.jsx
+++ b/src/menu/pastecontroller/index.jsx
@@ -66,7 +66,7 @@
         return cell
       })
     } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) {
-      item.subcards.forEach(card => {
+      item.subcards && item.subcards.forEach(card => {
         card.uuid = Utils.getuuid()
         if (card.elements) {
           if (sessionStorage.getItem('editMenuType') === 'popview') {
diff --git a/src/menu/popview/index.jsx b/src/menu/popview/index.jsx
index 0abb17e..a80ddd5 100644
--- a/src/menu/popview/index.jsx
+++ b/src/menu/popview/index.jsx
@@ -246,7 +246,7 @@
             buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`)
             _sort++
           })
-          item.subcards.forEach(card => {
+          item.subcards && item.subcards.forEach(card => {
             card.elements && card.elements.forEach(cell => {
               if (cell.eleType !== 'button') return
               this.checkBtn(cell)
diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx
index 01be5f2..e2180a4 100644
--- a/src/tabviews/custom/index.jsx
+++ b/src/tabviews/custom/index.jsx
@@ -570,7 +570,7 @@
       }
 
       if (item.type === 'card') {
-        item.subcards.forEach(card => {
+        item.subcards && item.subcards.forEach(card => {
           let _hasheight = card.style.height && card.style.height !== 'auto'
 
           if (card.style.shadow) { // 鍗$墖闃村奖
@@ -625,7 +625,7 @@
           })
         })
       } else if ((item.type === 'table' && item.subtype === 'tablecard') || item.type === 'carousel') {
-        item.subcards.forEach(card => {
+        item.subcards && item.subcards.forEach(card => {
           let _hasheight = card.style.height && card.style.height !== 'auto'
           card.elements = card.elements.filter(cell => {
             if (cell.eleType === 'button') {
diff --git a/src/utils/utils-custom.js b/src/utils/utils-custom.js
index 840ce6d..43a7b75 100644
--- a/src/utils/utils-custom.js
+++ b/src/utils/utils-custom.js
@@ -166,6 +166,80 @@
   }
 
   /**
+   * @description 鑾峰彇鍙叧鑱旀ā鍧�
+   */
+  static getLinkModules (components) {
+    let modules = components.map(item => {
+      if ((item.type === 'card' && item.subtype === 'datacard') || (item.type === 'table' && item.subtype === 'normaltable')) {
+        return {
+          value: item.uuid,
+          label: item.name
+        }
+      } else if (item.type === 'tabs') {
+        let _item = {
+          value: item.uuid,
+          label: item.name,
+          children: item.subtabs.map(f_tab => {
+            let subItem = {
+              value: f_tab.uuid,
+              label: f_tab.label,
+              children: this.getLinkModules(f_tab.components)
+            }
+
+            if (!subItem.children || subItem.children.length === 0) {
+              return {children: null}
+            }
+            return subItem
+          })
+        }
+
+        _item.children = _item.children.filter(t => t.children !== null)
+
+        if (_item.children.length === 0) {
+          return {children: null}
+        }
+
+        return _item
+      } else if (item.type === 'group') {
+        let _item = {
+          value: item.uuid,
+          label: item.name,
+          children: item.components.map(f_tab => {
+            if ((f_tab.type === 'card' && f_tab.subtype === 'datacard') || (f_tab.type === 'table' && f_tab.subtype === 'normaltable')) {
+              return {
+                value: f_tab.uuid,
+                label: f_tab.name
+              }
+            }
+            return {
+              children: null
+            }
+          })
+        }
+
+        _item.children = _item.children.filter(t => t.children !== null)
+
+        if (_item.children.length === 0) {
+          return {children: null}
+        }
+
+        return _item
+      } else {
+        return {
+          children: null
+        }
+      }
+    })
+
+    modules = modules.filter(mod => mod.children !== null)
+
+    if (modules.length === 0) {
+      return null
+    }
+    return modules
+  }
+
+  /**
    * @description 鑾峰彇鍒犻櫎鎸夐挳Id
    * @return {String}  name
    */
diff --git a/src/utils/utils-datamanage.js b/src/utils/utils-datamanage.js
index b995699..d878668 100644
--- a/src/utils/utils-datamanage.js
+++ b/src/utils/utils-datamanage.js
@@ -65,7 +65,7 @@
         if (setting.sysInterface === 'true' && window.GLOB.mainSystemApi) {
           param.rduri = window.GLOB.mainSystemApi
         } else if (setting.sysInterface !== 'true') {
-          param.rduri = setting.interface
+          param.rduri = window.GLOB.systemType === 'production' ? (setting.proInterface || setting.interface) : setting.interface
         }
       }
 

--
Gitblit v1.8.0