king
2023-03-11 d1d9dc29318cb2a9a466246adff7b78fe36cf623
Merge branch 'master' into positec
59个文件已修改
4个文件已添加
2070 ■■■■ 已修改文件
package-lock.json 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/paste/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/action.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.scss 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/index.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/editor/braft-editor/options.jsx 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/dragtitle/card.jsx 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/dragtitle/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.jsx 47 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/simple-form/options.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/index.jsx 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/step-form/options.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/tab-form/index.jsx 82 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/group/paste/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/actionform/index.jsx 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/actioncomponent/formconfig.jsx 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastebasetable/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/share/pastecomponent/index.jsx 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/tabs/paste/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/settingform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.jsx 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modalconfig/index.scss 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/modulecell/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/card.jsx 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/index.jsx 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/pastecomponent/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/modalconfig/source.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/pc/bgcontroller/index.jsx 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardItem/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/double-data-card/index.jsx 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-G6/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/editor/braft-editor/index.jsx 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/simple-form/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/step-form/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/form/tab-form/index.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/interfaces/interItem/index.jsx 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/popview/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/index.jsx 103 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss 117 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkVercode/index.jsx 220 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkVercode/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/comtableconfig/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/formtabconfig/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/dragelement/card.jsx 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/modalconfig/source.jsx 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/subtableconfig/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/editcomponent/index.jsx 132 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 66 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.scss 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/utils-custom.js 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/design/header/index.jsx 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/login/index.jsx 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/index.jsx 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/mobdesign/popview/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.jsx 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/pcdesign/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
package-lock.json
@@ -5415,9 +5415,9 @@
      }
    },
    "caniuse-lite": {
      "version": "1.0.30001399",
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001399.tgz",
      "integrity": "sha512-4vQ90tMKS+FkvuVWS5/QY1+d805ODxZiKFzsU8o/RsVJz49ZSRR8EjykLJbqhzdPgadbX6wB538wOzle3JniRA=="
      "version": "1.0.30001464",
      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001464.tgz",
      "integrity": "sha512-oww27MtUmusatpRpCGSOneQk2/l5czXANDSFvsc7VuOQ86s3ANhZetpwXNf1zY/zdfP63Xvjz325DAdAoES13g=="
    },
    "canvg": {
      "version": "3.0.10",
src/components/paste/index.jsx
@@ -17,10 +17,6 @@
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  pasteSubmit = () => {
    const { options } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -1,7 +1,7 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Popover, Button, Switch, Checkbox } from 'antd'
import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined, ProfileOutlined, WarningOutlined } from '@ant-design/icons'
import { EditOutlined, CopyOutlined, CloseOutlined, FontColorsOutlined, ProfileOutlined, WarningOutlined, PlusOutlined, MinusOutlined } from '@ant-design/icons'
import { resetStyle } from '@/utils/utils-custom.js'
import MkIcon from '@/components/mk-icon'
@@ -53,6 +53,8 @@
  if (card.OpenType === 'form') {
    if (card.formType === 'switch') {
      btnElement = (<Switch style={_style} className={card.size === 'large' ? 'ant-switch-large' : ''} size={card.size} checkedChildren={card.openText || ''} unCheckedChildren={card.closeText || ''}/>)
    } else if (card.formType === 'counter') {
      btnElement = (<div style={_style} className={'mk-counter ' + card.size}><span><MinusOutlined /></span><span>1</span><span><PlusOutlined /></span></div>)
    } else if (card.formType === 'radio') {
      btnElement = (<Checkbox style={_style}></Checkbox>)
    } else {
src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -142,6 +142,73 @@
    height: 26px;
  }
  .mk-counter {
    display: inline-block;
    white-space: nowrap;
    border: 1px solid #d9d9d9;
    font-size: 14px;
    border-radius: 2px;
    background: #ffffff;
    span {
      display: inline-block;
      height: 20px;
      line-height: 22px;
      vertical-align: top;
      text-align: center;
    }
    span:first-child {
      width: 22px;
      text-align: center;
      font-size: 12px;
      border-right: 1px solid #d9d9d9;
    }
    span:nth-child(2) {
      width: 42px;
    }
    span:last-child {
      width: 22px;
      text-align: center;
      font-size: 12px;
      border-left: 1px solid #d9d9d9;
    }
  }
  .mk-counter.small {
    font-size: 12px;
    span {
      height: 18px;
      line-height: 19px;
    }
    span:first-child {
      width: 20px;
      font-size: 10px;
    }
    span:nth-child(2) {
      width: 38px;
    }
    span:last-child {
      width: 20px;
      font-size: 10px;
    }
  }
  .mk-counter.large {
    font-size: 16px;
    span {
      height: 24px;
      line-height: 25px;
    }
    span:first-child {
      width: 26px;
      font-size: 13px;
    }
    span:nth-child(2) {
      width: 48px;
    }
    span:last-child {
      width: 26px;
      font-size: 13px;
    }
  }
  .card-cell > div {
    background-position: center center;
    background-repeat: no-repeat;
src/menu/components/editor/braft-editor/index.jsx
@@ -76,6 +76,10 @@
    }
  }
  componentDidMount() {
    MKEmitter.addListener('mkUpdateInter', this.mkUpdateInter)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
@@ -86,6 +90,21 @@
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkUpdateInter', this.mkUpdateInter)
  }
  mkUpdateInter = (inter, split) => {
    const { card } = this.state
    if (card.wrap.datatype === 'public' && card.wrap.publicId === inter.uuid) {
      let _card = {...card, columns: fromJS(inter.columns).toJS()}
      split.delay = split.delay + 10
      setTimeout(() => {
        this.updateComponent(_card)
      }, split.delay)
    }
  }
@@ -144,7 +163,21 @@
  }
  updateWrap = (res) => {
    this.updateComponent({...this.state.card, wrap: res})
    const { card } = this.state
    let _card = {...card, wrap: res}
    if (res.datatype === 'public') {
      let interfaces = window.GLOB.customMenu.interfaces || []
      let d = interfaces.filter(m => m.uuid === res.publicId && m.status === 'true')[0]
      if (d) {
        _card.columns = fromJS(d.columns).toJS()
      }
    }
    this.updateComponent(_card)
  }
  clickComponent = (e) => {
@@ -170,7 +203,7 @@
        <NormalHeader hideSearch="true" config={card} updateComponent={this.updateComponent}/>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <NormalForm title="富文本设置" width={700} update={this.updateWrap} getForms={this.getWrapForms}>
            <NormalForm title="富文本设置" width={750} update={this.updateWrap} getForms={this.getWrapForms}>
              <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <CopyComponent type="normaltable" card={card}/>
@@ -178,8 +211,7 @@
            <UserComponent config={card}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
            <EditorContent config={card} updateConfig={this.updateComponent}/>
            {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null}
            {card.wrap.datatype === 'static' ? <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null}
            {card.wrap.datatype === 'dynamic' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : <SettingOutlined style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/>}
          </div>
        } trigger="hover">
          <ToolOutlined />
src/menu/components/editor/braft-editor/options.jsx
@@ -4,6 +4,19 @@
export default function (wrap, columns) {
  let appType = sessionStorage.getItem('appType')
  let roleList = sessionStorage.getItem('sysRoles')
  let menu = window.GLOB.customMenu
  let interfaces = []
  if (menu.interfaces) {
    menu.interfaces.forEach(item => {
      if (item.status === 'true') {
        interfaces.push({
          value: item.uuid,
          label: item.name
        })
      }
    })
  }
  if (roleList) {
    try {
@@ -52,18 +65,29 @@
      options: [
        {value: 'dynamic', label: '动态'},
        {value: 'static', label: '静态'},
        {value: 'public', label: '公共数据源'},
      ],
      controlFields: [
        {field: 'field', values: ['dynamic']},
        {field: 'encryption', values: ['dynamic']},
        {field: 'field', values: ['dynamic', 'public']},
        {field: 'empty', values: ['dynamic', 'public']},
        {field: 'publicId', values: ['public']},
        {field: 'encryption', values: ['dynamic', 'public']},
      ]
    },
    {
      type: 'select',
      field: 'publicId',
      label: '数据源',
      initval: wrap.publicId || '',
      required: true,
      options: interfaces
    },
    {
      type: 'select',
      field: 'field',
      label: '文本字段',
      initval: wrap.field || '',
      tooltip: '选择动态值时,需设置文本字段才可生效。',
      tooltip: '选择动态值时,需设置文本字段才可生效,使用公共数据源时,需先保存数据源后再选取文本字段。',
      required: false,
      options: columns
    },
@@ -81,6 +105,19 @@
    },
    {
      type: 'radio',
      field: 'empty',
      label: '空值隐藏',
      initval: wrap.empty || 'show',
      tooltip: '当查询数据为空时,隐藏该组件。',
      required: false,
      skip: true,
      options: [
        {value: 'show', label: '否'},
        {value: 'hidden', label: '是'},
      ],
    },
    {
      type: 'radio',
      field: 'permission',
      label: '权限验证',
      initval: wrap.permission || 'false',
src/menu/components/form/dragtitle/card.jsx
@@ -9,9 +9,10 @@
import './index.scss'
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const Card = ({ id, card, sort, labelSize, active, moveCard, findCard, closeCard, selectCard, updateGroup }) => {
const Card = ({ id, card, sort, labelSize, active, moveCard, findCard, closeCard, selectCard, updateGroup, pasteForm }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'form', id, originalIndex },
@@ -79,6 +80,7 @@
          <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
        </NormalForm>
        <CopyComponent type="formgroup" card={card}/>
        <PasteComponent options={['form', 'forms']} updateConfig={(res) => pasteForm(res, id)} />
        <CloseOutlined className="close" type="close" onClick={close} />
      </div>
    } trigger="hover">
src/menu/components/form/dragtitle/index.jsx
@@ -4,7 +4,7 @@
import Card from './card'
import './index.scss'
const Container = ({list, labelSize, selectId, tabtype, handleList, handleGroup, closeGroup, selectGroup}) => {
const Container = ({list, labelSize, selectId, tabtype, handleList, handleGroup, handleForm, closeGroup, selectGroup}) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
@@ -33,6 +33,11 @@
    closeGroup(card)
  }
  const pasteForm = (res, id) => {
    const { card } = findCard(id)
    handleForm(card, res)
  }
  const selectCard = id => {
    const { card } = findCard(id)
    selectGroup(card)
@@ -51,6 +56,7 @@
          moveCard={moveCard}
          closeCard={closeCard}
          updateGroup={handleGroup}
          pasteForm={pasteForm}
          findCard={findCard}
          selectCard={selectCard}
        />
src/menu/components/form/simple-form/index.jsx
@@ -125,6 +125,7 @@
    card.width = card.wrap.width
    card.name = card.wrap.name
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -151,6 +152,9 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查关联主表“${m.label}”是否有效`})
          }
@@ -163,12 +167,17 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查关联主表“${m.label}”是否有效`})
          }
        })
      })
    }
    card.idCtrl = idCtrl
    this.setState({
      card: card
@@ -461,7 +470,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -506,7 +515,7 @@
    let _config = fromJS(this.state.card).toJS()
    if (res.subButton) {
      let _this = this
      let that = this
      _config.subcards[0].setting.focus = res.focus
      _config.subcards[0].setting.cache = res.cache
@@ -527,12 +536,38 @@
      })
      confirm({
        content: `替换表单及按钮配置?`,
        content: '替换表单及按钮配置?',
        onOk() {
          _this.updateComponent(_config)
          that.updateComponent(_config)
        },
        onCancel() {}
      })
      return
    } else if (res.fields) {
      if (_config.subcards[0].fields.length > 0) {
        let that = this
        _config.subcards[0].fields = res.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        confirm({
          title: '确定替换表单吗?',
          content: '原表单将删除。',
          onOk() {
            that.updateComponent(_config)
          },
          onCancel() {}
        })
      } else {
        _config.subcards[0].fields = res.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        this.updateComponent(_config)
      }
      return
    }
@@ -636,7 +671,7 @@
              <EditOutlined style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <CopyComponent type="simpleform" card={card}/>
            <PasteComponent config={card} options={['form', 'formgroup']} updateConfig={this.pasteForm} />
            <PasteComponent config={card} options={['form', 'forms', 'formgroup']} updateConfig={this.pasteForm} />
            <FontColorsOutlined className="style" title="调整样式" onClick={this.changeStyle}/>
            <UserComponent config={card}/>
            <DeleteOutlined className="close" title="删除组件" onClick={() => this.props.deletecomponent(card.uuid)} />
@@ -646,7 +681,7 @@
        } trigger="hover">
          <ToolOutlined />
        </Popover>
        <div className="form-area">
        <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={card.subcards[0]} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
src/menu/components/form/simple-form/index.scss
@@ -66,6 +66,17 @@
      background-color: transparent;
    }
  }
  // .form-area.mk-shadow {
  //   .mob-form {
  //     .am-list-line {
  //       border: none!important;
  //       .am-input-control {
  //         background-color: var(--mk-sys-color1);
  //       }
  //     }
  //   }
  // }
}
.menu-normal-form-edit-box::after {
  display: block;
src/menu/components/form/simple-form/options.jsx
@@ -159,6 +159,18 @@
    },
    {
      type: 'radio',
      field: 'formStyle',
      label: '表单样式',
      initval: wrap.formStyle || '',
      required: false,
      options: [
        {value: '', label: '默认'},
        {value: 'shadow', label: '阴影'},
      ],
      forbid: appType !== 'mob'
    },
    {
      type: 'radio',
      field: 'goback',
      label: '空值返回',
      initval: wrap.goback || 'false',
src/menu/components/form/step-form/index.jsx
@@ -132,6 +132,7 @@
    card.width = card.wrap.width
    card.name = card.wrap.name
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -158,6 +159,9 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
@@ -170,12 +174,17 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
        })
      })
    }
    card.idCtrl = idCtrl
    this.setState({
      card: card
@@ -563,7 +572,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -688,6 +697,98 @@
    this.updateComponent(_card)
  }
  clearGroup = () => {
    let group = fromJS(this.state.group).toJS()
    let card = fromJS(this.state.card).toJS()
    let _this = this
    group.fields = []
    card.subcards = card.subcards.map(item => {
      if (item.uuid === group.uuid) {
        return group
      }
      return item
    })
    confirm({
      content: `确定清空表单吗?`,
      onOk() {
        _this.setState({group})
        _this.updateComponent(card)
      },
      onCancel() {}
    })
  }
  parseForm = (g, res) => {
    let _group = fromJS(g).toJS()
    let _confirm = false
    if (res.copyType === 'form') {
      let fieldrepet = false // 字段重复
      res.uuid = Utils.getuuid()
      _group.fields.forEach(item => {
        if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      _group.fields.push(res)
    } else {
      if (_group.fields.length > 0) {
        _confirm = true
      }
      _group.fields = res.fields.map(item => {
        item.uuid = Utils.getuuid()
        return item
      })
    }
    if (_confirm) {
      let that = this
      confirm({
        title: '确定替换表单吗?',
        content: '原表单将删除。',
        onOk() {
          that.updateForms(_group)
        },
        onCancel() {}
      })
    } else {
      this.updateForms(_group)
    }
  }
  updateForms = (_group) => {
    const { group } = this.state
    let card = fromJS(this.state.card).toJS()
    card.subcards = card.subcards.map(item => {
      if (item.uuid === _group.uuid) {
        return _group
      }
      return item
    })
    if (_group.uuid === group.uuid) {
      this.setState({group: _group})
      this.updateComponent(card)
    } else {
      this.updateComponent(card)
    }
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
@@ -734,12 +835,14 @@
          selectId={group ? group.uuid : ''}
          handleList={this.changecards}
          handleGroup={this.changeGroup}
          handleForm={this.parseForm}
          closeGroup={this.closeGroup}
          selectGroup={this.selectGroup}
        />
        {group ? <div className="form-area">
        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
          <Switch checkedChildren="开" unCheckedChildren="关" 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}
src/menu/components/form/step-form/options.jsx
@@ -124,6 +124,18 @@
    },
    {
      type: 'radio',
      field: 'formStyle',
      label: '表单样式',
      initval: wrap.formStyle || '',
      required: false,
      options: [
        {value: '', label: '默认'},
        {value: 'shadow', label: '阴影'},
      ],
      forbid: appType !== 'mob'
    },
    {
      type: 'radio',
      field: 'goback',
      label: '空值返回',
      initval: wrap.goback || 'false',
src/menu/components/form/tab-form/index.jsx
@@ -144,6 +144,7 @@
    card.width = card.wrap.width
    card.name = card.wrap.name
    card.errors = []
    let idCtrl = false
    if (card.wrap.datatype !== 'static') {
      let supModule = card.setting.supModule ? card.setting.supModule[card.setting.supModule.length - 1] || '' : ''
@@ -170,6 +171,9 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
@@ -182,12 +186,17 @@
      card.subcards.forEach(item => {
        item.fields.forEach(m => {
          if (m.dataSource && /@ID@/ig.test(m.dataSource)) {
            idCtrl = true
          }
          if (m.type === 'linkMain' && !supModule) {
            card.errors.push({ level: 1, detail: `请检查分组“${item.setting.title}”中关联主表“${m.label}”是否有效`})
          }
        })
      })
    }
    card.idCtrl = idCtrl
    this.setState({
      card: card
@@ -568,7 +577,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -713,6 +722,74 @@
    })
  }
  parseForm = (g, res) => {
    let _group = fromJS(g).toJS()
    let _confirm = false
    if (res.copyType === 'form') {
      let fieldrepet = false // 字段重复
      res.uuid = Utils.getuuid()
      _group.fields.forEach(item => {
        if (res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) {
          fieldrepet = true
        }
      })
      if (fieldrepet) {
        notification.warning({
          top: 92,
          message: '字段已存在!',
          duration: 10
        })
        return
      }
      _group.fields.push(res)
    } else {
      if (_group.fields.length > 0) {
        _confirm = true
      }
      _group.fields = res.fields.map(item => {
        item.uuid = Utils.getuuid()
        return item
      })
    }
    if (_confirm) {
      let that = this
      confirm({
        title: '确定替换表单吗?',
        content: '原表单将删除。',
        onOk() {
          that.updateForms(_group)
        },
        onCancel() {}
      })
    } else {
      this.updateForms(_group)
    }
  }
  updateForms = (_group) => {
    const { group } = this.state
    let card = fromJS(this.state.card).toJS()
    card.subcards = card.subcards.map(item => {
      if (item.uuid === _group.uuid) {
        return _group
      }
      return item
    })
    if (_group.uuid === group.uuid) {
      this.setState({group: _group})
      this.updateComponent(card)
    } else {
      this.updateComponent(card)
    }
  }
  clickComponent = (e) => {
    if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') {
      e.stopPropagation()
@@ -760,10 +837,11 @@
          selectId={group ? group.uuid : ''}
          handleList={this.changecards}
          handleGroup={this.updateGroup}
          handleForm={this.parseForm}
          closeGroup={this.closeGroup}
          selectGroup={this.selectGroup}
        />
        {group ? <div className="form-area">
        {group ? <div className={`form-area mk-${card.wrap.formStyle || ''}`}>
          <PlusOutlined className="plus" title="添加表单" onClick={this.addForm}/>
          <FieldsComponent config={group} type="form" plusFields={this.plusFields} />
          <span style={{color: 'red', marginLeft: '30px', cursor: 'pointer'}} onClick={this.clearGroup}>清空</span>
src/menu/components/group/paste/index.jsx
@@ -18,10 +18,6 @@
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  pasteSubmit = () => {
    let appType = sessionStorage.getItem('appType')
    let options = ['datacard', 'propcard', 'balcony', 'timeline', 'simpleform', 'stepform', 'tabform', 'normaltable', 'tablecard', 'line', 'bar', 'pie', 'scatter', 'sandbox']
src/menu/components/share/actioncomponent/actionform/index.jsx
@@ -243,6 +243,8 @@
      if (this.record.formType === 'switch') {
        shows.push('field', 'size', 'openVal', 'closeVal', 'openText', 'closeText')
      } else if (this.record.formType === 'counter') {
        shows.push('field', 'size', 'min', 'max', 'decimal')
      } else if (this.record.formType === 'radio') {
        shows.push('field', 'checkType', 'openVal', 'closeVal')
      } else {
@@ -799,6 +801,7 @@
        content = <Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit} />
      } else if (item.type === 'number') {
        initVal = item.initVal || item.initVal === 0 ? item.initVal : ''
        rules = [
          { required: item.required, message: '请输入' + item.label + '!' }
        ]
src/menu/components/share/actioncomponent/formconfig.jsx
@@ -266,6 +266,9 @@
      }, {
        value: 'radio',
        text: '勾选框'
      }, {
        value: 'counter',
        text: '计数器'
      }, 
      ...formTypes]
    },
@@ -1026,7 +1029,7 @@
    {
      type: 'radio',
      key: 'size',
      label: '开关尺寸',
      label: '尺寸',
      initVal: card.size || 'default',
      options: [{
        value: 'large',
@@ -1061,6 +1064,27 @@
      required: false
    },
    {
      type: 'number',
      key: 'min',
      label: '最小值',
      initVal: card.min,
      required: false
    },
    {
      type: 'number',
      key: 'max',
      label: '最大值',
      initVal: card.max,
      required: false
    },
    {
      type: 'number',
      key: 'decimal',
      label: '小数位',
      initVal: card.decimal || 0,
      required: true
    },
    {
      type: 'text',
      key: 'closeVal',
      label: '关闭值',
src/menu/components/share/pastebasetable/index.jsx
@@ -19,10 +19,6 @@
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  pasteSubmit = () => {
    this.pasteFormRef.handleConfirm().then(res => {
      if (res.copyType !== 'basetable') {
src/menu/components/share/pastecomponent/index.jsx
@@ -21,10 +21,6 @@
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  resetconfig = (item, config) => {
    let _uuid = Utils.getuuid()
@@ -116,12 +112,17 @@
  pasteSubmit = () => {
    const { options } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
      if (!options.includes(res.copyType)) {
        notification.warning({ top: 92, message: '配置信息格式错误!', duration: 5 })
        return
      }
      if (!this.props.config) {
        this.props.updateConfig(res)
        this.setState({visible: false})
        return
      }
      let type = res.copyType
      let config = fromJS(this.props.config).toJS()
src/menu/components/tabs/paste/index.jsx
@@ -19,10 +19,6 @@
    visible: false
  }
  handleMenuClick = () => {
    this.setState({visible: true})
  }
  resetconfig = (item) => {
    if (item.type === 'tabs') {
      item.uuid = MenuUtils.getuuid()
src/menu/datasource/verifycard/settingform/index.jsx
@@ -409,7 +409,7 @@
                </Radio.Group>)}
              </Form.Item>
            </Col> : null}
            {!['navbar', 'balcony', 'menubar', 'interface'].includes(config.type) && (!config.wrap || config.wrap.supType !== 'multi') ? <Col span={8}>
            {!['navbar', 'balcony', 'menubar'].includes(config.type) && (!config.wrap || config.wrap.supType !== 'multi') ? <Col span={8}>
              <Form.Item label={
                <Tooltip placement="topLeft" title={'该组件如果受其他组件控制,请选项相应的组件,没有时选“无”。'}>
                  <QuestionCircleOutlined className="mk-form-tip" />
src/menu/modalconfig/index.jsx
@@ -4,8 +4,8 @@
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Card, Modal, Collapse, notification, Switch } from 'antd'
import { SettingOutlined } from '@ant-design/icons'
import { Button, Card, Modal, Collapse, notification, Switch, message } from 'antd'
import { SettingOutlined, CopyOutlined } from '@ant-design/icons'
import Api from '@/api'
import Utils from '@/utils/utils.js'
@@ -265,7 +265,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -456,8 +456,44 @@
    })
  }
  plusFields = (items) => {
  plusFields = (items, type) => {
    let _config = fromJS(this.state.config).toJS()
    if (type === 'forms') {
      if (_config.fields.length > 0) {
        let that = this
        _config.fields = items.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        confirm({
          title: '确定替换表单吗?',
          content: '原表单将删除。',
          onOk() {
            that.setState({
              config: _config
            })
          },
          onCancel() {}
        })
      } else {
        _config.fields = items.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        this.setState({
          config: _config
        })
        notification.success({
          top: 92,
          message: '粘贴成功!',
          duration: 2
        })
      }
      return
    }
    _config.fields.push(...items)
@@ -468,6 +504,39 @@
        this.handleForm(items[0])
      }
    })
  }
  triggerCopy = () => {
    const { config } = this.state
    let val = {
      copyType: 'forms',
      fields: config.fields || []
    }
    if (val.fields.length === 0) {
      message.warning('表单元素不可为空!')
      return
    }
    try {
      val = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
    } catch (e) {
      console.warn(e)
      message.warning('复制失败,请重试!')
      val = ''
    }
    if (val) {
      let oInput = document.createElement('input')
      oInput.value = val
      document.body.appendChild(oInput)
      oInput.select()
      document.execCommand('Copy')
      document.body.removeChild(oInput)
      message.success('复制成功。')
    }
  }
  render () {
@@ -493,7 +562,7 @@
            <Card title="表单配置" bordered={false} extra={
              <div>
                <Button type="danger" onClick={this.clearConfig}>清空</Button>
                <EditComponent options={['form']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
                <EditComponent options={['form', 'forms']} type="formboard" config={this.state.config} plusFields={this.plusFields}/>
                <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>保存</Button>
                <Button onClick={this.cancelConfig}>返回</Button>
              </div>
@@ -506,6 +575,7 @@
                  <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button>
                  <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button>
                  <CopyOutlined title="复制" onClick={this.triggerCopy} />
                  <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
                </div>
                <div className="ant-modal-body">
src/menu/modalconfig/index.scss
@@ -117,10 +117,17 @@
          z-index: 10;
          background: transparent;
          min-height: 50px;
          padding-right: 75px;
          padding-right: 80px;
          .ant-modal-title {
            display: inline-block;
          }
          .anticon-copy {
            position: absolute;
            top: 18px;
            color: #26C281;
            right: 65px;
            font-size: 16px;
          }
          .ant-switch {
            position: absolute;
            top: 15px;
src/menu/modulecell/index.jsx
@@ -67,7 +67,8 @@
          { subType: 'hint', text: '提示', type: 'form' },
          { subType: 'split', text: '分隔线', type: 'form' },
          { subType: 'linkMain', text: '关联主表', type: 'form' },
          { subType: 'formula', text: '公式', type: 'form' }
          { subType: 'formula', text: '公式', type: 'form' },
          { subType: 'vercode', text: '验证码', type: 'form' }
        ]
      },
      {
src/mob/components/formdragelement/card.jsx
@@ -212,6 +212,8 @@
        </div>
      </div>
    </div>)
  } else if (card.type === 'vercode') {
    formItem = <div className="am-list-item"><div className="am-list-line"><div className="am-input-label">{card.label}</div><div className="am-input-control"><span style={{color: '#bcbcbc'}}>{card.placeholder || ''}</span></div><div className="am-list-extra" style={{width: 'auto', height: 'auto', backgroundColor: '#fafafa', padding: '0 15px'}}>获取验证码</div></div></div>
  }
  let style = {...card.style}
src/mob/modalconfig/index.jsx
@@ -4,7 +4,7 @@
import { DndProvider } from 'react-dnd'
import HTML5Backend from 'react-dnd-html5-backend'
import moment from 'moment'
import { Button, Modal, Collapse, notification, Switch } from 'antd'
import { Button, Modal, Collapse, notification, Switch, message } from 'antd'
import { LeftOutlined } from '@ant-design/icons'
import Api from '@/api'
@@ -261,7 +261,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -409,12 +409,83 @@
    })
  }
  insert = (config) => {
  insert = (config, type) => {
    if (type === 'forms') {
      let _config = fromJS(this.state.config).toJS()
      if (_config.fields.length > 0) {
        let that = this
        _config.fields = config.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        confirm({
          title: '确定替换表单吗?',
          content: '原表单将删除。',
          onOk() {
            that.setState({
              config: _config
            })
          },
          onCancel() {}
        })
      } else {
        _config.fields = config.fields.map(item => {
          item.uuid = Utils.getuuid()
          return item
        })
        this.setState({
          config: _config
        })
        notification.success({
          top: 92,
          message: '粘贴成功!',
          duration: 2
        })
      }
      return
    }
    this.setState({
      config
    }, () => {
      this.handleForm(config.fields[config.fields.length - 1])
    })
  }
  triggerCopy = () => {
    const { config } = this.state
    let val = {
      copyType: 'forms',
      fields: config.fields || []
    }
    if (val.fields.length === 0) {
      message.warning('表单元素不可为空!')
      return
    }
    try {
      val = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
    } catch (e) {
      console.warn(e)
      message.warning('复制失败,请重试!')
      val = ''
    }
    if (val) {
      let oInput = document.createElement('input')
      oInput.value = val
      document.body.appendChild(oInput)
      oInput.select()
      document.execCommand('Copy')
      document.body.removeChild(oInput)
      message.success('复制成功。')
    }
  }
  clearConfig = () => {
@@ -453,6 +524,7 @@
            <Button icon="setting" onClick={this.changeSetting}>设置</Button>
            <Button type="primary" id="save-modal-config" loading={saving} onClick={this.submitConfig}>保存</Button>
            <Button onClick={this.cancelConfig}>返回</Button>
            <Button type="primary" style={{background: '#26C281', border: 'none'}} onClick={this.triggerCopy}>复制</Button>
            <PasteComponent config={config} updateConfig={this.insert} />
            <Button type="danger" onClick={this.clearConfig}>清空</Button>
            <Switch checkedChildren="开" unCheckedChildren="关" defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
src/mob/modalconfig/pastecomponent/index.jsx
@@ -20,7 +20,11 @@
  pasteSubmit = () => {
    const { config } = this.props
    this.pasteFormRef.handleConfirm().then(res => {
      if (res.copyType !== 'form') {
      if (res.copyType === 'forms') {
        this.props.updateConfig(res, 'forms')
        this.setState({visible: false})
        return
      } else if (res.copyType !== 'form') {
        notification.warning({ top: 92, message: '配置信息格式错误!', duration: 5 })
        return
      }
src/mob/modalconfig/source.jsx
@@ -109,6 +109,11 @@
    type: 'form',
    label: '公式',
    subType: 'formula',
  },
  {
    type: 'form',
    label: '验证码',
    subType: 'vercode',
  }
]
src/pc/bgcontroller/index.jsx
@@ -2,13 +2,14 @@
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Form, Select, Input } from 'antd'
import { ArrowUpOutlined, ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined } from '@ant-design/icons'
import { ArrowUpOutlined, ArrowDownOutlined, ArrowLeftOutlined, ArrowRightOutlined, BgColorsOutlined, ColumnWidthOutlined } from '@ant-design/icons'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
const StyleInput = asyncComponent(() => import('@/menu/stylecontroller/styleInput'))
const SysColorSketch = asyncComponent(() => import('@/menu/stylecontroller/syscolorsketch'))
const SourceComponent = asyncComponent(() => import('@/menu/components/share/sourcecomponent'))
const { Option } = Select
@@ -150,8 +151,52 @@
    }
  }
  /**
   * @description 修改阴影颜色 ,颜色控件
   */
  changeShadowColor = (val) => {
    let config = fromJS(this.props.config).toJS()
    config.style.shadowColor = val
    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
    this.props.updateConfig(config)
  }
  /**
   * @description 修改阴影颜色 ,颜色控件
   */
  changeShadowBlur = (val) => {
    let config = fromJS(this.props.config).toJS()
    config.style.shadowBlur = val
    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
    this.props.updateConfig(config)
  }
  /**
   * @description 修改阴影颜色 ,颜色控件
   */
  changeHShadow = (val) => {
    let config = fromJS(this.props.config).toJS()
    config.style.hShadow = val
    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
    this.props.updateConfig(config)
  }
  /**
   * @description 修改阴影颜色 ,颜色控件
   */
  changeVShadow = (val) => {
    let config = fromJS(this.props.config).toJS()
    config.style.vShadow = val
    config.style.boxShadow = `${config.style.hShadow || '0px'} ${config.style.vShadow || '0px'} ${config.style.shadowBlur || '0px'} ${config.style.shadowColor || 'transparent'}`
    this.props.updateConfig(config)
  }
  render () {
    const { config } = this.props
    const { config, type } = this.props
    const { backgroundColor, backgroundImage, backgroundSize, backgroundRepeat, backgroundPosition, background } = this.state
    const formItemLayout = {
      labelCol: {
@@ -174,8 +219,11 @@
          >
            <StyleInput defaultValue={config.style.width || '100%'} options={['px', '%', 'vw']} onChange={(val) => this.changePadding(val, 'width')}/>
          </Form.Item> */}
          <Form.Item className="color-control" colon={false} label="背景色">
          <Form.Item className="color-control" style={{marginBottom: '0px'}} colon={false} label="背景色">
            <ColorSketch value={backgroundColor} onChange={this.changeBackgroundColor} />
          </Form.Item>
          <Form.Item colon={false} label="系统色">
            <SysColorSketch onChange={this.changeBackgroundColor} />
          </Form.Item>
          {window.develop === true ? <Form.Item colon={false} label="颜色">
            <Input value={background} onChange={(e) => this.changeBackground(e.target.value)} />
@@ -209,6 +257,24 @@
              <Option value="bottom">bottom</Option>
            </Select>
          </Form.Item>
          {type === 'mob_popview' ? <p className="normal-view" style={{borderBottom: '1px solid #eaeaea', color: '#40a9ff'}}>阴影</p> : null}
          {type === 'mob_popview' ? <>
            <Form.Item colon={false} label={<BgColorsOutlined title="阴影颜色"/>}>
              <ColorSketch value={config.style.shadowColor || 'transparent'} onChange={this.changeShadowColor} />
            </Form.Item>
            <Form.Item colon={false} label={<BgColorsOutlined title="系统色"/>}>
              <SysColorSketch onChange={this.changeShadowColor} />
            </Form.Item>
            <Form.Item colon={false} label={<ColumnWidthOutlined title="模糊距离"/>}>
              <StyleInput defaultValue={config.style.shadowBlur || '0px'} options={['px']} onChange={this.changeShadowBlur}/>
            </Form.Item>
            <Form.Item colon={false} label={<ArrowRightOutlined title="水平位置"/>}>
              <StyleInput defaultValue={config.style.hShadow || '0px'} options={['px']} onChange={this.changeHShadow}/>
            </Form.Item>
            <Form.Item colon={false} label={<ArrowDownOutlined title="垂直位置"/>}>
              <StyleInput defaultValue={config.style.vShadow || '0px'} options={['px']} onChange={this.changeVShadow}/>
            </Form.Item>
          </> : null}
          <p className="normal-view" style={{borderBottom: '1px solid #eaeaea', color: '#40a9ff'}}>内边距</p>
          <Form.Item
            colon={false}
src/tabviews/custom/components/card/cardItem/index.jsx
@@ -51,7 +51,7 @@
      let menu = null
      
      if (card.menus && card.menus.length > 0) {
        let s = data[card.setting.menuType] || ''
        let s = data[card.setting.menuType] + ''
        card.menus.forEach(m => {
          if (s !== m.sign) return
          menu = m
src/tabviews/custom/components/card/double-data-card/index.jsx
@@ -282,7 +282,8 @@
  }
  checkTopLine = (id) => {
    const { config, data, selected } = this.state
    const { config, data, selected, card } = this.state
    let _opens = [...this.state.opens]
    if (!data || data.length === 0) {
      this.setState({
@@ -300,16 +301,26 @@
      let keys = []
      let items = []
      let last = ''
      if (card.setting.display === 'collapse') {
        _opens = []
      }
      data.forEach((item, i) => {
        if (!item.$disabled && item.selected === 'true') {
          items.push(item)
          keys.push(i)
          index = i
          last = item
          if (card.setting.display === 'collapse') {
            _opens.push(i)
          }
        }
      })
      this.setState({
        opens: _opens,
        activeKey: index,
        selectKeys: keys,
        selectedData: items
@@ -338,7 +349,12 @@
      return
    }
    if (card.setting.display === 'collapse') {
      _opens = [index]
    }
    this.setState({
      opens: _opens,
      activeKey: index,
      selectKeys: [index],
      selectedData: [data[index]]
src/tabviews/custom/components/chart/antv-G6/index.jsx
@@ -1494,7 +1494,7 @@
      let menu = null
      
      if (plot.menus && plot.menus.length > 0) {
        let s = data[plot.menuType] || ''
        let s = data[plot.menuType] + ''
        plot.menus.forEach(m => {
          if (s !== m.sign) return
          menu = m
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -1780,7 +1780,7 @@
        let menu = null
        
        if (plot.menus && plot.menus.length > 0) {
          let s = data[plot.menuType] || ''
          let s = data[plot.menuType] + ''
          plot.menus.forEach(m => {
            if (s !== m.sign) return
            menu = m
src/tabviews/custom/components/editor/braft-editor/index.jsx
@@ -31,7 +31,7 @@
    const { data, initdata } = this.props
    let _config = fromJS(this.props.config).toJS()
    let _data = {}
    let _data = { $$empty: true }
    let _sync = false
    let BID = ''
@@ -46,24 +46,22 @@
      BID = BData.$BID || ''
    }
    
    if (_config.setting && _config.wrap.datatype !== 'static') {
    if (_config.setting && _config.wrap.datatype === 'dynamic') {
      _sync = _config.setting.sync === 'true'
      if (_sync && data) {
        _data = data[_config.dataName] || {}
        _data = data[_config.dataName] || {$$empty: true}
        if (_data && Array.isArray(_data)) {
          _data = _data[0] || {}
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
      } else if (_sync && initdata) {
        _data = initdata || {}
        _data = initdata
        if (_data && Array.isArray(_data)) {
          _data = _data[0] || {}
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
      }
    } else {
      _data = {}
    }
    if (_config.wrap.minHeight) {
@@ -77,7 +75,7 @@
      config: _config,
      arr_field: _config.columns.map(col => col.field).join(','),
    }, () => {
      if (_config.wrap.datatype !== 'static' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') {
      if (_config.wrap.datatype === 'dynamic' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') {
        setTimeout(() => {
          this.loadData()
        }, _config.setting.delay || 0)
@@ -86,7 +84,14 @@
  }
  componentDidMount () {
    const { config } = this.state
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
    if (config.wrap.datatype === 'public') {
      MKEmitter.addListener('mkPublicData', this.mkPublicData)
    }
  }
  shouldComponentUpdate (nextProps, nextState) {
@@ -98,6 +103,8 @@
      return
    }
    MKEmitter.removeListener('reloadData', this.reloadData)
    MKEmitter.removeListener('mkPublicData', this.mkPublicData)
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
  }
  /**
@@ -107,17 +114,38 @@
    const { sync, config } = this.state
    if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) {
      let _data = {}
      let _data = {$$empty: true}
      if (nextProps.data && nextProps.data[config.dataName]) {
        _data = nextProps.data[config.dataName]
        if (_data && Array.isArray(_data)) {
          _data = _data[0]
          _data = _data[0] || {$$empty: true}
        }
      }
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
      this.setState({}, () => {
        this.loadData()
      })
    }
  }
  mkPublicData = (publicId, data) => {
    const { config } = this.state
    if (config.wrap.datatype === 'public' && config.wrap.publicId === publicId) {
      let _data = fromJS(data).toJS()
      this.setState({data: _data})
    }
  }
  resetParentParam = (MenuID, id) => {
    const { config } = this.state
    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
    if (id !== this.state.BID || id !== '') {
      this.setState({ BID: id }, () => {
        this.loadData()
      })
    }
@@ -135,15 +163,20 @@
    const { mainSearch } = this.props
    const { config, arr_field, BID } = this.state
    if (config.wrap.datatype === 'public') {
      MKEmitter.emit('reloadData', config.wrap.publicId)
      return
    }
    if (config.wrap.datatype === 'static') {
      this.setState({
        data: {},
        data: {$$empty: true},
        loading: false
      })
      return
    } else if (config.setting.supModule && !BID) { // BID 不存在时,不做查询
      this.setState({
        data: {},
        data: {$$empty: true},
        loading: false
      })
      return
@@ -165,7 +198,7 @@
    let result = await Api.genericInterface(param)
    if (result.status) {
      let _data = result.data && result.data[0] ? result.data[0] : {}
      let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
      this.setState({
        data: _data,
@@ -186,6 +219,8 @@
  render() {
    const { config, loading, data } = this.state
    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
    return (
      <div className="custom-braft-editor-box" id={'anchor' + config.uuid} style={config.style}>
        {loading ?
src/tabviews/custom/components/form/simple-form/index.jsx
@@ -63,6 +63,7 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        _data.$$uuid = _data[config.setting.primaryKey] || ''
      }
    } else {
      _data = {$$empty: true}
@@ -127,6 +128,8 @@
          _data = _data[0] || {$$empty: true}
        }
      }
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.setState({sync: false, data: _data})
    } else if (config.setting.useMSearch && nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) {
@@ -244,6 +247,8 @@
    if (result.status) {
      let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.setState({
        data: null,
        loading: false
@@ -289,6 +294,7 @@
    const { config, loading, BID, BData, data, group, dict } = this.state
    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
    if (config.idCtrl && (!data || data.$$empty)) return null
    
    return (
      <div className="custom-simple-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
src/tabviews/custom/components/form/step-form/index.jsx
@@ -62,6 +62,7 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        _data.$$uuid = _data[config.setting.primaryKey] || ''
      }
    } else {
      _data = {$$empty: true}
@@ -168,6 +169,8 @@
          _data = _data[0] || {$$empty: true}
        }
      }
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      if (config.wrap.statusControl && _data[config.wrap.statusControl]) {
        let _status = _data[config.wrap.statusControl]
@@ -304,6 +307,8 @@
      let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
      let _group = this.state.group
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      if (type === 'refresh') {
        _group = config.subcards[0]
      }
@@ -391,6 +396,7 @@
    const { config, loading, BID, BData, data, group, dict, step } = this.state
    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
    if (config.idCtrl && (!data || data.$$empty)) return null
    
    return (
      <div className="custom-normal-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
src/tabviews/custom/components/form/tab-form/index.jsx
@@ -61,6 +61,7 @@
          _data = _data[0] || {$$empty: true}
        }
        _sync = false
        _data.$$uuid = _data[config.setting.primaryKey] || ''
      }
    } else {
      _data = {$$empty: true}
@@ -142,6 +143,8 @@
          _data = _data[0] || {$$empty: true}
        }
      }
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.setState({sync: false, data: _data, group: null}, () => {
        this.setState({group: _group})
@@ -260,6 +263,8 @@
    if (result.status) {
      let _data = result.data && result.data[0] ? result.data[0] : {$$empty: true}
      _data.$$uuid = _data[config.setting.primaryKey] || ''
      this.setState({
        data: null,
        loading: false
@@ -307,6 +312,7 @@
    const { config, loading, BID, BData, data, group, dict } = this.state
    if (config.wrap.empty === 'hidden' && (!data || data.$$empty)) return null
    if (config.idCtrl && (!data || data.$$empty)) return null
    
    return (
      <div className="custom-tab-form-box" id={'anchor' + config.uuid} style={{...config.style}}>
src/tabviews/custom/components/interfaces/interItem/index.jsx
@@ -17,20 +17,34 @@
  loading = false
  
  state = {}
  state = {
    BID: ''
  }
  componentDidMount () {
    const { config } = this.props
    const { config, BID } = this.props
    if (config.setting.timer) {
      this.timer = new TimerTask()
      this.timer.init(config.uuid, config.setting.timer, config.setting.timerRepeats, () => {this.loadData()})
    }
    if (!config.setting.supModule) {
      this.setState({ BID: BID || '' })
    } else {
      let BData = window.GLOB.CacheData.get(config.setting.supModule)
      if (BData) {
        this.setState({ BID: BData.$BID || '' })
      }
    }
    setTimeout(() => {
      this.loadData()
    }, config.setting.delay)
    MKEmitter.addListener('reloadData', this.reloadData)
    MKEmitter.addListener('resetSelectLine', this.resetParentParam)
  }
  shouldComponentUpdate (nextProps, nextState) { return false }
@@ -44,6 +58,18 @@
    }
    this.timer && this.timer.stop()
    MKEmitter.removeListener('reloadData', this.reloadData)
    MKEmitter.removeListener('resetSelectLine', this.resetParentParam)
  }
  resetParentParam = (MenuID, id) => {
    const { config } = this.props
    if (!config.setting.supModule || config.setting.supModule !== MenuID) return
    if (id !== this.state.BID || id !== '') {
      this.setState({ BID: id }, () => {
        this.loadData()
      })
    }
  }
  reloadData = (publicId) => {
@@ -53,7 +79,15 @@
  }
  async loadData () {
    const { config, BID } = this.props
    const { config } = this.props
    const { BID } = this.state
    if (config.setting.supModule && !BID) {
      MKEmitter.emit('mkPublicData', config.uuid, { $$empty: true, $$uuid: '' })
      MKEmitter.emit('resetSelectLine', config.uuid, '', { $$empty: true, $$uuid: '' })
      this.loading = false
      return
    }
    if (this.loading) return
src/tabviews/custom/index.jsx
@@ -516,7 +516,7 @@
      if (item.wrap && item.wrap.supType === 'multi') { // 数据卡多上级组件
        mutil = true
        item.setting.supModule = item.supNodes[0].componentId
      } else if (item.setting && item.setting.supModule) {
      } else if (item.setting && item.setting.supModule && typeof(item.setting.supModule) !== 'string') {
        let pid = item.setting.supModule.pop()
        if (pid && pid !== 'empty') {
          item.setting.supModule = pid
@@ -999,6 +999,15 @@
      inter.setting.delay = delay
      delay += 15
      if (inter.setting.supModule) {
        let pid = inter.setting.supModule.pop()
        if (pid && pid !== 'empty') {
          inter.setting.supModule = pid
        } else {
          inter.setting.supModule = ''
        }
      }
      if (inter.setting.interType !== 'system') return inter
      let _customScript = ''
src/tabviews/custom/popview/index.jsx
@@ -363,7 +363,7 @@
      if (item.wrap && item.wrap.supType === 'multi') { // 数据卡多上级组件
        mutil = true
        item.setting.supModule = item.supNodes[0].componentId
      } else if (item.setting && item.setting.supModule) {
      } else if (item.setting && item.setting.supModule && typeof(item.setting.supModule) !== 'string') {
        let pid = item.setting.supModule.pop()
        if (pid && pid !== 'empty') {
          item.setting.supModule = pid
src/tabviews/zshare/actionList/normalbutton/index.jsx
@@ -13,6 +13,7 @@
import { updateForm } from '@/utils/utils-update.js'
import MKEmitter from '@/utils/events.js'
import MkIcon from '@/components/mk-icon'
import MkCounter from './mkcounter'
// import './index.scss'
const MutilForm = asyncSpinComponent(() => import('@/tabviews/zshare/mutilform'))
@@ -43,7 +44,8 @@
    disabled: false,
    hidden: false,
    autoMatic: false,
    check: false
    check: false,
    count: 0
  }
  moduleParams = null
@@ -59,7 +61,18 @@
    
    if (btn.OpenType === 'form') {
      let data = selectedData && selectedData[0] ? selectedData[0] : null
      this.setState({check: data && data[btn.field] === btn.openVal})
      if (btn.formType === 'counter') {
        let count = 0
        if (data && data[btn.field]) {
          count = +data[btn.field]
          if (isNaN(count)) {
            count = 0
          }
        }
        this.setState({count: count })
      } else {
        this.setState({check: data && data[btn.field] === btn.openVal})
      }
    } else if (btn.OpenType === 'formSubmit') {
      this.setState({
        selines: selectedData || []
@@ -95,7 +108,18 @@
    if (btn.OpenType === 'form') {
      let data = nextProps.selectedData && nextProps.selectedData[0] ? nextProps.selectedData[0] : null
      this.setState({check: data && data[btn.field] === btn.openVal})
      if (btn.formType === 'counter') {
        let count = 0
        if (data && data[btn.field]) {
          count = +data[btn.field]
          if (isNaN(count)) {
            count = 0
          }
        }
        this.setState({count: count })
      } else {
        this.setState({check: data && data[btn.field] === btn.openVal})
      }
    } else if (btn.OpenType === 'formSubmit') {
      this.setState({
        selines: nextProps.selectedData || []
@@ -352,29 +376,41 @@
        this.improveAction()
      })
    } else if (btn.OpenType === 'form') {
      this.setState({
        loading: true,
        check: !this.state.check
      }, () => {
        let type = 'text'
        let fieldlen = 50
        let value = this.state.check ? btn.openVal : btn.closeVal
        if (typeof(value) === 'number') {
          type = 'number'
          fieldlen = 0
        }
      if (btn.formType === 'counter') {
        let item = {
          type: type,
          type: 'number',
          readin: true,
          writein: true,
          fieldlen: fieldlen,
          fieldlen: btn.decimal || 0,
          key: btn.field,
          value: value
          value: this.state.count
        }
        this.execSubmit(data, () => { this.setState({loading: false})}, [item])
      })
        this.execSubmit(data, () => {}, [item])
      } else {
        this.setState({
          loading: true,
          check: !this.state.check
        }, () => {
          let type = 'text'
          let fieldlen = 50
          let value = this.state.check ? btn.openVal : btn.closeVal
          if (typeof(value) === 'number') {
            type = 'number'
            fieldlen = 0
          }
          let item = {
            type: type,
            readin: true,
            writein: true,
            fieldlen: fieldlen,
            key: btn.field,
            value: value
          }
          this.execSubmit(data, () => { this.setState({loading: false})}, [item])
        })
      }
    }
    if (window.GLOB.systemType === 'production') {
@@ -1944,11 +1980,13 @@
    }
    if ((res.ErrCode === 'S' || !res.ErrCode) || autoMatic) { // 执行成功
      notification.success({
        top: 92,
        message: res.message || '执行成功!',
        duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
      })
      if (btn.formType !== 'counter' || res.message) {
        notification.success({
          top: 92,
          message: res.message || '执行成功!',
          duration: btn.verify && btn.verify.stime ? btn.verify.stime : 2
        })
      }
    } else if (res.ErrCode === 'Y') { // 执行成功
      Modal.success({
        title: res.message || '执行成功!'
@@ -2382,7 +2420,7 @@
      MKEmitter.emit('popclose')
    } else if (btn.execError !== 'never') {
      MKEmitter.emit('refreshByButtonResult', btn.$menuId, btn.execError, btn, '', this.state.selines)
    } else if (btn.OpenType === 'form') {
    } else if (btn.OpenType === 'form' && btn.formType !== 'counter') {
      let data = this.props.selectedData && this.props.selectedData[0] ? this.props.selectedData[0] : null
      this.setState({check: data && data[btn.field] === btn.openVal})
    }
@@ -2760,15 +2798,22 @@
    }
  }
  changeCount = (count) => {
    this.setState({count}, () => {
      this.actionTrigger()
    })
  }
  render() {
    const { btn } = this.props
    const { loadingNumber, loadingTotal, loading, disabled, hidden, check } = this.state
    const { loadingNumber, loadingTotal, loading, disabled, hidden, check, count } = this.state
    if (hidden) return null
    if (btn.OpenType === 'form') {
      if (btn.formType === 'switch') { 
        return <Switch loading={loading} checked={check} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} onChange={(val,e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style} className={btn.size === 'large' ? 'ant-switch-large' : ''} size={btn.size} checkedChildren={btn.openText || ''} unCheckedChildren={btn.closeText || ''}/>
      } else if (btn.formType === 'counter') {
        return <MkCounter count={count} disabled={disabled} btn={btn} onChange={this.changeCount}/>
      } else if (btn.formType === 'radio') {
        return <Checkbox className={btn.checkType || ''} disabled={disabled || loading} title={disabled ? (btn.reason || '') : ''} checked={check} onChange={(e) => {e.stopPropagation();this.actionTrigger()}} style={btn.style}></Checkbox>
      } else {
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.jsx
New file
@@ -0,0 +1,116 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { message, InputNumber } from 'antd'
import { PlusOutlined, MinusOutlined } from '@ant-design/icons'
import './index.scss'
class MkCounter extends Component {
  static propTpyes = {
    count: PropTypes.number,
    btn: PropTypes.object,
    disabled: PropTypes.any,
    onChange: PropTypes.func
  }
  state = {
    count: 0,
    orival: 0
  }
  timer = null
  UNSAFE_componentWillMount() {
    this.setState({count: this.props.count, orival: this.props.count})
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    this.setState({count: nextProps.count, orival: nextProps.count})
  }
  minus = () => {
    const { btn } = this.props
    const { count } = this.state
    let val = count - 1
    if (btn.min !== '' && val < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      return
    } else if (btn.max !== '' && val > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      return
    }
    this.setState({count: val, orival: val})
    clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.props.onChange(val)
    }, 1000)
  }
  plus = () => {
    const { btn } = this.props
    const { count } = this.state
    let val = count + 1
    if (btn.min !== '' && val < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      return
    } else if (btn.max !== '' && val > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      return
    }
    this.setState({count: val, orival: val})
    clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.props.onChange(val)
    }, 1000)
  }
  submit = () => {
    const { btn } = this.props
    const { count, orival } = this.state
    if (count === '') {
      message.warning(`不可为空!`)
      this.setState({count: 0})
      return
    } else if (btn.min !== '' && count < btn.min) {
      message.warning(`不可小于${btn.min}!`)
      return
    } else if (btn.max !== '' && count > btn.max) {
      message.warning(`不可大于${btn.max}!`)
      return
    }
    if (orival === count) return
    clearTimeout(this.timer)
    this.timer = setTimeout(() => {
      this.props.onChange(count)
    }, 1000)
  }
  render() {
    const { btn, disabled } = this.props
    const { count } = this.state
    return (
      <div onClick={(e) => e.stopPropagation()} className={'mk-btn-counter ' + (btn.size || '') + (disabled ? ' mk-disabled' : '')} style={btn.style}>
        <span onClick={this.minus}><MinusOutlined /></span>
        <span><InputNumber value={count} onChange={(val) => this.setState({count: val})} onBlur={this.submit} onPressEnter={this.submit}/></span>
        <span onClick={this.plus}><PlusOutlined /></span>
      </div>
    )
  }
}
export default MkCounter
src/tabviews/zshare/actionList/normalbutton/mkcounter/index.scss
New file
@@ -0,0 +1,117 @@
.mk-btn-counter {
  position: relative;
  display: inline-block;
  white-space: nowrap;
  border: 1px solid #d9d9d9;
  font-size: 14px;
  border-radius: 2px;
  width: auto!important;
  max-width: auto!important;
  background: #ffffff;
  overflow: hidden;
  >span {
    display: inline-block;
    height: 20px;
    line-height: 22px;
    vertical-align: top;
    text-align: center;
  }
  >span:first-child {
    position: relative;
    width: 22px;
    text-align: center;
    font-size: 12px;
    cursor: pointer;
  }
  >span:first-child:after {
    content: ' ';
    display: inline-block;
    width: 1px;
    height: 26px;
    background-color: #d9d9d9;
    position: absolute;
    right: 0px;
  }
  >span:nth-child(2) {
    width: 42px;
    .ant-input-number {
      border: none;
      border-radius: 0;
      height: auto;
      box-shadow: none!important;
      .ant-input-number-handler-wrap {
        display: none;
      }
      .ant-input-number-input {
        padding: 0;
        height: auto;
        text-align: center;
      }
    }
  }
  >span:last-child {
    position: relative;
    width: 22px;
    text-align: center;
    font-size: 12px;
    cursor: pointer;
  }
  >span:last-child::before {
    content: ' ';
    display: inline-block;
    width: 1px;
    height: 26px;
    background-color: #d9d9d9;
    position: absolute;
    left: 0px;
  }
}
.mk-btn-counter.mk-disabled .ant-input-number-input {
  color: #bcbcbc !important;
}
.mk-btn-counter.mk-disabled::after {
  content: ' ';
  display: block;
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  bottom: 0;
}
.mk-btn-counter.small {
  font-size: 12px;
  >span {
    height: 18px;
    line-height: 19px;
  }
  >span:first-child {
    width: 20px;
    font-size: 10px;
  }
  >span:nth-child(2) {
    width: 38px;
  }
  >span:last-child {
    width: 20px;
    font-size: 10px;
  }
}
.mk-btn-counter.large {
  font-size: 16px;
  >span {
    height: 24px;
    line-height: 25px;
  }
  >span:first-child {
    width: 26px;
    font-size: 13px;
  }
  >span:nth-child(2) {
    width: 48px;
  }
  >span:last-child {
    width: 26px;
    font-size: 13px;
  }
}
src/tabviews/zshare/mutilform/index.jsx
@@ -27,6 +27,7 @@
const MKColor = asyncComponent(() => import('./mkColor'))
const MkFormula = asyncComponent(() => import('./mkFormula'))
const MkCascader = asyncComponent(() => import('./mkCascader'))
const MkVercode = asyncComponent(() => import('./mkVercode'))
const MKEditor = asyncComponent(() => import('@/components/editor'))
class MainSearch extends Component {
@@ -41,7 +42,10 @@
  state = {
    formlist: [],    // 表单项
    ID: ''
    ID: '',
    send_type: '',
    timestamp: '',
    n_id: ''
  }
  record = {}
@@ -100,6 +104,12 @@
        delete item.style.marginRight
      }
      if (item.type === 'split' && item.splitctrl) {
        if (data.hasOwnProperty(item.splitctrl.toLowerCase()) && data[item.splitctrl.toLowerCase()] === '') {
          return false
        }
      }
      if (item.type === 'split' || item.type === 'formula') return true
      if (item.type === 'hint') {
        if (item.field && data[item.field.toLowerCase()]) {
@@ -114,7 +124,7 @@
        item.precision = 'second'
      }
      if (!item.field || !['text', 'number', 'switch', 'rate', 'select', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color'].includes(item.type)) return false
      if (!item.field || !['text', 'number', 'switch', 'rate', 'select', 'link', 'cascader', 'linkMain', 'funcvar', 'date', 'datemonth', 'radio', 'checkbox', 'checkcard', 'fileupload', 'textarea', 'multiselect', 'brafteditor', 'color', 'vercode'].includes(item.type)) return false
      if (/^\s+$/.test(item.label)) {
        item.style = item.style || {}
@@ -161,6 +171,10 @@
          })
        }
        item.oriOptions = fromJS(item.options).toJS()
        if (item.empty === 'hidden' && item.oriOptions.length === 0) {
          item.hidden = true
        }
      }
      let newval = '$empty'
@@ -351,7 +365,7 @@
            message: formRule.input.formMessage.replace('@max', item.fieldlength)
          }
        ]
      } else if (item.type === 'linkMain') {
      } else if (item.type === 'linkMain' || item.type === 'vercode') {
        item.rules = [
          {
            required: item.required === 'true',
@@ -540,7 +554,7 @@
    let cache = action.setting.cache !== 'false'
    let debug = window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')
    let _sql = `Declare @mk_organization nvarchar(512)  select @mk_organization='${sessionStorage.getItem('organization') || ''}'\n`
    let _sql = `Declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)  select @mk_departmentcode='${sessionStorage.getItem('departmentcode') || ''}',@mk_organization='${sessionStorage.getItem('organization') || ''}',@mk_user_type='${sessionStorage.getItem('mk_user_type') || ''}'\n`
    let _sso = _sql
    deForms.forEach(item => {
@@ -662,7 +676,7 @@
  improveSimpleActionForm = (deForms) => {
    let cache = this.props.action.setting.cache !== 'false'
    let debug = window.GLOB.debugger === true || (window.debugger === true && options.sysType !== 'cloud')
    let _sql = `Declare @mk_organization nvarchar(512)  select @mk_organization='${sessionStorage.getItem('organization') || ''}'\n`
    let _sql = `Declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)  select @mk_departmentcode='${sessionStorage.getItem('departmentcode') || ''}',@mk_organization='${sessionStorage.getItem('organization') || ''}',@mk_user_type='${sessionStorage.getItem('mk_user_type') || ''}'\n`
    let deffers = deForms.map((form, index) => {
      let param = {
@@ -806,6 +820,10 @@
            })
          }
        }
        if (item.empty === 'hidden' && item.oriOptions.length > 0) {
          item.hidden = false
        }
      }
      
      return item
@@ -897,7 +915,6 @@
    formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.empty === 'hidden' && item.options.length === 0) return
      if (item.type === 'split') {
        fields.push(
@@ -957,6 +974,8 @@
          content = (<MKTextArea config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})}/>)
        } else if (item.type === 'rate') {
          content = (<Rate count={item.rateCount} disabled={item.readonly} style={{color: item.color || '#fadb14'}} onChange={(val) => this.recordChange({[item.field]: val})} character={item.character ? <MkIcon type={item.character}/> : <StarFilled />} allowHalf={item.allowHalf}/>)
        } else if (item.type === 'vercode') {
          content = (<MkVercode config={item} record={this.record} onSend={(send_type, timestamp, n_id) => this.setState({send_type, timestamp, n_id})} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit}/>)
        } else if (item.type === 'brafteditor') {
          content = (<MKEditor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
          label = item.hidelabel !== 'true' ? label : ''
@@ -988,7 +1007,7 @@
  }
  handleConfirm = () => {
    const { formlist } = this.state
    const { formlist, send_type, timestamp, n_id } = this.state
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
@@ -997,7 +1016,7 @@
          reject(err)
          return
        }
        let search = []
        let forms = []
        let record = {...this.record, ...values}
        formlist.forEach(item => {
@@ -1039,12 +1058,40 @@
            if (item.declareType === 'nvarchar(50)') {
              _item.type = 'text'
            }
          } else if (item.type === 'vercode') {
            _item.type = 'text'
            forms.push({
              type: 'text',
              readin: false,
              writein: false,
              fieldlen: 50,
              key: 'mk_timestamp',
              value: timestamp || ''
            })
            forms.push({
              type: 'text',
              readin: false,
              writein: false,
              fieldlen: 50,
              key: 'mk_send_type',
              value: send_type || ''
            })
            forms.push({
              type: 'text',
              readin: false,
              writein: false,
              fieldlen: 50,
              key: 'mk_n_id',
              value: n_id || ''
            })
          }
    
          search.push(_item)
          forms.push(_item)
        })
        resolve(search)
        resolve(forms)
      })
    })
  }
src/tabviews/zshare/mutilform/mkVercode/index.jsx
New file
@@ -0,0 +1,220 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { Input, Button, message } from 'antd'
import md5 from 'md5'
import moment from 'moment'
import Api from '@/api'
import MKEmitter from '@/utils/events.js'
// import './index.scss'
/**
 * @description 自定义文本输入
 */
class MkVercode extends Component {
  constructor(props) {
    super(props)
    this.state = {
      value: ''
    }
  }
  inputRef = React.createRef()
  timer = null
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  handleChange = (e) => {
    let val = e.target.value
    val = val.replace(/\n/g, '')
    this.props.onChange(val)
    this.setState({value: val})
    if (val.length === 6) {
      setTimeout(() => {
        this.handleInputSubmit()
      }, 50)
    }
  }
  handleInputSubmit = () => {
    const { config } = this.props
    if (config.enter === 'false') return
    if (config.enter === 'tab') {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
    } else {
      MKEmitter.emit('mkFC', 'focus', config.tabUuid)
      this.props.onSubmit()
    }
  }
  getvercode = () => {
    const { record, config } = this.props
    let _phone = record[config.phoneField] || ''
    if (!_phone) {
      message.warning('请输入手机号!')
      return
    } else if (!/^1[3456789]\d{9}$/.test(_phone)) {
      message.warning('手机号格式错误,请重填!')
      return
    }
    let timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
    let send_type = 'web_no'
    let n_id = (() => {
      let uuid = []
      let timestamp = new Date().getTime()
      let _options = '0123456789abcdefghigklmnopqrstuv'
      for (let i = 0; i < 19; i++) {
        uuid.push(_options.substr(Math.floor(Math.random() * 0x20), 1))
      }
      uuid = timestamp + uuid.join('')
      return uuid
    })()
    this.setState({
      verdisabled: true,
      delay: 60
    })
    this.timer = setTimeout(this.resetVerCodeDelay, 1000)
    if (config.sendType === 'sso') {
      send_type = 'web'
      n_id = ''
      let _param = {
        func: 'mes_sms_send_code_sso',
        send_type: send_type,
        mob: _phone,
        ID: config.smsId,
        LText: 'minke',
        timestamp: timestamp,
      }
      _param.secretkey = md5(`${_param.LText}mingke${_param.timestamp}`)
      Api.getSystemConfig(_param).then(res => {
        if (!res.status || !res.n_id) {
          clearTimeout(this.timer)
          this.setState({
            verdisabled: false,
            delay: null
          })
          message.warning(res.message || '验证码获取失败!')
          return
        }
        n_id = res.n_id
        let param = {
          func: 'MSN_sms_send_code',
          send_type: send_type,
          mob: _phone,
          timestamp: timestamp,
          ID: config.smsId,
          n_id: res.n_id
        }
        param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
        param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
        param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
        param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
        param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
        Api.genericInterface(param).then(res => {
          if (!res.status) {
            clearTimeout(this.timer)
            this.setState({
              verdisabled: false,
              delay: null
            })
            message.warning(res.message)
          } else {
            this.props.onSend(send_type, timestamp, n_id)
          }
        }, () => {
          clearTimeout(this.timer)
          this.setState({
            verdisabled: false,
            delay: null
          })
        })
      })
    } else {
      let param = {
        func: 'MSN_sms_send_code',
        send_type: send_type,
        mob: _phone,
        timestamp: timestamp,
        ID: config.smsId,
        n_id: n_id
      }
      param.LText = md5(`${_phone}mingke${window.GLOB.appkey}${param.timestamp}`)
      param.secretkey = md5(`${param.LText}mingke${param.timestamp}`)
      param.rduri = 'https://sso.mk9h.cn/webapi/dostars'
      param.userid = 'bh0bapabtd45epsgra79segbch6c1ibk'
      param.LoginUID = 'bh0bapabtd45epsgra79segbch6c1ibk'
      Api.genericInterface(param).then(res => {
        if (!res.status) {
          clearTimeout(this.timer)
          this.setState({
            verdisabled: false,
            delay: null
          })
          message.warning(res.message)
        } else {
          this.props.onSend(send_type, timestamp, n_id)
        }
      }, () => {
        clearTimeout(this.timer)
        this.setState({
          verdisabled: false,
          delay: null
        })
      })
    }
  }
  resetVerCodeDelay = () => {
    const { delay } = this.state
    if (delay && delay > 1) {
      this.setState({delay: delay - 1})
      this.timer = setTimeout(this.resetVerCodeDelay, 1000)
    } else {
      this.setState({
        verdisabled: false,
        delay: null
      })
    }
  }
  render() {
    const { config } = this.props
    const { value, verdisabled, delay } = this.state
    return <Input ref={this.inputRef} className="mk-form-input" allowClear placeholder={config.placeholder || ''} value={value} autoComplete="off" disabled={config.readonly} onChange={this.handleChange} onPressEnter={this.handleInputSubmit} addonAfter={
      <Button type="link" disabled={verdisabled} style={{padding: 0, minWidth: '70px'}} size="small" onClick={this.getvercode}>
        {delay ? `${delay}s` : '获取验证码'}
      </Button>
    }/>
  }
}
export default MkVercode
src/tabviews/zshare/mutilform/mkVercode/index.scss
src/templates/comtableconfig/index.jsx
@@ -58,7 +58,6 @@
    delActions: [],          // 删除按钮列表
    copyActions: [],         // 复制按钮组
    tabviews: [],            // 所有标签页
    thawButtons: [],         // 已选择要解冻的按钮
    activeKey: '0',          // 默认展开基本信息
    chartview: null,         // 当前视图
    openEdition: '',         // 编辑版本标记,防止多人操作
@@ -294,7 +293,7 @@
   */
  submitConfig = () => {
    const { menu } = this.props
    const { delActions, thawButtons, openEdition } = this.state
    const { delActions, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
@@ -538,26 +537,7 @@
      }).then(resp => {
        if (resp === false) return
        if (thawButtons.length > 0) {
          let defers = thawButtons.map(item => {
            return new Promise((resolve) => {
              Api.getSystemConfig({
                func: 'sPC_MainMenu_ReDel',
                MenuID: item
              }).then(res => {
                if (res.status) {
                  resolve('')
                } else {
                  resolve(res.message)
                }
              })
            })
          })
          return Promise.all(defers)
        } else {
          return true
        }
        return true
      }).then(res => {
        if (res === true || res === false) return res
@@ -570,9 +550,6 @@
          })
          return false
        } else {
          this.setState({
            thawButtons: []
          })
          return true
        }
      }).then(resp => {
@@ -1001,7 +978,6 @@
   */
  editConfig = (res) => {
    this.setState({
      thawButtons: res.thawButtons,
      config: res.config
    })
  }
@@ -1227,7 +1203,7 @@
                <Unattended config={config} updateConfig={this.updateconfig}/>
                <Versions MenuId={menu.MenuID} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} MenuID={this.props.menu.MenuID} thawButtons={this.state.thawButtons} refresh={this.editConfig}/>
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={this.state.config} refresh={this.editConfig}/>
                <UpdateTable config={config}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={this.state.config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
src/templates/formtabconfig/index.jsx
@@ -518,7 +518,7 @@
          let param = {
            func: 's_debug_sql',
            exec_type: 'y',
            LText: `declare @mk_organization nvarchar(512)
            LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
              ${res.dataSource}`
          }
src/templates/modalconfig/dragelement/card.jsx
@@ -135,6 +135,12 @@
    formItem = <div style={{marginTop: '8px', color: 'rgba(0, 0, 0, 0.85)', lineHeight: '1.5', ...card.style}}>{card.formula}{card.postfix || ''}</div>
  } else if (card.type === 'split') {
    formItem = <div className="split-line" style={card.style}>{card.label}</div>
  } else if (card.type === 'vercode') {
    formItem = <Input style={{marginTop: '4px'}} placeholder={card.placeholder || ''} value={card.initval} addonAfter={
      <Button type="link" style={{padding: 0}} size="small">
        获取验证码
      </Button>
    }/>
  } else if (card.type === 'checkcard') {
    className += ' checkcard'
    formItem = <CheckCard config={card} />
src/templates/modalconfig/index.jsx
@@ -399,7 +399,7 @@
        let param = {
          func: 's_debug_sql',
          exec_type: 'y',
          LText: `declare @mk_organization nvarchar(512)
          LText: `declare @mk_departmentcode nvarchar(512),@mk_organization nvarchar(512),@mk_user_type nvarchar(20)
            ${res.dataSource}`
        }
@@ -732,7 +732,6 @@
      onCancel() {}
    })
  }
  render () {
    const { editAction } = this.props
src/templates/modalconfig/source.jsx
@@ -179,6 +179,11 @@
    type: 'form',
    label: '公式',
    subType: 'formula',
  },
  {
    type: 'form',
    label: '验证码',
    subType: 'vercode',
  }
]
src/templates/subtableconfig/index.jsx
@@ -59,7 +59,6 @@
    delActions: [],          // 删除按钮列表
    copyActions: [],         // 复制按钮组
    tabviews: [],            // 所有标签页
    thawButtons: [],         // 已选择要解冻的按钮
    activeKey: '0',          // 默认展开基本信息
    chartview: null,         // 当前视图
    openEdition: '',         // 编辑版本标记,防止多人操作
@@ -285,7 +284,7 @@
   * @description 标签页保存
   */
  submitConfig = () => {
    const { delActions, thawButtons, openEdition } = this.state
    const { delActions, openEdition } = this.state
    let _config = fromJS(this.state.config).toJS()
    let copyreg = /\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2}$/ig
@@ -478,26 +477,7 @@
    }).then(resp => {
      if (resp === false) return
      if (thawButtons.length > 0) {
        let defers = thawButtons.map(item => {
          return new Promise((resolve) => {
            Api.getSystemConfig({
              func: 'sPC_MainMenu_ReDel',
              MenuID: item
            }).then(res => {
              if (res.status) {
                resolve('')
              } else {
                resolve(res.message)
              }
            })
          })
        })
        return Promise.all(defers)
      } else {
        return true
      }
      return true
    }).then(res => {
      if (res === true || res === false) return res
@@ -510,9 +490,6 @@
        })
        return false
      } else {
        this.setState({
          thawButtons: []
        })
        return true
      }
    }).then(resp => {
@@ -834,7 +811,6 @@
   */
  updateConfig = (res) => {
    this.setState({
      thawButtons: res.thawButtons,
      config: res.config
    })
  }
@@ -1023,7 +999,7 @@
              <div>
                <Versions MenuId={config.uuid} open_edition={openEdition} updateConfig={this.refreshConfig}/>
                <ReplaceField type="table" config={config} updateConfig={this.updateconfig}/>
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} MenuID={config.uuid} thawButtons={this.state.thawButtons} refresh={this.updateConfig}/>
                <EditComponent type="table" options={['search', 'form', 'action', 'columns']} config={config} refresh={this.updateConfig}/>
                <Switch className="big" checkedChildren="启" unCheckedChildren="停" checked={config.enabled} onChange={this.onEnabledChange} />
                <Button type="primary" id="save-config" onClick={this.submitConfig} loading={this.state.menuloading}>保存</Button>
                <Button onClick={this.cancelConfig}>返回</Button>
src/templates/zshare/editcomponent/index.jsx
@@ -1,117 +1,23 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Modal, Spin, notification, Button } from 'antd'
import { UnlockOutlined, SnippetsOutlined } from '@ant-design/icons'
import { Modal, notification, Button } from 'antd'
import { SnippetsOutlined } from '@ant-design/icons'
import Api from '@/api'
import Utils from '@/utils/utils.js'
import PasteForm from '@/templates/zshare/pasteform'
import TransferForm from '@/templates/zshare/basetransferform'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class editComponent extends Component {
  static propTpyes = {
    options: PropTypes.array,
    MenuID: PropTypes.any,
    config: PropTypes.object,
    thawButtons: PropTypes.any,
    refresh: PropTypes.func
  }
  state = {
    thawVisible: false,
    thawbtnlist: null,
    pasteVisible: false,
    targetKeys: []
  }
  /**
   * @description 解冻按钮
   */
  handleThaw = () => {
    const { MenuID } = this.props
    this.setState({
      thawVisible: true,
      targetKeys: []
    })
    Api.getSystemConfig({
      func: 'sPC_Get_FrozenMenu',
      ParentID: MenuID,
      TYPE: 40
    }).then(res => {
      if (res.status) {
        let _list = []
        res.data.forEach(menu => {
          let _conf = ''
          if (menu.ParentParam) {
            try {
              _conf = JSON.parse(window.decodeURIComponent(window.atob(menu.ParentParam)))
            } catch (e) {
              console.warn('Parse Failure')
              _conf = ''
            }
          }
          if (_conf) {
            _list.push({
              key: menu.MenuID,
              title: menu.MenuName,
              btnParam: _conf
            })
          }
        })
        this.setState({
          thawbtnlist: _list
        })
      } else {
        notification.warning({
          top: 92,
          message: res.message,
          duration: 5
        })
      }
    })
  }
  /**
   * @description 解冻按钮提交
   */
  thawBtnSubmit = () => {
    const { thawButtons } = this.props
    const { thawbtnlist, targetKeys } = this.state
    let config = fromJS(this.props.config).toJS()
    if (targetKeys.length === 0) {
      notification.warning({
        top: 92,
        message: '请选择解冻按钮',
        duration: 5
      })
    } else {
      thawbtnlist.forEach(item => {
        if (targetKeys.includes(item.key)) {
          config.action.push(item.btnParam)
        }
      })
      this.props.refresh({
        type: 'thaw',
        thawButtons: [...thawButtons, ...targetKeys],
        config: config
      })
      this.setState({
        thawVisible: false,
        targetKeys: []
      })
    }
    visible: false
  }
  pasteSubmit = () => {
@@ -176,6 +82,8 @@
        }
        
        this.props.plusFields([res])
      } else if (res.copyType === 'forms') {
        this.props.plusFields(res, 'forms')
      } else {
        notification.warning({
          top: 92,
@@ -185,45 +93,23 @@
        return
      }
      this.setState({
        pasteVisible: false
        visible: false
      })
    })
  }
  handleMenuClick = e => {
    if (e.key === 'thaw') {
      this.handleThaw()
    } else if (e.key === 'paste') {
      this.setState({pasteVisible: true})
    }
  }
  render() {
    const { MenuID } = this.props
    return (
      <div style={{display: 'inline-block'}}>
        {MenuID ? <Button className="mk-border-green" onClick={this.handleThaw}><UnlockOutlined /> 解冻按钮</Button> : null}
        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={() => this.setState({pasteVisible: true})}><SnippetsOutlined /> 粘贴</Button>
        {/* 解冻按钮模态框 */}
        <Modal
          title="解冻按钮"
          visible={this.state.thawVisible}
          onOk={this.thawBtnSubmit}
          onCancel={() => {this.setState({thawVisible: false, thawbtnlist: null, targetKeys: []})}}
          destroyOnClose
        >
          {!this.state.thawbtnlist && <Spin style={{marginLeft: 'calc(50% - 22px)', marginTop: '70px', marginBottom: '70px'}} size="large" />}
          {this.state.thawbtnlist && <TransferForm onChange={(vals) => this.setState({targetKeys: vals})} menulist={this.state.thawbtnlist}/>}
        </Modal>
        <Button style={{borderColor: '#40a9ff', color: '#40a9ff'}} onClick={() => this.setState({visible: true})}><SnippetsOutlined /> 粘贴</Button>
        {/* 按钮配置信息粘贴复制 */}
        <Modal
          title="粘贴"
          visible={this.state.pasteVisible}
          visible={this.state.visible}
          width={600}
          maskClosable={false}
          onOk={this.pasteSubmit}
          onCancel={() => {this.setState({pasteVisible: false})}}
          onCancel={() => {this.setState({visible: false})}}
          destroyOnClose
        >
          <PasteForm wrappedComponentRef={(inst) => this.pasteFormRef = inst} inputSubmit={this.pasteSubmit}/>
src/templates/zshare/formconfig.jsx
@@ -2408,6 +2408,23 @@
    roleList = []
  }
  let msgTemps = sessionStorage.getItem('msgTemplate')
  if (msgTemps) {
    try {
      msgTemps = JSON.parse(msgTemps)
      msgTemps = msgTemps.map(item => {
        item.value = item.ID
        item.label = item.SignName + ' - ' + item.TemplateCode
        return item
      })
    } catch (e) {
      msgTemps = []
    }
  } else {
    msgTemps = []
  }
  inputfields = inputfields.map((item, index) => {
    item.label = `${index + 1}、${item.field || ''}(${item.label})`
    return item
@@ -2498,6 +2515,9 @@
  }, {
    value: 'formula',
    text: '公式'
  }, {
    value: 'vercode',
    text: '验证码'
  }]
  let _fieldlength = 50
@@ -2560,6 +2580,9 @@
    }, {
      value: 'formula',
      text: '公式'
    }, {
      value: 'vercode',
      text: '验证码'
    }]
  }
@@ -3458,11 +3481,20 @@
      }]
    },
    {
      type: 'text',
      key: 'splitctrl',
      label: '控制字段',
      initVal: card.splitctrl || '',
      tooltip: '选行且行中对应字段值为空时隐藏。',
      required: false,
      options: columns
    },
    {
      type: 'radio',
      key: 'place',
      label: '排列',
      initVal: card.place || 'left_right',
      tooltip: '提示文字与输入框的位置关系。',
      tooltip: '提示文字与输入框的位置关系。注:选择器、日期表单在表单样式为阴影时有效',
      forbid: appType !== 'mob',
      options: [{
        value: 'left_right',
@@ -3632,6 +3664,38 @@
      }]
    },
    {
      type: 'radio',
      key: 'sendType',
      label: '发送方式',
      initVal: card.sendType || 'local',
      tooltip: '短信发送时是否通过单点系统。',
      required: false,
      options: [{
        value: 'local',
        text: '本地'
      }, {
        value: 'sso',
        text: '单点'
      }]
    },
    {
      type: 'select',
      key: 'phoneField',
      label: '手机号',
      initVal: card.phoneField || '',
      required: true,
      options: inputfields
    },
    {
      type: 'select',
      key: 'smsId',
      label: '短信模板',
      initVal: card.smsId || '',
      tooltip: '请选择适当的短信模板。',
      required: true,
      options: msgTemps
    },
    {
      type: 'number',
      key: 'span',
      min: 1,
src/templates/zshare/modalform/index.jsx
@@ -21,27 +21,28 @@
const modalTypeOptions = {
  text: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'regular', 'interception', 'span', 'labelwidth', 'encryption', 'tooltip', 'extra', 'enter', 'cursor', 'scan', 'splitline', 'placeholder', 'place', 'marginTop', 'marginBottom', 'lenControl', 'inputType'],
  number: ['initval', 'readonly', 'hidden', 'decimal', 'min', 'max', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'enter', 'cursor', 'splitline', 'place', 'marginTop', 'marginBottom'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom', 'empty'],
  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'arrange', 'marginTop', 'marginBottom', 'empty'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline', 'arrange', 'marginTop', 'marginBottom', 'empty'],
  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'splitline', 'marginTop', 'marginBottom', 'empty'],
  multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'dropdown', 'empty'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkField', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
  select: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
  checkbox: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
  radio: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'linkSubField', 'span', 'labelwidth', 'tooltip', 'extra', 'setAll', 'emptyText', 'splitline', 'arrange', 'marginTop', 'marginBottom'],
  checkcard: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'span', 'labelwidth', 'display', 'tooltip', 'extra', 'width', 'multiple', 'splitline', 'marginTop', 'marginBottom'],
  multiselect: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'dropdown'],
  link: ['initval', 'readonly', 'required', 'hidden', 'readin', 'resourceType', 'declare', 'setAll', 'linkField', 'linkSubField', 'span', 'place', 'labelwidth', 'tooltip', 'extra', 'emptyText', 'enter', 'splitline', 'dropdown', 'marginTop', 'marginBottom'],
  fileupload: ['readonly', 'required', 'readin', 'fieldlength', 'maxfile', 'fileType', 'span', 'labelwidth', 'tooltip', 'extra', 'compress', 'miniSet', 'splitline', 'marginTop', 'marginBottom', 'maxSize'],
  switch: ['initval', 'openVal', 'closeVal', 'openText', 'closeText', 'readonly', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom'],
  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'splitline', 'marginTop', 'marginBottom'],
  date: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'place', 'marginTop', 'marginBottom', 'minDate', 'maxDate', 'precision'],
  datemonth: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'splitline', 'place', 'marginTop', 'marginBottom'],
  datetime: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'extra', 'declareType', 'mode', 'splitline', 'marginTop', 'marginBottom', 'minDate', 'maxDate'],
  textarea: ['initval', 'readonly', 'required', 'hidden', 'readin', 'fieldlength', 'span', 'labelwidth', 'maxRows', 'encryption', 'interception', 'tooltip', 'extra', 'count', 'placeholder', 'marginTop', 'marginBottom'],
  cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'splitline', 'marginTop', 'marginBottom', 'separator', 'empty'],
  cascader: ['readonly', 'required', 'hidden', 'readin', 'resourceType', 'fieldlength', 'span', 'labelwidth', 'tooltip', 'extra', 'place', 'splitline', 'marginTop', 'marginBottom', 'separator'],
  color: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'tooltip', 'colorType', 'extra', 'marginTop', 'marginBottom'],
  rate: ['initval', 'readonly', 'required', 'hidden', 'readin', 'span', 'labelwidth', 'splitline', 'tooltip', 'extra', 'marginTop', 'marginBottom', 'allowHalf', 'color', 'rateCount', 'character', 'place'],
  hint: ['label', 'field', 'type', 'blacklist', 'message', 'span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
  split: ['label', 'type', 'marginTop', 'marginBottom', 'splitline'],
  split: ['label', 'type', 'marginTop', 'marginBottom', 'splitline', 'splitctrl'],
  formula: ['label', 'type', 'marginTop', 'marginBottom', 'splitline', 'span', 'labelwidth', 'formula', 'eval', 'postfix'],
  brafteditor: ['required', 'hidelabel', 'hidden', 'readin', 'fieldlength', 'readonly', 'span', 'labelwidth', 'tooltip', 'extra', 'encryption', 'marginTop', 'marginBottom'],
  funcvar: ['span', 'labelwidth', 'splitline', 'marginTop', 'marginBottom'],
  linkMain: ['readonly', 'required', 'hidden','declare', 'span', 'labelwidth', 'tooltip', 'interception', 'extra', 'marginTop', 'marginBottom']
  linkMain: ['readonly', 'required', 'hidden','declare', 'span', 'labelwidth', 'tooltip', 'interception', 'extra', 'place', 'marginTop', 'marginBottom'],
  vercode: ['label', 'field', 'type', 'blacklist', 'supField', 'readonly', 'required', 'hidden', 'span', 'labelwidth', 'tooltip', 'marginTop', 'marginBottom', 'placeholder', 'enter', 'smsId', 'phoneField', 'sendType']
}
class MainSearch extends Component {
@@ -120,7 +121,7 @@
    reRequired.field = true
    if (['hint', 'split', 'formula'].includes(type)) {
    if (['hint', 'split', 'formula', 'vercode'].includes(type)) {
      reRequired.field = false
      shows = fromJS(modalTypeOptions[type]).toJS()
    }
@@ -153,6 +154,10 @@
      }
      if (sessionStorage.getItem('appType') === 'mob') { // 移动端右侧扩展信息
        shows.push('placeholder')
      }
    } else if (type === 'vercode') {
      if (this.record.enter === 'tab' || this.record.enter === 'sub') {
        shows.push('tabField')
      }
    } else if (type === 'linkMain') {
      if (this.record.declare === 'nvarchar') {
@@ -263,6 +268,12 @@
      }
    }
    if (['multiselect', 'select', 'link', 'radio', 'checkbox', 'checkcard', 'cascader'].includes(type)) {
      if (this.record.hidden !== 'true') {
        shows.push('empty')
      }
    }
    if (type === 'cascader') {
      if (this.record.resourceType === '0') {        // 自定义资源
        shows.push('options', 'topmark', 'linkSubField')
src/templates/zshare/modalform/index.scss
@@ -47,4 +47,9 @@
    cursor: pointer;
    font-size: 14px;
  }
  >.ant-row >.ant-col {
    display: inline-block;
    vertical-align: top;
    float: none;
  }
}
src/utils/utils-custom.js
@@ -674,6 +674,14 @@
   * @description 按钮重置
   */
  static resetBtn (btn, commonId) {
    if (btn.OpenType === 'pop' || (btn.OpenType === 'funcbutton' && btn.execMode === 'pop')) {
      if (btn.modal && btn.modal.fields.length > 0) {
        btn.modal.fields = btn.modal.fields.map(m => {
          m.uuid = this.getuuid()
          return m
        })
      }
    }
    if (btn.switchTab && btn.switchTab.length > 0) {
      btn.switchTab = btn.switchTab.map(m => md5(commonId + m))
    }
@@ -750,6 +758,15 @@
          card.elements = card.elements.map(cell => {
            if (cell.eleType === 'button') {
              cell.uuid = md5(commonId + cell.uuid)
              if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
                if (cell.modal && cell.modal.fields.length > 0) {
                  cell.modal.fields = cell.modal.fields.map(m => {
                    m.uuid = this.getuuid()
                    return m
                  })
                }
              }
            } else {
              cell.uuid = this.getuuid()
            }
@@ -763,6 +780,14 @@
          card.backElements = card.backElements.map(cell => {
            if (cell.eleType === 'button') {
              cell.uuid = md5(commonId + cell.uuid)
              if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
                if (cell.modal && cell.modal.fields.length > 0) {
                  cell.modal.fields = cell.modal.fields.map(m => {
                    m.uuid = this.getuuid()
                    return m
                  })
                }
              }
            } else {
              cell.uuid = this.getuuid()
            }
@@ -781,6 +806,14 @@
        item.elements = item.elements.map(cell => {
          if (cell.eleType === 'button') {
            cell.uuid = md5(commonId + cell.uuid)
            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
              if (cell.modal && cell.modal.fields.length > 0) {
                cell.modal.fields = cell.modal.fields.map(m => {
                  m.uuid = this.getuuid()
                  return m
                })
              }
            }
          } else {
            cell.uuid = this.getuuid()
          }
@@ -822,6 +855,14 @@
          }
          col.elements = col.elements.map(cell => {
            cell.uuid = md5(commonId + cell.uuid)
            if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
              if (cell.modal && cell.modal.fields.length > 0) {
                cell.modal.fields = cell.modal.fields.map(m => {
                  m.uuid = this.getuuid()
                  return m
                })
              }
            }
            return cell
          })
@@ -858,6 +899,14 @@
      }
      item.action = item.action.map(cell => {
        cell.uuid = md5(commonId + cell.uuid)
        if (cell.OpenType === 'pop' || (cell.OpenType === 'funcbutton' && cell.execMode === 'pop')) {
          if (cell.modal && cell.modal.fields.length > 0) {
            cell.modal.fields = cell.modal.fields.map(m => {
              m.uuid = this.getuuid()
              return m
            })
          }
        }
        return cell
      })
src/views/design/header/index.jsx
@@ -335,6 +335,41 @@
      }
    })
  }
  getSmStemp = () => {
    if (!sessionStorage.getItem('msgTemplate')) {
      let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
        inner join (select openid from sapp where id='${window.GLOB.appkey}') b
        on a.openid=b.openid`
      _sql = Utils.formatOptions(_sql)
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: _sql,
        obj_name: 'data',
        arr_field: 'ID,TemplateCode,SignName'
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
      Api.getSystemConfig(param).then(res => {
        let msgs = []
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        } else if (res.data) {
          msgs = res.data
        }
        sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
      })
    }
  }
  
  UNSAFE_componentWillMount () {
    sessionStorage.setItem('isEditState', 'true')
@@ -390,7 +425,8 @@
      setTimeout(() => {
        this.setSystemFuncs()
      }, 200)
        this.getSmStemp()
      }, 500)
    }
  }
src/views/login/index.jsx
@@ -531,6 +531,13 @@
            authError: res.message
          })
        }
      }, () => {
        if (index === -1 || index > 10) {
          this.setState({
            auth: false,
            authError: '网络错误导致系统授权失败,请联系管理员。'
          })
        }
      })
    }
src/views/mobdesign/index.jsx
@@ -148,7 +148,6 @@
    MKEmitter.addListener('changeEditMenu', this.changeEditMenu)
    setTimeout(() => {
      this.getAppPictures()
      this.getSmStemp()
      this.getRoleFields()
      setGLOBFuncs()
    }, 1000)
@@ -337,41 +336,6 @@
      return false
    }
    return true
  }
  getSmStemp = () => {
    if (!sessionStorage.getItem('msgTemplate')) {
      let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
        inner join (select openid from sapp where id='${window.GLOB.appkey}') b
        on a.openid=b.openid`
      _sql = Utils.formatOptions(_sql)
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: _sql,
        obj_name: 'data',
        arr_field: 'ID,TemplateCode,SignName'
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
      Api.getSystemConfig(param).then(res => {
        let msgs = []
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        } else if (res.data) {
          msgs = res.data
        }
        sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
      })
    }
  }
  changeEditMenu = (menu) => {
@@ -2059,7 +2023,7 @@
                  <Panel header="元素" key="element">
                    <Modulecell />
                  </Panel>
                  <Panel header={'页面样式'} key="background">
                  <Panel header="页面样式" key="background">
                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                  </Panel>
                </Collapse>
src/views/mobdesign/popview/index.jsx
@@ -272,8 +272,8 @@
              <Panel header="元素" key="element">
                <Modulecell />
              </Panel>
              <Panel header={'页面样式'} key="background">
                <BgController config={config} updateConfig={this.updateConfig} />
              <Panel header="页面样式" key="background">
                <BgController config={config} type="mob_popview" updateConfig={this.updateConfig} />
              </Panel>
            </Collapse>
          </div>
src/views/pcdesign/index.jsx
@@ -133,7 +133,6 @@
    setTimeout(() => {
      this.getAppPictures()
      this.getSmStemp()
      this.getRoleFields()
      setGLOBFuncs()
    }, 1000)
@@ -313,83 +312,6 @@
        this.props.history.replace('/pcdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: MenuID || homeId, type: 'view'}))))
      }
    })
  }
  getSmStemp = () => {
    if (!sessionStorage.getItem('msgTemplate')) {
      let _sql = `select ID,TemplateCode,SignName+'_'+describe as SignName from (select * from bd_msn_sms_temp where deleted=0 and status=20 ) a
        inner join (select openid from sapp where id='${window.GLOB.appkey}') b
        on a.openid=b.openid`
      _sql = Utils.formatOptions(_sql)
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: _sql,
        obj_name: 'data',
        arr_field: 'ID,TemplateCode,SignName'
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
      Api.getSystemConfig(param).then(res => {
        let msgs = []
        if (!res.status) {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        } else if (res.data) {
          msgs = res.data
          sessionStorage.setItem('msgTemplate', JSON.stringify(msgs))
        }
      })
    }
    if (!sessionStorage.getItem('printTemps')) {
      let _sql = `select ID,Images,PrintTempNO+PrintTempName as PN from sPrintTemplate
      where appkey= @appkey@ and Deleted=0 and typechartwo='web_print'
      union select ID,Images,a.PrintTempNO+PrintTempName as PN
      from (select * from sPrintTemplate where appkey= '' and Deleted=0 and typechartwo='web_print') a
      left join (select PrintTempNO from sPrintTemplate where appkey= @appkey@ and Deleted=0 ) b
      on a.PrintTempNO=b.PrintTempNO
      left join (select Srcid from sPrintTemplate_Log where appkey='' and apicode= @appkey@ and Deleted=0 ) c
      on a.ID=c.Srcid where b.PrintTempNO is null and c.Srcid is null`
      let param = {
        func: 'sPC_Get_SelectedList',
        LText: Utils.formatOptions(_sql),
        obj_name: 'data',
        arr_field: 'PN,ID,Images'
      }
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
      param.secretkey = Utils.encrypt(param.LText, param.timestamp)
      param.open_key = Utils.encryptOpenKey(param.secretkey, param.timestamp) // 云端数据验证
      Api.getSystemConfig(param).then(res => {
        if (res.status) {
          let temps = res.data.map(temp => {
            return {
              value: temp.ID,
              text: temp.PN
            }
          })
          sessionStorage.setItem('printTemps', JSON.stringify(temps))
        } else {
          notification.warning({
            top: 92,
            message: res.message,
            duration: 5
          })
        }
      })
    }
  }
  getAppPictures = () => {
@@ -1729,7 +1651,7 @@
                  <Panel header="元素" key="element">
                    <Modulecell />
                  </Panel>
                  <Panel header={'页面样式'} key="background">
                  <Panel header="页面样式" key="background">
                    {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null}
                  </Panel>
                </Collapse>
src/views/pcdesign/index.scss
@@ -267,6 +267,9 @@
    background: rgba(0, 0, 0, 0);
  }
}
.mk-pc-view + .modal-form-board {
  padding-top: 0px;
}
body {
  overflow-y: hidden;