king
2021-08-04 c5a378919ea922fd3216e70d9c5479edfe0d7178
2021-08-04
13个文件已修改
15个文件已添加
4个文件已删除
2043 ■■■■■ 已修改文件
src/components/normalform/index.jsx 88 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/index.scss 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.jsx 250 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/index.scss 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkInput/index.jsx 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkInput/index.scss 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkNumberInput/index.jsx 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkNumberInput/index.scss 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkRadio/index.jsx 94 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkRadio/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkSelect/index.jsx 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/mkSelect/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/styleInput/index.jsx 144 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/modalform/styleInput/index.scss 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/index.jsx 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/options.jsx 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/wrapsetting/index.jsx 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/wrapsetting/index.scss 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/wrapsetting/settingform/index.jsx 415 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/balcony/wrapsetting/settingform/index.scss 36 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/action.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.jsx 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.scss 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 170 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.scss 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkNumberInput/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/zshare/mutilform/mkSelect/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/verifycard/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/normalform/index.jsx
New file
@@ -0,0 +1,88 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Modal } from 'antd'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import ModalForm from './modalform'
import './index.scss'
class NormalFormComponent extends Component {
  static propTpyes = {
    width: PropTypes.any,
    check: PropTypes.any,
    title: PropTypes.string,
    getForms: PropTypes.func,
    update: PropTypes.func
  }
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    visible: false,
    formlist: []
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  trigger = () => {
    this.setState({
      visible: true,
      formlist: this.props.getForms()
    })
  }
  submit = () => {
    const { check } = this.props
    this.Ref.handleConfirm().then(res => {
      if (check) {
        this.props.update(res, () => {
          this.setState({
            visible: false,
            formlist: []
          })
        })
      } else {
        this.setState({
          visible: false,
          formlist: []
        })
        this.props.update(res)
      }
    })
  }
  render () {
    const { title, width, children } = this.props
    const { visible, dict, formlist } = this.state
    return (
      <div className="normal-form-wrap">
        <span onClick={this.trigger}>{children}</span>
        <Modal
          wrapClassName="popview-modal"
          title={title}
          visible={visible}
          width={width}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.submit}
          onCancel={() => { this.setState({ visible: false }) }}
          destroyOnClose
        >
          <ModalForm
            dict={dict}
            formlist={formlist}
            inputSubmit={this.submit}
            wrappedComponentRef={(inst) => this.Ref = inst}
          />
        </Modal>
      </div>
    )
  }
}
export default NormalFormComponent
src/components/normalform/index.scss
New file
@@ -0,0 +1,3 @@
.normal-form-wrap {
  display: inline-block;
}
src/components/normalform/modalform/index.jsx
New file
@@ -0,0 +1,250 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
// import { fromJS } from 'immutable'
import { Form, Row, Col, Tooltip, Icon, Cascader } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import MKEInput from './mkInput'
import MKNumberInput from './mkNumberInput'
import MKSelect from './mkSelect'
import './index.scss'
const MKRadio = asyncComponent(() => import('./mkRadio'))
const StyleInput = asyncComponent(() => import('./styleInput'))
const MKFileUpload = asyncComponent(() => import('@/tabviews/zshare/fileupload'))
const MKColor = asyncComponent(() => import('@/tabviews/zshare/mutilform/mkColor'))
class ModalForm extends Component {
  static propTpyes = {
    formlist: PropTypes.array,   // 表单列表
    inputSubmit: PropTypes.func  // input回车提交
  }
  state = {
    formlist: [],    // 表单项
  }
  record = {}
  componentDidMount () {
    let record = {}
    let controlFields = {}
    let fieldMap = new Map()
    let formlist = this.props.formlist.filter(item => {
      if (item.controlFields) { // 多层表单控制
        controlFields[item.field] = item.controlFields
      }
      item.hidden = false
      if (item.type === 'text') {
        let _rules = [{
          required: item.required,
          message: item.label + '不可为空!'
        }]
        item.rules = _rules
      } else if (item.type === 'number') {
        item.rules = [{
          required: item.required,
          message: item.label + '不可为空!'
        }, {
          validator: (rule, value, callback) => this.handleConfirmPassword(rule, value, callback, item)
        }]
      } else if (item.type === 'textarea') {
        let _rules = [
          {
            required: item.required,
            message: item.label + '不可为空!'
          }
        ]
        item.rules = _rules
      } else {
        item.rules = [
          {
            required: item.required,
            message: '请选择' + item.label + '!'
          }
        ]
      }
      record[item.field] = item.initval
      fieldMap.set(item.field, item)
      return true
    })
    Object.keys(controlFields).forEach(key => {
      if (!fieldMap.has(key)) return
      let supItem = fieldMap.get(key)
      let fields = []
      controlFields[key].forEach(item => {
        if (!fieldMap.has(item.field)) return
        let cell = fieldMap.get(item.field)
        if (cell.hidden) return
        if (supItem.hidden || !item.values.includes(supItem.initval)) {
          cell.hidden = true
          fieldMap.set(item.field, cell)
        }
        fields.push(item)
      })
      supItem.controlFields = fields
      fieldMap.set(key, supItem)
    })
    formlist = formlist.map(cell => {
      return fieldMap.get(cell.field) || cell
    })
    this.record = record
    this.setState({ formlist })
  }
  handleConfirmPassword = (rule, value, callback, item) => {
    let val = parseFloat(value)
    if (!isNaN(val)) {
      if (typeof(item.min) === 'number' && val < item.min) {
        callback(item.label + '最小值为 ' + item.min)
      } else if (typeof(item.max) === 'number' && val > item.max) {
        callback(item.label + '最大值为 ' + item.max)
      }
    }
    callback()
  }
  recordChange = (values, item) => {
    this.record = {...this.record, ...values}
    if (item && item.controlFields) {
      let map = new Map()
      this.state.formlist.forEach(cell => {
        if (!cell.field) return
        map.set(cell.field, cell)
      })
      let reset = (current) => {
        let val = this.record[current.field]
        current.controlFields.forEach(cell => {
          let m = map.get(cell.field)
          m.hidden = current.hidden || !cell.values.includes(val)
          if (m.hidden) {
            m.initval = this.record[m.field]
          }
          map.set(cell.field, m)
          if (m.controlFields) {
            reset(m)
          }
        })
      }
      reset(item)
      this.setState({
        formlist: this.state.formlist.map(cell => {
          if (cell.field) {
            return map.get(cell.field)
          }
          return cell
        })
      })
    }
  }
  getFields() {
    const { getFieldDecorator } = this.props.form
    const { formlist } = this.state
    const fields = []
    formlist.forEach((item, index) => {
      if (item.hidden) return
      let content = null
      let label = item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}><Icon type="question-circle" />{item.label}</Tooltip> : item.label
      if (item.type === 'text') {
        content = (<MKEInput config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
      } else if (item.type === 'number') {
        content = (<MKNumberInput config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
      } else if (item.type === 'select' || item.type === 'multiselect') {
        content = (<MKSelect config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} />)
      } else if (item.type === 'color') {
        content = (<MKColor config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
      } else if (item.type === 'styleInput') {
        content = (<StyleInput config={item} onChange={(val) => this.recordChange({[item.field]: val})}/>)
      } else if (item.type === 'radio') {
        content = (<MKRadio config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)}/>)
      } else if (item.type === 'fileupload') {
        content = (<MKFileUpload config={item} onChange={(val) => this.recordChange({[item.field]: val})} />)
      } else if (item.type === 'cascader') {
        content = (<Cascader options={item.options} expandTrigger="hover" placeholder="" />)
      }
      if (!content) return
      fields.push(
        <Col span={item.span || 12} key={index}>
          <Form.Item label={label}>
            {getFieldDecorator(item.field, {
              initialValue: item.initval,
              rules: item.rules
            })(content)}
          </Form.Item>
        </Col>
      )
    })
    return fields
  }
  handleConfirm = () => {
    // 表单提交时检查输入值是否正确
    return new Promise((resolve, reject) => {
      this.props.form.validateFieldsAndScroll((err, values) => {
        if (err) {
          reject(err)
          return
        }
        resolve(values)
      })
    })
  }
  render() {
    const formItemLayout = {
      labelCol: {
        xs: { span: 24 },
        sm: { span: 8 }
      },
      wrapperCol: {
        xs: { span: 24 },
        sm: { span: 16 }
      }
    }
    return (
      <Form {...formItemLayout} className="normal-form-field">
        <Row gutter={24}>{this.getFields()}</Row>
      </Form>
    )
  }
}
export default Form.create()(ModalForm)
src/components/normalform/modalform/index.scss
New file
@@ -0,0 +1,112 @@
.normal-form-field {
  position: relative;
  padding: 0px 24px 20px;
  >.ant-row >.ant-col {
    display: inline-block;
    float: none;
    vertical-align: top;
    padding-left: 1.2%!important;
    padding-right: 1.2%!important;
  }
  .ant-form-item-label .anticon-question-circle {
    color: #c49f47;
    margin-right: 3px;
  }
  .ant-checkbox-group {
    line-height: unset;
    .ant-checkbox-wrapper {
      margin-right: 8px;
    }
    .ant-checkbox-wrapper + .ant-checkbox-wrapper {
      margin-left: 0;
    }
  }
  .ant-form-item {
    display: flex;
  }
  .ant-form-item.checkcard {
    margin-bottom: 10px;
    .ant-form-item-control {
      line-height: 1.5;
    }
  }
  .ant-form-item.hint {
    margin-bottom: 0px;
    .message {
      margin-top: 9px;
      line-height: 1.5;
      color: rgba(0, 0, 0, 0.85);
    }
  }
  .ant-form-item-control-wrapper {
    flex: 1;
  }
  .ant-form-item-label {
    overflow: hidden;
    display: inline-block;
    text-overflow: ellipsis;
    white-space: nowrap;
    width: 33.3%;
  }
  >.ant-row.cols2 .ant-col-24 {
    .ant-form-item {
      .ant-form-item-label {
        width: 16%;
      }
    }
  }
  >.ant-row.cols3 .ant-col-24 {
    .ant-form-item {
      .ant-form-item-label {
        width: 10.5%;
      }
    }
  }
  >.ant-row.cols4 .ant-col-24 {
    .ant-form-item {
      .ant-form-item-label {
        width: 7.5%;
      }
    }
  }
  .ant-input-number {
    width: 100%;
  }
  .ant-form-explain {
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
  .color-sketch-block {
    margin-top: 7px;
    overflow: hidden;
    .color-sketch-block-box {
      min-width: 100px;
    }
  }
  .normal-braft-editor {
    border: 1px solid #d9d9d9;
    border-radius: 4px;
    overflow-x: hidden;
  }
  p {
    color: #1890ff;
    font-size: 15px;
    padding-left: 10px;
    border-bottom: 1px solid #e9e9e9;
  }
  .ant-input-disabled {
    color: rgba(0, 0, 0, 0.65)!important;
    cursor: default!important;
  }
  .ant-input-number-input {
    color: rgba(0, 0, 0, 0.65)!important;
    cursor: default!important;
  }
  .ant-select-disabled {
    color: rgba(0, 0, 0, 0.65)!important;
    .ant-select-selection--multiple .ant-select-selection__choice {
      color: rgba(0, 0, 0, 0.65)!important;
    }
  }
}
src/components/normalform/modalform/mkInput/index.jsx
New file
@@ -0,0 +1,71 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { Input } from 'antd'
import MKEmitter from '@/utils/events.js'
import './index.scss'
/**
 * @description 自定义文本输入
 */
class MKEInput extends Component {
  constructor(props) {
    super(props)
    const config = props.config
    this.state = {
      value: config.initval
    }
  }
  inputRef = React.createRef()
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    const { config } = this.props
    MKEmitter.addListener('mkFC', this.mkFormHandle)
    if (config.focus) {
      this.inputRef.current.select()
    }
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkFC', this.mkFormHandle)
  }
  mkFormHandle = (type, field, value) => {
    if (field !== this.props.config.field) return
    if (type === 'focus') {
      this.inputRef.current.select()
    } else if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, true)
    }
  }
  handleChange = (e) => {
    let val = e.target.value
    this.setState({value: val})
    this.props.onChange(val)
  }
  render() {
    const { config } = this.props
    const { value } = this.state
    return <Input ref={this.inputRef} placeholder={config.placeholder || ''} value={value} autoComplete="off" onChange={this.handleChange} onPressEnter={this.props.onSubmit} />
  }
}
export default MKEInput
src/components/normalform/modalform/mkInput/index.scss
New file
@@ -0,0 +1,27 @@
.am-list-item.am-input-item {
  .am-input-control {
    height: 100%;
    input {
      height: 100%;
    }
  }
  .am-input-label {
    width: 28%;
    max-width: 120px;
    text-overflow: ellipsis;
  }
  .am-input-extra {
    max-height: 40px;
    .anticon-scan {
      font-size: 22px;
      padding: 8px 5px;
    }
  }
}
.am-input-item.right {
  .am-input-control {
    input {
      text-align: right;
    }
  }
}
src/components/normalform/modalform/mkNumberInput/index.jsx
New file
@@ -0,0 +1,62 @@
import React, { Component } from 'react'
import { is, fromJS } from 'immutable'
import { InputNumber } from 'antd'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class MKNumberInput extends Component {
  constructor(props) {
    super(props)
    const config = props.config
    this.state = {
      value: config.initval,
      precision: config.precision
    }
  }
  inputNumberRef = React.createRef()
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    MKEmitter.addListener('mkFC', this.mkFormHandle)
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkFC', this.mkFormHandle)
  }
  mkFormHandle = (type, field, value) => {
    if (field !== this.props.config.field) return
    if (type === 'focus') {
      this.inputNumberRef.current.focus()
    } else if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, true)
    }
  }
  handleChange = (val) => {
    this.setState({value: val})
    this.props.onChange(val)
  }
  render() {
    const { onSubmit } = this.props
    const { value, precision } = this.state
    return (<InputNumber ref={this.inputNumberRef} value={value} precision={precision} onChange={this.handleChange} onPressEnter={onSubmit} />)
  }
}
export default MKNumberInput
src/components/normalform/modalform/mkNumberInput/index.scss
New file
@@ -0,0 +1,27 @@
.am-list-item.am-input-item {
  .am-input-control {
    height: 100%;
    input {
      height: 100%;
    }
  }
  .am-input-label {
    width: 28%;
    max-width: 120px;
    text-overflow: ellipsis;
  }
  .am-input-extra {
    max-height: 40px;
    .anticon-scan {
      font-size: 22px;
      padding: 8px 5px;
    }
  }
}
.am-input-item.right {
  .am-input-control {
    input {
      text-align: right;
    }
  }
}
src/components/normalform/modalform/mkRadio/index.jsx
New file
@@ -0,0 +1,94 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Radio } from 'antd'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class MKRadio extends Component {
  static propTpyes = {
    config: PropTypes.object,
    onChange: PropTypes.func
  }
  state = {
    value: this.props.config.initval,
    config: fromJS(this.props.config).toJS(),
    options: fromJS(this.props.config.options).toJS(),
  }
  componentDidMount () {
    MKEmitter.addListener('mkFP', this.mkFormHandle)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkFP', this.mkFormHandle)
  }
  mkFormHandle = (field, parentId) => {
    const { config } = this.state
    if (field !== config.field) return
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId) : []
    let val = options[0] ? options[0].value : ''
    this.setState({
      options,
      value: val
    })
    this.props.onChange(val)
    config.linkFields && config.linkFields.forEach((m, i) => {
      setTimeout(() => {
        MKEmitter.emit('mkFP', m, val)
      }, (i + 1) * 70)
    })
  }
  onChange = (e) => {
    const { config } = this.state
    let value = e.target.value
    let other = {}
    if (config.subFields) {
      let option = this.state.options.filter(m => m.value === value)[0]
      option && config.subFields.forEach((n, i) => {
        other[n] = option[n] || ''
        setTimeout(() => {
          MKEmitter.emit('mkFC', 'input', n, option[n] || '')
        }, i * 5)
      })
    }
    config.linkFields && config.linkFields.forEach((m, i) => {
      setTimeout(() => {
        MKEmitter.emit('mkFP', m, value)
      }, (i + 1) * 100)
    })
    this.setState({value})
    this.props.onChange(value, other)
  }
  render() {
    const { value, options } = this.state
    return (
      <Radio.Group value={value} onChange={this.onChange}>
        {options.map(option => <Radio key={option.value} value={option.value}>{option.label}</Radio>)}
      </Radio.Group>
    )
  }
}
export default MKRadio
src/components/normalform/modalform/mkRadio/index.scss
src/components/normalform/modalform/mkSelect/index.jsx
New file
@@ -0,0 +1,140 @@
import React, {Component} from 'react'
import { is, fromJS } from 'immutable'
import { Select } from 'antd'
import MKEmitter from '@/utils/events.js'
import './index.scss'
class MKSelect extends Component {
  constructor(props) {
    super(props)
    const config = props.config
    let value = config.initval
    if (config.type === 'multiselect') {
      value = value || []
    }
    this.state = {
      config: fromJS(config).toJS(),
      options: fromJS(config.options).toJS(),
      value,
    }
  }
  componentDidMount () {
    const { config } = this.state
    if (config.type !== 'multiselect') {
      MKEmitter.addListener('mkFP', this.mkFormHandle)
    }
    MKEmitter.addListener('mkFC', this.mkFormControl)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkFP', this.mkFormHandle)
    MKEmitter.removeListener('mkFC', this.mkFormControl)
  }
  mkFormControl = (type, field, value) => {
    if (field !== this.props.config.field) return
    if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, {})
    }
  }
  mkFormHandle = (field, parentId) => {
    if (field !== this.state.config.field) return
    const { config } = this.state
    let options = config.oriOptions ? config.oriOptions.filter(option => option.ParentID === parentId) : []
    let val = options[0] ? options[0].value : ''
    this.setState({
      options,
      value: val
    })
    this.props.onChange(val)
    config.linkFields && config.linkFields.forEach((m, i) => {
      setTimeout(() => {
        MKEmitter.emit('mkFP', m, val)
      }, (i + 1) * 70)
    })
  }
  selectChange = (val) => {
    const { config } = this.state
    let other = {}
    if (config.subFields) {
      let option = this.state.options.filter(m => m.value === val)[0]
      option && config.subFields.forEach((n, i) => {
        other[n] = option[n] || ''
        setTimeout(() => {
          MKEmitter.emit('mkFC', 'input', n, option[n] || '')
        }, i * 5)
      })
    }
    config.linkFields && config.linkFields.forEach((m, i) => {
      setTimeout(() => {
        MKEmitter.emit('mkFP', m, val)
      }, (i + 1) * 100)
    })
    this.setState({value: val})
    this.props.onChange(val, other)
  }
  mutilselectChange = (val) => {
    this.props.onChange(val)
  }
  render() {
    const { value, config, options } = this.state
    if (config.type !== 'multiselect') {
      return (
        <Select
          showSearch
          allowClear
          value={value}
          filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
          onSelect={this.selectChange}
          onChange={(val) => val === undefined && this.selectChange('')}
        >
          {options.map(option =>
            <Select.Option id={option.value} title={option.label} key={option.value} value={option.value}>{option.label || option.text}</Select.Option>
          )}
        </Select>
      )
    } else {
      return (<Select
        showSearch
        mode="multiple"
        defaultValue={value}
        filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
        onChange={this.mutilselectChange}
      >
        {options.map(option =>
          <Select.Option id={option.value} title={option.label} key={option.value} value={option.value}>{option.label || option.text}</Select.Option>
        )}
      </Select>)
    }
  }
}
export default MKSelect
src/components/normalform/modalform/mkSelect/index.scss
src/components/normalform/modalform/styleInput/index.jsx
New file
@@ -0,0 +1,144 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Select, Input } from 'antd'
import MKEmitter from '@/utils/events.js'
import './index.scss'
const { Option } = Select
class StyleInput extends Component {
  static propTpyes = {
    config: PropTypes.object,
    onChange: PropTypes.func,
  }
  state = {
    value: '',
    unit: '',
    options: []
  }
  UNSAFE_componentWillMount () {
    const { config } = this.props
    let val = config.initval || ''
    let options = config.options || ['px', 'vh', 'vw', '%']
    let unit = options[0]
    if (val) {
      if (val.indexOf('px') > -1) {
        unit = 'px'
      } else if (val.indexOf('%') > -1) {
        unit = '%'
      } else if (val.indexOf('vw') > -1) {
        unit = 'vw'
      } else if (val.indexOf('vh') > -1) {
        unit = 'vh'
      }
    }
    let _val = parseFloat(val)
    if (isNaN(_val)) {
      _val = ''
    }
    this.setState({value: _val, options: options, unit})
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  componentDidMount () {
    MKEmitter.addListener('mkFC', this.mkFormHandle)
  }
  componentWillUnmount () {
    this.setState = () => {
      return
    }
    MKEmitter.removeListener('mkFC', this.mkFormHandle)
  }
  mkFormHandle = (type, field, value) => {
    if (field !== this.props.config.field) return
    if (type === 'input') {
      let val = value
      let unit = this.state.unit
      if (val) {
        if (val.indexOf('px') > -1) {
          unit = 'px'
        } else if (val.indexOf('%') > -1) {
          unit = '%'
        } else if (val.indexOf('vw') > -1) {
          unit = 'vw'
        } else if (val.indexOf('vh') > -1) {
          unit = 'vh'
        }
      }
      let _val = parseFloat(val)
      if (isNaN(_val)) {
        _val = ''
      }
      this.setState({value: _val, unit})
      this.props.onChange(value, true)
    }
  }
  changeValue = (e) => {
    const { unit } = this.state
    let val = e.target.value
    if (/\d+\.$/.test(val)) {
      this.setState({
        value: val
      })
      return
    }
    let _val = parseFloat(val)
    if (isNaN(_val)) {
      _val = ''
    }
    this.setState({
      value: _val,
    })
    this.props.onChange(_val !== '' ? `${_val}${unit}` : '')
  }
  changeUnit = (val) => {
    const { value } = this.state
    this.setState({unit: val})
    this.props.onChange(value !== '' ? `${value}${val}` : '')
  }
  render () {
    const { value, options, unit } = this.state
    return (
      <div className="style-input-wrap">
        <Input value={value} addonAfter={
          options.length > 1 ?
          <Select value={unit} onChange={this.changeUnit}>
            {options.map(item => <Option key={item} value={item}>{item}</Option>)}
          </Select> :
          <div className="single-unit">{unit}</div>
        } onChange={this.changeValue}/>
      </div>
    )
  }
}
export default StyleInput
src/components/normalform/modalform/styleInput/index.scss
New file
@@ -0,0 +1,11 @@
.style-input-wrap {
  line-height: 32px;
  .ant-select {
    width: 60px!important;
  }
  .single-unit {
    width: 38px;
    text-align: left;
    color: rgba(255, 255, 255, 0.65);
  }
}
src/menu/components/card/balcony/index.jsx
@@ -8,12 +8,14 @@
import { resetStyle } from '@/utils/utils-custom.js'
import MKEmitter from '@/utils/events.js'
import Utils from '@/utils/utils.js'
import MenuUtils from '@/utils/utils-custom.js'
import { balconyWrapForm } from './options'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('./wrapsetting'))
const NormalForm = asyncIconComponent(() => import('@/components/normalform'))
const CardCellComponent = asyncComponent(() => import('../cardcellcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/components/paste'))
@@ -204,6 +206,43 @@
    resolve({status: true})
  }
  getWrapForms = () => {
    const { wrap } = this.state.card
    let modules = MenuUtils.getLinkModules(fromJS(window.GLOB.customMenu).toJS().components) || []
    let supmodules = MenuUtils.getSupModules(fromJS(window.GLOB.customMenu).toJS().components, '') || []
    let roleList = sessionStorage.getItem('sysRoles')
    if (roleList) {
      try {
        roleList = JSON.parse(roleList)
      } catch {
        roleList = []
      }
    } else {
      roleList = []
    }
    return fromJS(balconyWrapForm).toJS().map(item => {
      item.initval = wrap[item.field] || item.initval
      if (item.field === 'blacklist') {
        item.options = roleList
      } else if (item.field === 'syncModule') {
        item.options = modules
      } else if (item.field === 'supModule') {
        item.options = supmodules
      }
      return item
    })
  }
  updateWrap = (res) => {
    delete res.quick
    this.updateComponent({...this.state.card, wrap: res})
  }
  render() {
    const { card } = this.state
@@ -215,7 +254,9 @@
          <div className="mk-popover-control">
            <Icon className="plus" title="添加元素" onClick={this.addElement} type="plus" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <WrapComponent config={card} updateConfig={this.updateComponent} />
            <NormalForm title="卡片设置" width={800} update={this.updateWrap} getForms={this.getWrapForms}>
              <Icon type="edit" style={{color: '#1890ff'}} title="编辑"/>
            </NormalForm>
            <CopyComponent type="balcony" card={card}/>
            <PasteComponent options={['action', 'customCardElement']} updateConfig={this.pasteComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
src/menu/components/card/balcony/options.jsx
New file
@@ -0,0 +1,195 @@
/**
 * @description Wrap表单配置信息
 */
export const balconyWrapForm = [
  {
    type: 'text',
    field: 'name',
    label: '组件名称',
    initval: '',
    tooltip: '用于组件间的区分。',
    required: true
  },
  {
    type: 'number',
    field: 'width',
    label: '宽度',
    initval: '',
    tooltip: '栅格布局,每行等分为24列。',
    min: 1,
    max: 24,
    precision: 0,
    required: true
  },
  {
    type: 'radio',
    field: 'datatype',
    label: '数据来源',
    initval: '',
    tooltip: '选择静态值,无需配置数据源。',
    required: false,
    options: [
      {value: 'dynamic', label: '动态'},
      {value: 'static', label: '静态'},
    ]
  },
  {
    type: 'radio',
    field: 'linkType',
    label: '受控类型',
    initval: 'static',
    tooltip: '组件与其他组件之间的控制类型,独立表示与其他没有关联。',
    required: false,
    options: [
      {value: 'static', label: '独立'},
      {value: 'sync', label: '同步'},
      {value: 'sup', label: '上级'},
    ],
    controlFields: [
      {field: 'supModule', values: ['sup']},
      {field: 'supControl', values: ['sup']},
      {field: 'syncModule', values: ['sync']},
      {field: 'checkAll', values: ['sync']},
    ]
  },
  {
    type: 'cascader',
    field: 'supModule',
    label: '上级组件',
    initval: '',
    required: true,
    options: []
  },
  {
    type: 'radio',
    field: 'supControl',
    label: '显示控制',
    tooltip: '当前组件在主表选中行时显示,还是始终显示。',
    initval: 'show',
    required: false,
    options: [
      {value: 'hidden', label: '选行'},
      {value: 'show', label: '始终'},
    ]
  },
  {
    type: 'cascader',
    field: 'syncModule',
    label: '同步组件',
    initval: '',
    required: true,
    options: []
  },
  {
    type: 'radio',
    field: 'checkAll',
    label: '全选',
    initval: 'hidden',
    tooltip: '当同步组件可多选时,设置全选有效。',
    required: false,
    options: [
      {value: 'hidden', label: '隐藏'},
      {value: 'show', label: '显示'},
    ]
  },
  {
    type: 'radio',
    field: 'position',
    label: '位置',
    initval: 'relative',
    tooltip: '使用固定定位时,请在测试环境中查看定位效果。',
    required: false,
    options: [
      {value: 'relative', label: '相对定位'},
      {value: 'fixed', label: '固定定位'},
    ],
    controlFields: [
      {field: 'quick', values: ['fixed']},
      {field: 'top', values: ['fixed']},
      {field: 'right', values: ['fixed']},
      {field: 'bottom', values: ['fixed']},
      {field: 'left', values: ['fixed']},
      {field: 'realwidth', values: ['fixed']},
      {field: 'transform', values: ['fixed']},
    ]
  },
  {
    type: 'select',
    field: 'quick',
    label: '快捷选择',
    initval: '',
    required: false,
    subFields: ['top', 'left', 'right', 'bottom', 'transform'],
    options: [
      {value: 'top', label: '上', top: '0px', left: '0px', right: '0px', bottom: '', transform: ''},
      {value: 'top-left', label: '左上', top: '0px', left: '0px', right: '', bottom: '', transform: ''},
      {value: 'top-right', label: '右上', top: '0px', left: '', right: '0px', bottom: '', transform: ''},
      {value: 'left-middle', label: '左中', top: '50%', left: '0px', right: '', bottom: '', transform: 'translateY(-50%)'},
      {value: 'right-middle', label: '右中', top: '50%', left: '', right: '0px', bottom: '', transform: 'translateY(-50%)'},
      {value: 'bottom-left', label: '左下', top: '', left: '0px', right: '', bottom: '0px', transform: ''},
      {value: 'bottom-right', label: '右下', top: '', left: '', right: '0px', bottom: '0px', transform: ''},
      {value: 'bottom', label: '下', top: '', left: '0px', right: '0px', bottom: '0px', transform: ''},
      {value: 'middle', label: '中间', top: '50%', left: '50%', right: '', bottom: '', transform: 'translate(-50%, -50%)'}
    ]
  },
  {
    type: 'styleInput',
    field: 'top',
    label: '距上',
    initval: '',
    required: false
  },
  {
    type: 'styleInput',
    field: 'right',
    label: '距右',
    initval: '',
    required: false
  },
  {
    type: 'styleInput',
    field: 'bottom',
    label: '距下',
    initval: '',
    required: false
  },
  {
    type: 'styleInput',
    field: 'left',
    label: '距左',
    initval: '',
    required: false
  },
  {
    type: 'styleInput',
    field: 'realwidth',
    label: '实际宽度',
    initval: '',
    required: false
  },
  {
    type: 'select',
    field: 'transform',
    label: '变换',
    initval: '',
    required: false,
    options: [
      {value: 'translateY(-50%)', label: '上移50%'},
      {value: 'translateY(50%)', label: '下移50%'},
      {value: 'translateX(-50%)', label: '左移50%'},
      {value: 'translateX(50%)', label: '右移50%'},
      {value: 'translate(-50%, -50%)', label: '左上移50%'},
      {value: 'translate(-50%, 50%)', label: '左下移50%'},
      {value: 'translate(50%, -50%)', label: '右上移50%'},
      {value: 'translate(50%, 50%)', label: '右下移50%'},
    ]
  },
  {
    type: 'multiselect',
    field: 'blacklist',
    label: '黑名单',
    initval: '',
    required: false,
    options: []
  },
]
src/menu/components/card/balcony/wrapsetting/index.jsx
File was deleted
src/menu/components/card/balcony/wrapsetting/index.scss
File was deleted
src/menu/components/card/balcony/wrapsetting/settingform/index.jsx
File was deleted
src/menu/components/card/balcony/wrapsetting/settingform/index.scss
File was deleted
src/menu/components/card/cardcellcomponent/dragaction/action.jsx
@@ -48,7 +48,7 @@
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control">
      <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
        <Icon className="edit" title="编辑" type="edit" onClick={() => editCard(id)} />
        <Icon className="copy" title="复制" type="copy" onClick={() => copyCard(id)} />
        <Icon className="close" title="删除" type="close" onClick={() => delCard(id)} />
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -24,7 +24,7 @@
  '10:1': '10%', '3:4': '133.33%', '2:3': '150%', '9:16': '177.78%'
}
const Card = ({ id, parent, fields, card, moveCard, findCard, editCard, delCard, copyCard, changeStyle, updateMarks, doubleClickCard }) => {
const Card = ({ id, parent, fields, card, moveCard, findCard, editCard, delCard, copyCard, changeStyle, updateMarks }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'action', id, originalIndex },
@@ -153,7 +153,7 @@
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control">
      <div className="mk-popover-control" onDoubleClick={(e) => e.stopPropagation()}>
        <Icon className="edit" title="编辑" type="edit" onClick={() => editCard(id)} />
        <Icon className="copy" title="复制" type="copy" onClick={() => copyCard(id)} />
        <Icon className="close" title="删除" type="close" onClick={() => delCard(id)} />
@@ -162,7 +162,7 @@
      </div>
    } trigger="hover">
      <div ref={node => drag(drop(node))} className={'ant-col card-cell ant-col-' + card.width}>
        <div style={_style} onClick={clickComponent} onDoubleClick={() => doubleClickCard(id)} id={card.uuid}>
        <div style={_style} onClick={clickComponent} id={card.uuid}>
          {getContent()}
        </div>
      </div>
src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -85,7 +85,7 @@
  const doubleClickCard = id => {
    const { card } = findCard(id)
    if (card.eleType !== 'button' && card.eleType !== 'text' && card.eleType !== 'picture') {
    if (card.eleType !== 'button') {
      return
    }
    
@@ -139,7 +139,6 @@
              editCard={editCard}
              updateMarks={updateMarks}
              changeStyle={changeStyle}
              doubleClickCard={doubleClickCard}
              delCard={delCard}
              findCard={findCard}
            />
src/menu/components/card/cardcellcomponent/dragaction/index.scss
@@ -100,6 +100,23 @@
    font-weight: inherit;
    font-style: inherit;
  }
  .ant-mk-check {
    white-space: nowrap;
    overflow: hidden;
    word-break: break-word;
    text-overflow: ellipsis;
    font-weight: inherit;
    font-style: inherit;
    .ant-checkbox-wrapper {
      font-weight: inherit;
      font-size: inherit;
      font-style: inherit;
      color: inherit;
      span {
        font-weight: inherit;
      }
    }
  }
  .ant-mk-picture {
    background-size: cover;
    background-position: center center;
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -25,6 +25,7 @@
  if (type === 'table' || (type === 'card' && subtype === 'datacard')) {
    _options.push({value: 'sequence', text: '序号'})
  }
  let appMenus = []
  const isApp = sessionStorage.getItem('appType') === 'pc'
src/menu/components/card/cardcellcomponent/index.jsx
@@ -595,94 +595,96 @@
          handleSubConfig={this.handleSubConfig}
          deleteMenu={this.deleteElement}
        />
        {/* 编辑按钮:复制、编辑 */}
        <Modal
          title={'编辑元素'}
          visible={visible}
          width={800}
          maskClosable={false}
          onCancel={this.editModalCancel}
          onOk={this.handleSubmit}
          destroyOnClose
        >
          <ElementForm
            dict={dict}
            card={card}
            formlist={this.state.formlist}
            inputSubmit={this.handleSubmit}
            config={cards}
            wrappedComponentRef={(inst) => this.elementFormRef = inst}
          />
        </Modal>
        {/* 编辑按钮:复制、编辑 */}
        <Modal
          title={dict['model.action'] + '-' + (card && card.copyType === 'action' ? dict['model.copy'] : dict['model.edit'])}
          visible={actvisible}
          width={800}
          maskClosable={false}
          onCancel={this.editModalCancel}
          footer={[
            <Button key="cancel" onClick={this.editModalCancel}>{dict['model.cancel']}</Button>,
            <Button key="confirm" type="primary" onClick={this.handleActionSubmit}>{dict['model.confirm']}</Button>
          ]}
          destroyOnClose
        >
          <ActionForm
            dict={dict}
            type={cards.type === 'balcony' ? '' : 'card'}
            card={card}
            formlist={this.state.formlist}
            inputSubmit={this.handleActionSubmit}
            setting={cards.setting}
            wrappedComponentRef={(inst) => this.actionFormRef = inst}
          />
        </Modal>
        {/* 按钮使用系统存储过程时,验证信息模态框 */}
        <Modal
          wrapClassName="model-table-action-verify-modal"
          title={'验证信息'}
          visible={profVisible}
          width={'75vw'}
          maskClosable={false}
          okText={dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ profVisible: false }) }}
          destroyOnClose
        >
          {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ?
            <VerifyCard
              card={card}
        <div onDoubleClick={(e) => e.stopPropagation()}>
          {/* 编辑按钮:复制、编辑 */}
          <Modal
            title={'编辑元素'}
            visible={visible}
            width={800}
            maskClosable={false}
            onCancel={this.editModalCancel}
            onOk={this.handleSubmit}
            destroyOnClose
          >
            <ElementForm
              dict={dict}
              card={card}
              formlist={this.state.formlist}
              inputSubmit={this.handleSubmit}
              config={cards}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.execMode ?
            <VerifyPrint
              card={card}
              wrappedComponentRef={(inst) => this.elementFormRef = inst}
            />
          </Modal>
          {/* 编辑按钮:复制、编辑 */}
          <Modal
            title={dict['model.action'] + '-' + (card && card.copyType === 'action' ? dict['model.copy'] : dict['model.edit'])}
            visible={actvisible}
            width={800}
            maskClosable={false}
            onCancel={this.editModalCancel}
            footer={[
              <Button key="cancel" onClick={this.editModalCancel}>{dict['model.cancel']}</Button>,
              <Button key="confirm" type="primary" onClick={this.handleActionSubmit}>{dict['model.confirm']}</Button>
            ]}
            destroyOnClose
          >
            <ActionForm
              dict={dict}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.OpenType === 'excelIn' ?
            <VerifyExcelIn
              type={cards.type === 'balcony' ? '' : 'card'}
              card={card}
              dict={dict}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.OpenType === 'excelOut' ?
            <VerifyExcelOut
              card={card}
              dict={dict}
              config={cards}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
        </Modal>
              formlist={this.state.formlist}
              inputSubmit={this.handleActionSubmit}
              setting={cards.setting}
              wrappedComponentRef={(inst) => this.actionFormRef = inst}
            />
          </Modal>
          {/* 按钮使用系统存储过程时,验证信息模态框 */}
          <Modal
            wrapClassName="model-table-action-verify-modal"
            title={'验证信息'}
            visible={profVisible}
            width={'75vw'}
            maskClosable={false}
            okText={dict['model.submit']}
            onOk={this.verifySubmit}
            onCancel={() => { this.setState({ profVisible: false }) }}
            destroyOnClose
          >
            {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ?
              <VerifyCard
                card={card}
                dict={dict}
                config={cards}
                columns={cards.columns}
                wrappedComponentRef={(inst) => this.verifyRef = inst}
              /> : null
            }
            {card && card.execMode ?
              <VerifyPrint
                card={card}
                dict={dict}
                columns={cards.columns}
                wrappedComponentRef={(inst) => this.verifyRef = inst}
              /> : null
            }
            {card && card.OpenType === 'excelIn' ?
              <VerifyExcelIn
                card={card}
                dict={dict}
                columns={cards.columns}
                wrappedComponentRef={(inst) => this.verifyRef = inst}
              /> : null
            }
            {card && card.OpenType === 'excelOut' ?
              <VerifyExcelOut
                card={card}
                dict={dict}
                config={cards}
                wrappedComponentRef={(inst) => this.verifyRef = inst}
              /> : null
            }
          </Modal>
        </div>
      </div>
    )
  }
src/menu/components/card/cardcomponent/index.jsx
@@ -251,7 +251,7 @@
      <Col span={card.setting.width || 6} offset={offset || 0}>
        <div className="card-item" style={_style} onClick={this.clickComponent} onDoubleClick={(e) => {e.stopPropagation(); this.doubleClickCard()}} id={card.uuid}>
          <CardCellComponent cards={cards} cardCell={card} side={side} elements={elements} updateElement={this.updateCard}/>
          <div className="card-control">
          <div className="card-control" onDoubleClick={(e) => e.stopPropagation()}>
            <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
              <div className="mk-popover-control">
                <Icon className="plus" title="添加元素" onClick={this.addElement} type="plus" />
src/tabviews/custom/components/card/cardcellList/index.scss
@@ -118,6 +118,22 @@
    word-break: break-word;
    text-overflow: ellipsis;
  }
  .ant-mk-check {
    white-space: nowrap;
    overflow: hidden;
    word-break: break-word;
    text-overflow: ellipsis;
    font-style: inherit;
    .ant-checkbox-wrapper {
      font-weight: inherit;
      font-size: inherit;
      font-style: inherit;
      color: inherit;
      span {
        font-weight: inherit;
      }
    }
  }
  .ant-slider {
    margin: 0px;
  }
src/tabviews/zshare/mutilform/index.jsx
@@ -663,7 +663,7 @@
        if (item.type === 'text' || item.type === 'linkMain') {
          content = (<MKInput config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'number') {
          content = (<MKNumberInput config={item} onChange={(val) => this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
          content = (<MKNumberInput config={item} onChange={(val, defer) => !defer && this.recordChange({[item.field]: val})} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'select' || item.type === 'link' || item.type === 'multiselect') {
          content = (<MKSelect config={item} onChange={(val, other) => this.recordChange({[item.field]: val, ...other}, item)} onSubmit={this.props.inputSubmit} />)
        } else if (item.type === 'color') {
src/tabviews/zshare/mutilform/mkNumberInput/index.jsx
@@ -43,13 +43,13 @@
      this.inputNumberRef.current.focus()
    } else if (type === 'input') {
      this.setState({value})
      this.props.onChange(value, true)
    }
  }
  handleChange = (val) => {
    this.props.onChange(val)
    this.setState({value: val})
    this.props.onChange(val)
  }
  render() {
src/tabviews/zshare/mutilform/mkSelect/index.jsx
@@ -150,7 +150,7 @@
          value={value}
          filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0}
          onSelect={this.selectChange}
          onClear={() => this.selectChange('')}
          onChange={(val) => val === undefined && this.selectChange('')}
          disabled={config.readonly}
        >
          {options.map(option =>
src/templates/zshare/verifycard/index.jsx
@@ -831,7 +831,7 @@
        }
        _form = _form.join(', ')
        _updatesql = `update ${card.sql} set ${_form} where ${config.setting.primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
        _updatesql = `update ${card.sql} set ${_form} where ${config.setting.primaryKey || 'id'}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
      }
      if (card.sqlType === 'insert') {
@@ -840,7 +840,7 @@
        _defaultsql = _updatesql
      } else if (card.sqlType === 'insertOrUpdate') {
        _defaultsql += `select @tbid=''
          select @tbid='X' from ${card.sql} where ${config.setting.primaryKey}=@ID@
          select @tbid='X' from ${card.sql} where ${config.setting.primaryKey || 'id'}=@ID@
          if @tbid=''
            begin
            ${_insertsql}
@@ -855,7 +855,7 @@
        if (_verify.voucher && _verify.voucher.enabled) {
          _voucher = ',BVoucher=@BVoucher,FIBVoucherDate=@FIBVoucherDate,FiYear=@FiYear'
        }
        _defaultsql = `update ${card.sql} set deleted=1,modifydate=getdate(),modifyuserid=@userid@${_voucher} where ${config.setting.primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
        _defaultsql = `update ${card.sql} set deleted=1,modifydate=getdate(),modifyuserid=@userid@${_voucher} where ${config.setting.primaryKey || 'id'}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
      } else if (card.sqlType === 'delete') {
        let _msg = ''
        if (columns && columns.length > 0 && card.Ot !== 'notRequired' && card.Ot !== 'requiredOnce') {
@@ -867,7 +867,7 @@
            _index++
          })
        }
        _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${card.sql} 数据: ${_msg}${config.setting.primaryKey}='+@ID@,200),@userid@,@username,@fullname delete ${card.sql} where ${config.setting.primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
        _defaultsql += `insert into snote (remark,createuserid,CreateUser,CreateStaff) select left('删除表:${card.sql} 数据: ${_msg}${config.setting.primaryKey || 'id'}='+@ID@,200),@userid@,@username,@fullname delete ${card.sql} where ${config.setting.primaryKey}${card.Ot !== 'requiredOnce' ? '=@ID@' : ' in (select ID  from dbo.SplitComma(@ID@))'};`
      }
      let _columns = []