king
2021-08-01 55a1b8402fd258da084df9b8a3935eef8450247c
2021-08-01
35个文件已修改
4个文件已添加
1283 ■■■■■ 已修改文件
src/menu/components/form/dragtitle/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/dragtitle/index.scss 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/formconfig.jsx 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/formaction/index.scss 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/normal-form/groupform/index.jsx 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/normal-form/index.jsx 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/groupform/index.jsx 147 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/groupform/index.scss 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.jsx 744 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.scss 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/wrapsetting/settingform/index.jsx 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/group/groupcomponents/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastecomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/tabcomponents/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/menushell/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulesource/option.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/pastecontroller/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/styleInput/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/tabs/tabcomponents/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/topbar/normal-navbar/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/mobshell/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modulesource/option.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/searchconfig/searchdragelement/index.scss 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/menushell/card.jsx 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/modulesource/option.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/normal-form/index.scss 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/changeuserbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/excelInbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/exceloutbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/newpagebutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/popupbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/printbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/tabbutton/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/menudesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/dragtitle/index.jsx
@@ -4,7 +4,7 @@
import Card from './card'
import './index.scss'
const Container = ({list, selectId, handleList, handleGroup, closeGroup, selectGroup}) => {
const Container = ({list, selectId, tabtype, handleList, handleGroup, closeGroup, selectGroup}) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
@@ -44,7 +44,7 @@
  }
  return (
    <div className="normal-form-titles" >
    <div className={'normal-form-titles ' + (tabtype || '') } >
      {cards.map(card => (
        <Card
          id={card.uuid}
src/menu/components/form/dragtitle/index.scss
@@ -36,4 +36,54 @@
      background: #1890ff;
    }
  }
}
.normal-form-titles.mktab {
  font-size: 16px;
  line-height: 36px;
  min-height: 36px;
  margin-bottom: 16px;
  border-bottom: 1px solid #d9d9d9;
  .form-sort {
    display: none;
  }
  .page-card {
    margin-bottom: 0px;
    border-bottom: 2px solid transparent;
  }
  .page-card::before {
    display: none;
  }
  .page-card.active {
    border-bottom-color: #1890ff;
  }
}
.normal-form-titles.mkbtn {
  font-size: 16px;
  line-height: 36px;
  min-height: 36px;
  margin-bottom: 16px;
  .form-sort {
    display: none;
  }
  .page-card {
    margin-bottom: 0px;
    background: #ffffff;
    color: #1890ff;
    border: 1px solid #1890ff;
    border-radius: 0px;
  }
  .page-card:first-child {
    border-radius: 4px 0px 0px 4px;
  }
  .page-card:last-child {
    border-radius: 0px 4px 4px 0px;
  }
  .page-card::before {
    display: none;
  }
  .page-card.active {
    background: #1890ff;
    color: #ffffff;
  }
}
src/menu/components/form/formaction/formconfig.jsx
@@ -274,19 +274,19 @@
      required: false,
      options: modules
    },
    {
      type: 'radio',
      key: 'enable',
      label: '是否显示',
      initVal: card.enable || 'true',
      required: false,
      options: [{
        value: 'true',
        text: '显示'
      }, {
        value: 'false',
        text: '隐藏'
      }]
    },
    // {
    //   type: 'radio',
    //   key: 'enable',
    //   label: '是否显示',
    //   initVal: card.enable || 'true',
    //   required: false,
    //   options: [{
    //     value: 'true',
    //     text: '显示'
    //   }, {
    //     value: 'false',
    //     text: '隐藏'
    //   }]
    // }
  ]
}
src/menu/components/form/formaction/index.jsx
@@ -53,7 +53,7 @@
    const { group } = this.props
    let _style = element.style ? fromJS(element.style).toJS() : {}
    let options = ['font', 'border', 'padding', 'margin', 'backgroundColor']
    let options = ['font', 'border', 'padding', 'margin', 'backgroundColor', 'width']
    this.setState({
      card: element
@@ -195,13 +195,13 @@
    return (
      <div className="mk-form-action">
        {group.sort !== 1 ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
        {group.prevButton && group.prevButton.enable !== 'false' && group.sort !== 1 ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="edit" title="编辑" type="edit" onClick={() => this.handleAction(group.prevButton)} />
            <Icon className="style" title="调整样式" onClick={() => this.handleStyle(group.prevButton)} type="font-colors" />
          </div>
        } trigger="hover">
          <Button type="link" className={'prev ' + group.prevButton.enable} style={resetStyle(group.prevButton.style)}>{group.prevButton.label}</Button>
          <Button type="link" className="prev" style={resetStyle(group.prevButton.style)}>{group.prevButton.label}</Button>
        </Popover> : null}
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
@@ -212,13 +212,13 @@
        } trigger="hover">
          <Button type="link" className="submit mk-primary" onDoubleClick={this.changeMenu} style={resetStyle(group.subButton.style)}>{group.subButton.label}</Button>
        </Popover>
        {group.sort !== config.subcards.length ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
        {group.nextButton && group.nextButton.enable !== 'false' && group.sort !== config.subcards.length ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="edit" title="编辑" type="edit" onClick={() => this.handleAction(group.nextButton)} />
            <Icon className="style" title="调整样式" onClick={() => this.handleStyle(group.nextButton)} type="font-colors" />
          </div>
        } trigger="hover">
          <Button type="link" className={'skip ' + group.nextButton.enable} style={resetStyle(group.nextButton.style)}>{group.nextButton.label}</Button>
          <Button type="link" className="skip" style={resetStyle(group.nextButton.style)}>{group.nextButton.label}</Button>
        </Popover> : null}
        {/* 编辑按钮:复制、编辑 */}
        <Modal
src/menu/components/form/formaction/index.scss
@@ -4,24 +4,14 @@
  padding-bottom: 10px;
  .prev {
    margin-right: 15px;
  }
  .prev.false {
    span {
      text-decoration: line-through;
    }
    height: auto;
  }
  .submit {
    border: none;
    height: auto;
  }
  .skip {
    position: absolute;
    right: 5px;
  }
  .skip:not(.true) {
    span {
      text-decoration: line-through;
    }
    float: right;
    height: auto;
  }
}
src/menu/components/form/normal-form/groupform/index.jsx
@@ -144,6 +144,52 @@
              )}
            </Form.Item>
          </Col> : null}
          <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="第一组不显示。">
                <Icon type="question-circle" />
                上一步
              </Tooltip>
            }>
              {getFieldDecorator('prevEnable', {
                initialValue: group.prevButton.enable
              })(
                <Radio.Group>
                  <Radio value="true">显示</Radio>
                  <Radio value="false">隐藏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="提交">
              {getFieldDecorator('subEnable', {
                initialValue: group.subButton.enable
              })(
                <Radio.Group>
                  <Radio value="true">显示</Radio>
                  <Radio value="false">隐藏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label={
              <Tooltip placement="topLeft" title="最后一组不显示。">
                <Icon type="question-circle" />
                跳过
              </Tooltip>
            }>
              {getFieldDecorator('nextEnable', {
                initialValue: group.nextButton.enable
              })(
                <Radio.Group>
                  <Radio value="true">显示</Radio>
                  <Radio value="false">隐藏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
src/menu/components/form/normal-form/index.jsx
@@ -79,9 +79,9 @@
          sort: 1,
          style: {},
          fields: [],
          prevButton: {label: '上一步', type: 'prev', enable: 'true'},
          subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
          nextButton: {label: '跳过', type: 'next', enable: 'false'}
          prevButton: {label: '上一步', type: 'prev', enable: 'true', style: {marginRight: '15px', paddingTop: '5px', paddingBottom: '5px'}},
          subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
          nextButton: {label: '跳过', type: 'next', enable: 'false', style: {paddingTop: '5px', paddingBottom: '5px'}}
        }]
      }
@@ -211,9 +211,9 @@
      sort: card.subcards.length + 1,
      style: {},
      fields: [],
      prevButton: {label: '上一步', type: 'prev', enable: 'true'},
      subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px'}},
      nextButton: {label: '跳过', type: 'next', enable: 'false'}
      prevButton: {label: '上一步', type: 'prev', enable: 'true', style: {marginRight: '15px', paddingTop: '5px', paddingBottom: '5px'}},
      subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
      nextButton: {label: '跳过', type: 'next', enable: 'false', style: {paddingTop: '5px', paddingBottom: '5px'}}
    }
    card.subcards.push(newcard)
@@ -287,10 +287,19 @@
  }
  handleGroupSubmit = () => {
    const { group } = this.state
    let group = fromJS(this.state.group).toJS()
    this.groupRef.handleConfirm().then(res => {
      group.prevButton.enable = res.prevEnable
      group.subButton.enable = res.subEnable
      group.nextButton.enable = res.nextEnable
      delete res.prevEnable
      delete res.subEnable
      delete res.nextEnable
      group.setting = res
      this.setState({groupvisible: false})
      this.updateGroup(group)
    })
src/menu/components/form/tab-form/groupform/index.jsx
New file
@@ -0,0 +1,147 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { Form, Row, Col, Input, Radio, Select } from 'antd'
import { formRule } from '@/utils/option.js'
import './index.scss'
class SettingForm extends Component {
  static propTpyes = {
    dict: PropTypes.object,     // 字典项
    group: PropTypes.object,    // 表单配置信息
    inputSubmit: PropTypes.any  // 回车提交事件
  }
  state = {
    fields: null,
    appType: sessionStorage.getItem('appType')
  }
  UNSAFE_componentWillMount () {
    const { group } = this.props
    const { appType } = this.state
    let fields = []
    if (appType === 'mob') {
      group.fields.forEach(f => {
        if (f.field && ['text', 'number'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
          fields.push(f)
        }
      })
    } else {
      group.fields.forEach(f => {
        if (f.field && ['select', 'link', 'text', 'number'].includes(f.type) && f.hidden !== 'true' && f.readonly !== 'true') {
          fields.push(f)
        }
      })
    }
    this.setState({
      fields: fields
    })
  }
  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 { group, dict } = this.props
    const { getFieldDecorator } = this.props.form
    const { fields, appType } = this.state
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="ant-advanced-search-form modal-setting-form">
        <Row gutter={24}>
          <Col span={12}>
            <Form.Item label="标题">
              {getFieldDecorator('title', {
                initialValue: group.setting.title,
                rules: [
                  {
                    max: formRule.input.max,
                    message: formRule.input.message
                  }
                ]
              })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />)}
            </Form.Item>
          </Col>
          <Col span={12}>
            <Form.Item label="焦点">
              {getFieldDecorator('focus', {
                initialValue: group.setting.focus || ''
              })(
                <Select
                  showSearch
                  filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
                >
                  <Select.Option value="">
                    {dict['model.empty']}
                  </Select.Option>
                  {fields.map(option =>
                    <Select.Option id={option.uuid} title={option.label} key={option.uuid} value={option.field}>
                      {option.label}
                    </Select.Option>
                  )}
                </Select>
              )}
            </Form.Item>
          </Col>
          {appType !== 'mob' ? <Col span={12}>
            <Form.Item label="表单排列">
              {getFieldDecorator('align', {
                initialValue: group.setting.align || 'left_right'
              })(
                <Radio.Group>
                  <Radio value="left_right">左右</Radio>
                  <Radio value="up_down">上下</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col> : null}
          <Col span={12}>
            <Form.Item label="提交">
              {getFieldDecorator('subEnable', {
                initialValue: group.subButton.enable
              })(
                <Radio.Group>
                  <Radio value="true">显示</Radio>
                  <Radio value="false">隐藏</Radio>
                </Radio.Group>
              )}
            </Form.Item>
          </Col>
        </Row>
      </Form>
    )
  }
}
export default Form.create()(SettingForm)
src/menu/components/form/tab-form/groupform/index.scss
New file
@@ -0,0 +1,18 @@
.ant-advanced-search-form.modal-setting-form {
  .textarea {
    .ant-form-item-label {
      width: 16.3%;
    }
    .ant-form-item-control-wrapper {
      width: 83.33333333%;
    }
  }
  .ant-input-number {
    width: 100%;
  }
  .anticon-question-circle {
    color: #c49f47;
    position: relative;
    left: -3px;
  }
}
src/menu/components/form/tab-form/index.jsx
New file
@@ -0,0 +1,744 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Icon, Popover, Modal, Button, Switch, notification } from 'antd'
import moment from 'moment'
import Api from '@/api'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import { getModalForm } from '@/templates/zshare/formconfig'
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 ModalForm = asyncComponent(() => import('@/templates/zshare/modalform'))
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('@/menu/components/form/wrapsetting'))
const CardComponent = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
const FormTitle = asyncComponent(() => import('../dragtitle'))
const GroupForm = asyncComponent(() => import('./groupform'))
const FormAction = asyncComponent(() => import('../formaction'))
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 FieldsComponent = asyncComponent(() => import('@/templates/sharecomponent/fieldscomponent'))
const { confirm } = Modal
class PropCardEditComponent extends Component {
  static propTpyes = {
    card: PropTypes.object,
    deletecomponent: PropTypes.func,
    updateConfig: PropTypes.func,
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    appType: sessionStorage.getItem('appType'),
    card: null,
    back: false,
    group: null,
    showField: false,
    visible: false,
    editform: null,
    formlist: null,
    sqlVerifing: false,
    standardform: null
  }
  UNSAFE_componentWillMount () {
    const { card } = this.props
    if (card.isNew) {
      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: { },
        wrap: { name: card.name, width: card.width || 24, datatype: 'static', groupLabel: 'show', color: '#1890ff', tabtype: 'mktab' },
        style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' },
        columns: [],
        scripts: [],
        subcards: [{
          uuid: Utils.getuuid(),
          setting: {title: '第一步', align: 'left_right'},
          sort: 1,
          style: {},
          fields: [],
          subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
        }]
      }
      if (card.config) {
        let config = fromJS(card.config).toJS()
        _card.wrap = config.wrap
        _card.wrap.name = card.name
        _card.style = config.style
        _card.subcards = config.subcards.map(scard => {
          scard.uuid = Utils.getuuid()
          scard.fields = scard.fields.map(elem => {
            elem.uuid = Utils.getuuid()
            return elem
          })
          return scard
        })
      }
      this.setState({
        card: _card,
        group: _card.subcards[0] || null
      })
      this.props.updateConfig(_card)
    } else {
      let _card = fromJS(card).toJS()
      this.setState({
        card: _card,
        group: _card.subcards[0] || null
      })
    }
  }
  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)
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin', 'shadow'], 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: { title: `第${card.subcards.length + 1}步`, align: 'left_right' },
      sort: card.subcards.length + 1,
      style: {},
      fields: [],
      subButton: {label: '提交', type: 'submit', enable: 'true', style: {backgroundColor: '#1890ff', color: '#ffffff', paddingLeft: '25px', paddingRight: '25px', paddingTop: '5px', paddingBottom: '5px'}},
    }
    card.subcards.push(newcard)
    this.setState({
      card,
      group: newcard,
      groupvisible: true
    })
    this.props.updateConfig(card)
  }
  changecards = (list) => {
    let card = fromJS(this.state.card).toJS()
    card.subcards = list.map((item, index) => {
      item.sort = index + 1
      return item
    })
    this.setState({card})
    this.props.updateConfig(card)
  }
  selectGroup = (item) => {
    this.setState({
      group: item
    })
  }
  changeGroup = (item) => {
    this.setState({
      group: item,
      groupvisible: true
    })
  }
  closeGroup = (cell) => {
    const { group } = this.state
    let card = fromJS(this.state.card).toJS()
    const _this = this
    confirm({
      content: '确定删除分组吗?',
      onOk() {
        card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid)
        let _group = group
        if (group.uuid === cell.uuid) {
          _group = card.subcards[0] || null
        }
        _this.setState({card, group: _group})
        _this.props.updateConfig(card)
      },
      onCancel() {}
    })
  }
  updateGroup = (group) => {
    let card = fromJS(this.state.card).toJS()
    card.subcards = card.subcards.map(item => {
      if (item.uuid === group.uuid) {
        return group
      }
      return item
    })
    this.setState({card, group})
    this.props.updateConfig(card)
  }
  handleGroupSubmit = () => {
    let group = fromJS(this.state.group).toJS()
    this.groupRef.handleConfirm().then(res => {
      group.subButton.enable = res.subEnable
      delete res.subEnable
      group.setting = res
      this.setState({groupvisible: false})
      this.updateGroup(group)
    })
  }
  changecols = (type) => {
    let card = fromJS(this.state.card).toJS()
    let config = fromJS(this.state.group).toJS()
    let _this = this
    config.fields = config.fields.map(item => {
      item.labelwidth = 33.3
      item.span = 24
      if (['textarea','split','hint','checkcard','brafteditor'].includes(item.type)) {
        if (type === 2) {
          item.labelwidth = 16.3
        } else if (type === 3) {
          item.labelwidth = 10.5
        } else if (type === 4) {
          item.labelwidth = 8.3
        }
      } else if (type === 2) {
        item.span = 12
      } else if (type === 3) {
        item.span = 8
      } else if (type === 4) {
        item.span = 6
      }
      return item
    })
    confirm({
      content: `确定切换为${type}列吗?`,
      onOk() {
        card.subcards = card.subcards.map(item => {
          if (item.uuid === config.uuid) {
            return config
          }
          return item
        })
        _this.setState({group: config, card})
        _this.props.updateConfig(card)
      },
      onCancel() {}
    })
  }
  handleList = (list, newcard) => {
    let group = fromJS(this.state.group).toJS()
    let card = fromJS(this.state.card).toJS()
    group.fields = list
    card.subcards = card.subcards.map(item => {
      if (item.uuid === group.uuid) {
        return group
      }
      return item
    })
    this.setState({card, group}, () => {
      if (newcard) {
        this.handleForm(newcard)
      }
    })
    this.props.updateConfig(card)
  }
  closeForm = (cell) => {
    let group = fromJS(this.state.group).toJS()
    let card = fromJS(this.state.card).toJS()
    let _this = this
    group.fields = group.fields.filter(item => item.uuid !== cell.uuid)
    card.subcards = card.subcards.map(item => {
      if (item.uuid === group.uuid) {
        return group
      }
      return item
    })
    confirm({
      content: `确定删除<<${cell.label}>>吗?`,
      onOk() {
        _this.setState({card, group})
        _this.props.updateConfig(card)
      },
      onCancel() {}
    })
  }
  addForm = () => {
    const { appType } = this.state
    let group = fromJS(this.state.group).toJS()
    let lastItem = group.fields[group.fields.length - 1]
    let span = appType === 'mob' ? 24 : 12
    if (lastItem && lastItem.span) {
      span = lastItem.span
    }
    let newcard = {
      uuid: Utils.getuuid(),
      label: '',
      field: '',
      initval: '',
      type: 'text',
      resourceType: '0',
      setAll: 'false',
      span: span,
      labelwidth: 33.3,
      options: [],
      dataSource: '',
      decimal: 0,
      orderType: 'asc',
      readonly: 'false',
      required: 'true',
      focus: true
    }
    group.fields.push(newcard)
    this.setState({group}, () => {
      this.handleForm(newcard)
    })
  }
  editModalCancel = () => {
    let group = fromJS(this.state.group).toJS()
    group.fields = group.fields.filter(item => !item.focus)
    this.setState({group, visible: false, editform: null})
    this.updateGroup(group)
  }
  /**
   * @description 表单编辑
   */
  handleForm = (_item) => {
    const { card, group, appType } = this.state
    let _form = fromJS(_item).toJS()
    let _inputfields = []
    let _tabfields = []
    let _linkableFields = []
    let _linksupFields = [{
      value: '',
      text: '空'
    }]
    let standardform = null
    _inputfields = group.fields.filter(item => item.type === 'text' || item.type === 'number' || item.type === 'textarea' || item.type === 'color')
    if (appType === 'mob') {
      _tabfields = group.fields.filter(item => _form.field !== item.field && item.hidden !== 'true' && ['text', 'number'].includes(item.type))
    } else {
      _tabfields = group.fields.filter(item => _form.field !== item.field && item.hidden !== 'true' && ['text', 'number', 'select', 'link'].includes(item.type))
    }
    _tabfields.unshift({field: '', text: '原表单'})
    let uniq = new Map()
    uniq.set(_form.field, true)
    let index = null
    group.fields.forEach((item, i) => {
      if (_form.uuid === item.uuid) {
        index = i
      }
      if (!['select', 'link', 'radio', 'checkcard'].includes(item.type)) return
      if (item.field && !uniq.has(item.field)) {
        uniq.set(item.field, true)
        _linkableFields.push({
          value: item.field,
          text: item.label + ' (表单)'
        })
        _linksupFields.push({
          value: item.field,
          text: item.label
        })
      }
    })
    if (index !== null) {
      if (index === 0) {
        standardform = group.fields[index + 1] || null
      } else {
        standardform = group.fields[index - 1] || null
      }
    }
    card.columns.forEach(col => {
      if (col.field && !uniq.has(col.field)) {
        uniq.set(col.field, true)
        _linkableFields.push({
          value: col.field,
          text: col.label + ' (显示列)'
        })
      }
    })
    if (_form.linkSubField && _form.linkSubField.length > 0) {
      let fields = _inputfields.map(item => item.field)
      _form.linkSubField = _form.linkSubField.filter(item => fields.includes(item))
    }
    if (appType !== 'mob' && !_form.span && standardform && standardform.span) {
      _form.span = standardform.span
      _form.labelwidth = standardform.labelwidth
    }
    this.setState({
      standardform,
      visible: true,
      editform: _form,
      formlist: getModalForm(_form, _inputfields, _tabfields, _linkableFields, _linksupFields, false)
    })
  }
  /**
   * @description 编辑后提交
   * 1、获取编辑后的表单信息
   * 2、去除可能存在的示例表单
   * 3、通过loading刷新
   */
  handleSubmit = () => {
    this.formRef.handleConfirm().then(res => {
      let _config = fromJS(this.state.group).toJS()
      let fieldrepet = false // 字段重复
      let labelrepet = false // 提示文字重复
      _config.fields = _config.fields.map(item => {
        if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        } else if (res.label && item.uuid !== res.uuid && item.label === res.label) {
          labelrepet = true
        }
        if (item.uuid === res.uuid) {
          return res
        } else {
          return item
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      } else if (labelrepet) {
        notification.warning({
          top: 92,
          message: '名称已存在!',
          duration: 10
        })
        return
      }
      if (['select', 'multiselect', 'link', 'checkbox', 'radio', 'checkcard'].includes(res.type) && res.resourceType === '1' && /\s/.test(res.dataSource)) {
        this.setState({
          sqlVerifing: true
        })
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: res.dataSource
        }
        param.LText = param.LText.replace(/@\$|\$@/ig, '')
        param.LText = Utils.formatOptions(param.LText)
        param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
        param.secretkey = Utils.encrypt('', param.timestamp)
        if (window.GLOB.mainSystemApi && res.database === 'sso') {
          param.rduri = window.GLOB.mainSystemApi
        }
        Api.getLocalConfig(param).then(result => {
          if (result.status) {
            this.setState({
              sqlVerifing: false,
              editform: null,
              visible: false
            })
            this.updateGroup(_config)
          } else {
            this.setState({sqlVerifing: false})
            Modal.error({
              title: result.message
            })
          }
        })
      } else {
        this.setState({
          editform: null,
          visible: false
        })
        this.updateGroup(_config)
      }
    })
  }
  pasteForm = (res) => {
    let _config = fromJS(this.state.group).toJS()
    let fieldrepet = false // 字段重复
    let labelrepet = false // 提示文字重复
    _config.fields.forEach(item => {
      if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
        fieldrepet = true
      } else if (res.label && item.label === res.label) {
        labelrepet = true
      }
    })
    if (fieldrepet) {
      notification.warning({
        top: 92,
        message: '字段已存在!',
        duration: 10
      })
      return
    } else if (labelrepet) {
      notification.warning({
        top: 92,
        message: '名称已存在!',
        duration: 10
      })
      return
    }
    _config.fields.push(res)
    this.updateGroup(_config)
    this.handleForm(res)
    notification.success({
      top: 92,
      message: '粘贴成功!',
      duration: 2
    })
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
      MKEmitter.emit('clickComponent', this.state.card)
    }
  }
  render() {
    const { card, dict, group, appType } = this.state
    return (
      <div className="menu-normal-form-edit-box" style={resetStyle(card.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.addCard} type="plus" />
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <CopyComponent type="propcard" card={card}/>
            <PasteComponent config={card} options={['form']} updateConfig={this.pasteForm} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <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>
        <FormTitle
          list={card.subcards}
          tabtype={card.wrap.tabtype || ''}
          selectId={group ? group.uuid : ''}
          handleList={this.changecards}
          handleGroup={this.changeGroup}
          closeGroup={this.closeGroup}
          selectGroup={this.selectGroup}
        />
        {group ? <div className="form-area">
          <Icon className="plus" title="添加表单" onClick={this.addForm} type="plus" />
          <FieldsComponent config={group} type="form" updatefield={this.updateGroup} />
          <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button> : null}
          <div style={{clear: 'both'}}></div>
          {appType !== 'mob' ? <CardComponent
            list={group.fields}
            setting={group.setting}
            showField={this.state.showField}
            placeholder={dict['header.form.modal.placeholder']}
            handleList={this.handleList}
            handleForm={this.handleForm}
            closeForm={this.closeForm}
          /> : <MobCardComponent
            list={group.fields}
            setting={group.setting}
            showField={this.state.showField}
            handleList={this.handleList}
            handleForm={this.handleForm}
            closeForm={this.closeForm}
          />}
          <FormAction config={card} group={group} updateconfig={this.updateGroup}/>
        </div> : null}
        <Modal
          title="分组编辑"
          visible={this.state.groupvisible}
          width={850}
          maskClosable={false}
          onCancel={() => this.setState({groupvisible: false})}
          onOk={this.handleGroupSubmit}
          destroyOnClose
        >
          <GroupForm
            dict={dict}
            group={group}
            inputSubmit={this.handleGroupSubmit}
            wrappedComponentRef={(inst) => this.groupRef = inst}
          />
        </Modal>
        <Modal
          title={this.state.dict['model.edit']}
          visible={this.state.visible}
          width={850}
          onCancel={this.editModalCancel}
          onOk={this.handleSubmit}
          confirmLoading={this.state.sqlVerifing}
          destroyOnClose
        >
          <ModalForm
            dict={this.state.dict}
            card={this.state.editform}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            standardform={this.state.standardform}
            wrappedComponentRef={(inst) => this.formRef = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default PropCardEditComponent
src/menu/components/form/tab-form/index.scss
New file
@@ -0,0 +1,78 @@
.menu-normal-form-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);
  }
  .page-card {
    position: relative;
    background: #ffffff;
    border-radius: 2px;
    margin-bottom: 15px;
  }
  .form-area {
    position: relative;
    >.plus {
      color: #26C281;
      cursor: pointer;
      padding: 4px 10px;
    }
    >button {
      float: right;
      margin-right: 10px;
    }
    >.mk-cols-change {
      height: 24px;
      padding: 0 10px;
    }
    >.quickly-add {
      display: inline-block;
      margin-left: 10px;
      button {
        color: #1890ff;
        background: transparent;
        border: none;
        box-shadow: none;
        padding: 0;
        height: 24px;
      }
    }
    .modal-fields-row {
      padding-top: 10px;
      padding-bottom: 30px;
    }
  }
}
.menu-normal-form-edit-box::after {
  display: block;
  content: ' ';
  clear: both;
}
.menu-normal-form-edit-box:hover {
  z-index: 1;
  box-shadow: 0px 0px 4px #1890ff;
}
src/menu/components/form/wrapsetting/settingform/index.jsx
@@ -128,7 +128,7 @@
                )}
              </Form.Item>
            </Col>
            <Col span={12}>
            {config.subtype !== 'tabform' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="表单加载时的状态,当字段值与表单组的状态值一致时,启用对应的表单组。">
                  <Icon type="question-circle" />
@@ -146,7 +146,7 @@
                  </Select>
                )}
              </Form.Item>
            </Col>
            </Col> : null}
            <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="加载时是否显示分组名称。">
@@ -164,7 +164,19 @@
                )}
              </Form.Item>
            </Col>
            <Col span={12}>
            {config.subtype === 'tabform' ? <Col span={12}>
              <Form.Item label="分组风格">
                {getFieldDecorator('tabtype', {
                  initialValue: wrap.tabtype || 'mktab'
                })(
                  <Radio.Group>
                    <Radio value="mktab">tab页</Radio>
                    <Radio value="mkbtn">按钮组</Radio>
                  </Radio.Group>
                )}
              </Form.Item>
            </Col> : null}
            {config.subtype !== 'tabform' ? <Col span={12}>
              <Form.Item label={
                <Tooltip placement="topLeft" title="完成后的颜色">
                  <Icon type="question-circle" />
@@ -177,7 +189,7 @@
                  <ColorSketch />
                )}
              </Form.Item>
            </Col>
            </Col> : null}
            <Col span={12}>
              <Form.Item label="黑名单">
                {getFieldDecorator('blacklist', {
src/menu/components/group/groupcomponents/card.jsx
@@ -14,6 +14,7 @@
const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
const AntvScatter = asyncComponent(() => import('@/menu/components/chart/antv-scatter'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
const AntvDashboard = asyncComponent(() => import('@/menu/components/chart/antv-dashboard'))
const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card'))
const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
@@ -63,8 +64,10 @@
      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'scatter') {
      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm card={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') {
src/menu/components/share/pastecomponent/index.jsx
@@ -148,7 +148,7 @@
        MKEmitter.emit('copyButtons', copyBtns)
      }
      if (config.type === 'form' && config.subtype === 'stepform') {
      if (config.type === 'form') {
        this.props.updateConfig(res)
        this.setState({visible: false})
        return
src/menu/components/tabs/tabcomponents/card.jsx
@@ -17,6 +17,7 @@
const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
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'))
@@ -68,8 +69,10 @@
      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'scatter') {
      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm 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') {
src/menu/menushell/card.jsx
@@ -19,6 +19,7 @@
const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
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'))
@@ -69,8 +70,10 @@
      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'scatter') {
      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm 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') {
src/menu/modulesource/option.jsx
@@ -30,7 +30,8 @@
  { 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: form, component: 'form', subtype: 'stepform', title: '表单(分步)', width: 24 },
  { type: 'menu', url: form, component: 'form', subtype: 'tabform', title: '表单(tab页)', 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'] },
  { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '常用表', width: 24 },
src/menu/pastecontroller/index.jsx
@@ -153,6 +153,17 @@
        }
        return col
      })
    } else if (item.type === 'form') {
      item.subcards = item.subcards.map(cell => {
        cell.uuid = Utils.getuuid()
        cell.fields = cell.fields.map(m => {
          m.uuid = Utils.getuuid()
          return m
        })
        return cell
      })
    }
    if (item.btnlog) {
src/menu/stylecontroller/styleInput/index.jsx
@@ -106,7 +106,7 @@
    const { unit } = this.state
    let val = e.target.value
    if (/\d+\.$/.test(val)) {
    if (/\d+\.$|^-$/.test(val)) {
      this.setState({
        value: val
      })
src/mob/components/formdragelement/index.scss
@@ -10,7 +10,7 @@
  }
  .am-list-item {
    font-size: 16px;
    padding-left: 10px;
    // padding-left: 10px;
    position: relative;
    display: flex;
    height: 44px;
src/mob/components/tabs/tabcomponents/card.jsx
@@ -17,6 +17,7 @@
const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card'))
const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
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'))
@@ -69,8 +70,10 @@
      return (<NormalTree card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'scatter') {
      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm 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') {
src/mob/components/topbar/normal-navbar/index.jsx
@@ -36,7 +36,7 @@
        width: 24,
        subtype: card.subtype,
        wrap: { type: 'navbar', height: 50, title: 'NavBar', back: 'true', search: 'false', logout: 'false' },
        style: {borderBottomColor: '#bcbcbc', borderBottomWidth: '1px', paddingLeft: '10px', paddingRight: '10px', lineHeight: '2.8', fontSize: '18px' },
        style: {boxShadow: '0 0 3px #D9D9D9', shadowColor: '#D9D9D9', shadowBlur: '3px', paddingLeft: '10px', paddingRight: '10px', lineHeight: '2.8', fontSize: '18px' },
      }
      if (card.config) {
src/mob/mobshell/card.jsx
@@ -17,6 +17,7 @@
const TableCard = asyncComponent(() => import('@/menu/components/card/table-card'))
const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox'))
const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor'))
@@ -87,8 +88,10 @@
      return (<AntvDashboard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'scatter') {
      return (<AntvScatter card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm 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') {
src/mob/modulesource/option.jsx
@@ -34,7 +34,8 @@
  { 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: form, component: 'form', subtype: 'stepform', title: '表单(分步)', width: 24 },
  { type: 'menu', url: form, component: 'form', subtype: 'tabform', title: '表单(tab页)', width: 24 },
  { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '轮播-动态数据', width: 24 },
  { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '轮播-静态数据', width: 24 },
  { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '常用表', width: 24 },
src/mob/searchconfig/searchdragelement/index.scss
@@ -10,7 +10,7 @@
  }
  .am-list-item {
    font-size: 16px;
    padding-left: 10px;
    // padding-left: 10px;
    position: relative;
    display: flex;
    height: 44px;
src/pc/menushell/card.jsx
@@ -17,6 +17,7 @@
const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table'))
const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group'))
const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form'))
const TabForm = asyncComponent(() => import('@/menu/components/form/tab-form'))
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'))
@@ -79,8 +80,10 @@
      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 === 'form') {
    } else if (card.type === 'form' && card.subtype === 'stepform') {
      return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'form' && card.subtype === 'tabform') {
      return (<TabForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'search') {
      return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>)
    } else if (card.type === 'pie') {
src/pc/modulesource/option.jsx
@@ -33,7 +33,8 @@
  { 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: form, component: 'form', subtype: 'stepform', title: '表单(分步)', width: 24 },
  { type: 'menu', url: form, component: 'form', subtype: 'tabform', title: '表单(tab页)', width: 24 },
  { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '轮播-动态数据', width: 24 },
  { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '轮播-静态数据', width: 24 },
  { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '常用表', width: 24 },
src/tabviews/custom/components/form/normal-form/index.scss
@@ -65,17 +65,14 @@
    position: relative;
    text-align: center;
    padding-bottom: 10px;
    .prev {
      margin-right: 15px;
    }
    .submit {
      min-width: 70px;
      border: none;
    }
    .skip {
      position: absolute;
      right: 5px;
      float: right;
      height: auto;
    }
  }
  .mk-form-action.no-button {
src/tabviews/zshare/actionList/changeuserbutton/index.jsx
@@ -207,7 +207,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || ''
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/excelInbutton/index.jsx
@@ -467,7 +467,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || 'upload'
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/exceloutbutton/index.jsx
@@ -881,7 +881,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || 'download'
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/newpagebutton/index.jsx
@@ -213,7 +213,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || ''
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -1815,7 +1815,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || ''
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/popupbutton/index.jsx
@@ -207,7 +207,8 @@
      icon = ''
    } else if (show === 'icon') {
      icon = btn.icon || ''
    } else if (show === 'text') {
    // } else if (show === 'text') {
    } else {
      label = btn.label
    }
src/tabviews/zshare/actionList/printbutton/index.jsx
@@ -1349,7 +1349,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || ''
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/tabviews/zshare/actionList/tabbutton/index.jsx
@@ -205,7 +205,8 @@
        icon = ''
      } else if (show === 'icon') {
        icon = btn.icon || ''
      } else if (show === 'text') {
      // } else if (show === 'text') {
      } else {
        label = btn.label
      }
src/views/menudesign/index.jsx
@@ -856,7 +856,7 @@
          check(item.components)
          return
        }
        if (['propcard', 'brafteditor', 'sandbox', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['propcard', 'brafteditor', 'sandbox', 'stepform', 'tabform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
  
        if (item.setting) {
src/views/mobdesign/index.jsx
@@ -1122,7 +1122,7 @@
          error = `导航栏《${item.name}》未设置菜单参数!`
        }
        if (['propcard', 'brafteditor', 'sandbox', 'tabbar', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['propcard', 'brafteditor', 'sandbox', 'tabbar', 'stepform', 'tabform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
        if (item.setting) {
src/views/pcdesign/index.jsx
@@ -1375,7 +1375,7 @@
          check(item.components)
          return
        }
        if (['propcard', 'brafteditor', 'sandbox', 'stepform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['propcard', 'brafteditor', 'sandbox', 'stepform', 'tabform'].includes(item.subtype) && item.wrap.datatype === 'static') return
        if (['balcony'].includes(item.type) && item.wrap.datatype === 'static') return
        
        if (item.setting) {