king
2021-05-18 f07fcb9f65ce2468439452755663870e7afc15c4
2021-05-18
4个文件已修改
3个文件已添加
438 ■■■■■ 已修改文件
src/menu/components/form/normal-form/index.jsx 30 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/card.jsx 139 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/index.jsx 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/mob/components/formdragelement/index.scss 127 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/sharecomponent/fieldscomponent/index.jsx 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/formconfig.jsx 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/templates/zshare/modalform/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/form/normal-form/index.jsx
@@ -18,6 +18,7 @@
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const WrapComponent = asyncIconComponent(() => import('@/menu/components/form/wrapsetting'))
const CardComponent = asyncComponent(() => import('@/templates/modalconfig/dragelement'))
const MobCardComponent = asyncComponent(() => import('@/mob/components/formdragelement'))
const FormTitle = asyncComponent(() => import('../dragtitle'))
const GroupForm = asyncComponent(() => import('./groupform'))
const FormAction = asyncComponent(() => import('../formaction'))
@@ -37,6 +38,7 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    appType: sessionStorage.getItem('appType'),
    card: null,
    back: false,
    group: null,
@@ -404,9 +406,13 @@
  }
  addForm = () => {
    const { appType } = this.state
    let group = fromJS(this.state.group).toJS()
    let lastItem = group.fields[group.fields.length - 1]
    let span = lastItem ? lastItem.span : 12
    let span = appType === 'mob' ? 24 : 12
    if (lastItem && lastItem.span) {
      span = lastItem.span
    }
    let newcard = {
      uuid: Utils.getuuid(),
@@ -615,7 +621,7 @@
  }
  render() {
    const { card, dict, group } = this.state
    const { card, dict, group, appType } = this.state
    return (
      <div className="menu-normal-form-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}>
@@ -646,12 +652,12 @@
          <Icon className="plus" title="添加表单" onClick={this.addForm} type="plus" />
          <FieldsComponent config={group} type="form" updatefield={this.updateGroup} />
          <Switch checkedChildren={dict['model.switch.open']} unCheckedChildren={dict['model.switch.close']} defaultChecked={this.state.showField} onChange={(val) => this.setState({showField: val})} />
          <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button>
          <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>
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(1)}>1列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(2)}>2列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(3)}>3列</Button> : null}
          {appType !== 'mob' ? <Button className="mk-cols-change" onClick={() => this.changecols(4)}>4列</Button> : null}
          <div style={{clear: 'both'}}></div>
          <CardComponent
          {appType !== 'mob' ? <CardComponent
            list={group.fields}
            setting={group.setting}
            showField={this.state.showField}
@@ -659,7 +665,15 @@
            handleList={this.handleList}
            handleForm={this.handleForm}
            closeForm={this.closeForm}
          />
          /> : <MobCardComponent
            list={group.fields}
            setting={group.setting}
            showField={this.state.showField}
            placeholder={dict['header.form.modal.placeholder']}
            handleList={this.handleList}
            handleForm={this.handleForm}
            closeForm={this.closeForm}
          />}
          <FormAction config={card} group={group} updateconfig={this.updateGroup}/>
        </div> : null}
        <Modal
src/mob/components/formdragelement/card.jsx
New file
@@ -0,0 +1,139 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon, DatePicker, Button, Popover, Switch, Radio, Checkbox, Form } from 'antd'
import { InputItem, TextareaItem } from 'antd-mobile'
import moment from 'moment'
import asyncComponent from '@/utils/asyncComponent'
import './index.scss'
const { MonthPicker } = DatePicker
const Editor = asyncComponent(() => import('@/components/editor'))
const ColorSketch = asyncComponent(() => import('@/mob/colorsketch'))
const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard'))
const Card = ({ id, card, moveCard, findCard, editCard, closeCard, copyCard, showField }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'form', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'form',
    canDrop: () => true,
    drop: (item) => {
      const { id: draggedId, originalIndex } = item
      if (originalIndex === undefined) {
        item.dropTargetId = id
      } else if (draggedId && draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    }
  })
  const opacity = isDragging ? 0 : 1
  const edit = () => {
    editCard(id)
  }
  const close = () => {
    closeCard(id)
  }
  const copy = () => {
    copyCard(id)
  }
  let selectval = ''
  if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') {
    if (card.initval) {
      let _option = card.options.filter(option => option.Value === card.initval)[0]
      if (_option) {
        selectval = _option.Text || ''
      } else {
        selectval = ''
      }
    } else if (card.setAll === 'true') {
      selectval = card.emptyText || '空'
    }
  }
  let formItem = null
  if (card.type === 'text') {
    formItem = (<InputItem value={card.initval}>{card.label}</InputItem>)
  } else if (card.type === 'number') {
    formItem = (<InputItem type="number" value={card.initval}>{card.label}</InputItem>)
  } else if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') {
    formItem = (<div className="am-list-item am-list-item-middle"><div className="am-list-line"><div className="am-list-content">{card.label}</div><div className="am-list-extra">{selectval || '请选择'}</div><div className="am-list-arrow am-list-arrow-horizontal"></div></div></div>)
  } else if (card.type === 'color') {
    formItem = (<ColorSketch value={card.initval || 'transparent'}/>)
  } else if (card.type === 'date') {
    formItem = (<DatePicker value={card.initval ? moment().subtract(card.initval, 'days') : null} />)
  } else if (card.type === 'datemonth') {
    formItem = (<MonthPicker value={card.initval ? moment().subtract(card.initval, 'month') : null} />)
  } else if (card.type === 'datetime') {
    formItem = (<DatePicker showTime value={card.initval ? moment().subtract(card.initval, 'days') : null} />)
  } else if (card.type === 'textarea') {
    formItem = (<TextareaItem title={card.label} autoHeight />)
  } else if (card.type === 'brafteditor') {
    formItem = (<Editor />)
  } else if (card.type === 'fileupload') {
    formItem = (<Button style={{marginTop: '3px'}}><Icon type="upload" /> 点击上传 </Button>)
  } else if (card.type === 'funcvar') {
    formItem = (<InputItem type="number" value={card.linkfield}>{card.label}</InputItem>)
  } else if (card.type === 'switch') {
    formItem = (<Switch checkedChildren={card.openText || ''} unCheckedChildren={card.closeText || ''} style={{marginTop: '8px'}} checked={card.initval}/>)
  } else if (card.type === 'radio') {
    formItem = card.options && card.options.length > 0 ? (<Radio.Group value={card.initval}>
      {card.options.map(cell => <Radio key={cell.key} value={cell.Value}>{cell.Text}</Radio>)}
    </Radio.Group>) : (<Radio.Group value={1}>
      <Radio value={1}>A</Radio>
      <Radio value={2}>B</Radio>
      <Radio value={3}>C</Radio>
      <Radio value={4}>D</Radio>
    </Radio.Group>)
  } else if (card.type === 'checkbox') {
    let _val = card.initval ? card.initval.split(',') : []
    formItem = card.options && card.options.length > 0 ? (<Checkbox.Group value={_val}>
      {card.options.map(cell => <Checkbox key={cell.key} value={cell.Value}>{cell.Text}</Checkbox>)}
    </Checkbox.Group>) : (<Checkbox.Group value={['A', 'C']}>
      <Checkbox value="A">A</Checkbox>
      <Checkbox value="B">B</Checkbox>
      <Checkbox value="C">C</Checkbox>
      <Checkbox value="D">D</Checkbox>
    </Checkbox.Group>)
  } else if (card.type === 'hint') {
    formItem = <div style={{marginTop: '10px', color: 'rgba(0, 0, 0, 0.85)', lineHeight: '1.5'}}>{card.message}</div>
  } else if (card.type === 'split') {
    formItem = <div className="split-line">{card.label}</div>
  } else if (card.type === 'checkcard') {
    formItem = <CheckCard width={card.width} ratio={card.ratio} display={card.display} fields={card.fields} options={card.options} />
  }
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control">
        <Icon className="edit" type="edit" onClick={edit} />
        <Icon className="copy" type="copy" onClick={copy} />
        <Icon className="close" type="close" onClick={close} />
      </div>
    } trigger="hover">
      <div className="page-card" style={{ opacity: opacity}}>
        <div ref={node => drag(drop(node))}>
          {card.type === 'split' ? formItem : <Form.Item
            className={'ant-form-item ' + (card.required === 'true' ? 'required' : '')}
          >
            {formItem}
            {showField ? <div className="field-name">{card.field}</div> : ''}
          </Form.Item>}
        </div>
      </div>
    </Popover>
  )
}
export default Card
src/mob/components/formdragelement/index.jsx
New file
@@ -0,0 +1,124 @@
import React, { useState } from 'react'
import { useDrop } from 'react-dnd'
import { is, fromJS } from 'immutable'
import update from 'immutability-helper'
import Utils from '@/utils/utils.js'
import Card from './card'
import './index.scss'
const Container = ({list, setting, placeholder, handleList, handleForm, closeForm, showField }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
    if (!card) return
    const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] })
    handleList(_cards)
  }
  if (!is(fromJS(cards), fromJS(list))) {
    setCards(list)
  }
  const findCard = id => {
    const card = cards.filter(c => `${c.uuid}` === id)[0]
    return {
      card,
      index: cards.indexOf(card),
    }
  }
  const editCard = id => {
    const { card } = findCard(id)
    delete card.focus
    handleForm(card)
  }
  const closeCard = id => {
    const { card } = findCard(id)
    closeForm(card)
  }
  const copyCard = id => {
    const { card, index: overIndex } = findCard(id)
    let _card = fromJS(card).toJS()
    _card.uuid = Utils.getuuid()
    _card.focus = true
    // 复制到剪切板
    let oInput = document.createElement('input')
    let val = JSON.parse(JSON.stringify(_card))
    val.copyType = 'form'
    oInput.value = window.btoa(window.encodeURIComponent(JSON.stringify(val)))
    document.body.appendChild(oInput)
    oInput.select()
    document.execCommand('Copy')
    oInput.className = 'oInput'
    oInput.style.display = 'none'
    document.body.removeChild(oInput)
    const _cards = update(cards, { $splice: [[overIndex + 1, 0, _card]] })
    setCards(_cards)
    handleList(_cards, _card)
  }
  const [, drop] = useDrop({
    accept: 'form',
    drop(item) {
      if (item.hasOwnProperty('originalIndex')) {
        return
      }
      let newcard = {}
      newcard.uuid = Utils.getuuid()
      newcard.label = 'label'
      newcard.type = item.subType
      newcard.resourceType = '0'
      newcard.options = []
      newcard.readonly = 'false'
      newcard.required = 'true'
      newcard.focus = true
      let targetId = ''
      if (item.dropTargetId) {
        targetId = item.dropTargetId
        delete item.dropTargetId
      } else if (cards.length > 0) {
        targetId = cards[cards.length - 1].uuid
      }
      const { index: overIndex } = findCard(`${targetId}`) // cards为空时 overIndex 为 -1
      const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] })
      setCards(_cards)
      handleList(_cards, newcard)
    }
  })
  return (
    <div ref={drop} className={'ant-row modal-fields-row ' + (setting.align || 'left_right')} >
      {cards.map(card => {
        return <Card
          id={card.uuid}
          key={card.uuid}
          card={card}
          showField={showField}
          moveCard={moveCard}
          editCard={editCard}
          closeCard={closeCard}
          copyCard={copyCard}
          findCard={findCard}
        />
      })}
    </div>
  )
}
export default Container
src/mob/components/formdragelement/index.scss
New file
@@ -0,0 +1,127 @@
.modal-fields-row {
  padding-bottom: 35px;
  .mob-col.ant-col {
    display: inline-block;
    float: none;
    vertical-align: top;
    padding-left: 1.2%;
    padding-right: 1.2%;
  }
  .am-list-item.am-input-item {
    padding-left: 0;
  }
  .am-list-item .am-input-label {
    font-size: 16px;
  }
  .am-list-line {
    border-bottom: 1PX solid #ddd;
    input {
      text-align: right;
    }
  }
  .ant-form-item-children {
    padding-left: 10px;
  }
  .split-line {
    color: #1890ff;
    font-size: 15px;
    padding-left: 10px;
    border-bottom: 1px solid #e9e9e9;
  }
  .ant-form-item.required {
    .am-input-label::before {
      display: inline-block;
      margin-right: 4px;
      color: #f5222d;
      font-size: 14px;
      font-family: SimSun, sans-serif;
      line-height: 1;
      content: '*';
    }
  }
  .ant-form-item {
    cursor: move;
    display: flex;
    margin-bottom: 0px;
    .ant-form-item-label {
      overflow: visible;
      position: relative;
      cursor: move;
      height: 40px;
      width: 33.3%;
      label {
        width: 100%;
        cursor: move;
        overflow: hidden;
        display: inline-block;
        text-overflow: ellipsis;
        white-space: nowrap;
      }
      .anticon-question-circle {
        color: #c49f47;
        margin-right: 3px;
        line-height: 40px;
      }
    }
    .ant-form-item-control-wrapper {
      position: relative;
      flex: 1;
      .ant-select {
        width: 100%;
        margin-top: 4px;
      }
      .field-name {
        line-height: 1.3;
        float: left;
      }
      .ant-checkbox-group {
        line-height: 40px;
        .ant-checkbox-wrapper {
          margin-right: 8px;
        }
        .ant-checkbox-wrapper + .ant-checkbox-wrapper {
          margin-left: 0px;
        }
      }
      .ant-radio-group {
        line-height: 40px;
      }
      .ant-calendar-picker {
        width: 100%;
        margin-top: 4px;
      }
      .ant-input-number {
        width: 100%;
        margin-top: 4px;
      }
      .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;
      }
    }
    .ant-form-item-control-wrapper::after {
      content: '';
      position: absolute;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      opacity: 0;
      z-index: 1;
    }
    .ant-col-cuslabel {
      width: 10.5%;
    }
    .ant-col-cuswrap {
      width: 89.5%;
    }
  }
}
src/templates/sharecomponent/fieldscomponent/index.jsx
@@ -19,6 +19,7 @@
  state = {
    dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    appType: sessionStorage.getItem('appType'),
    fields: [],          // 字段集
    tableVisible: false,    // 模态框控制
  }
@@ -247,7 +248,10 @@
  
      let _columns = [...columnsMap.values()]
      let lastItem = config.fields[config.fields.length - 1]
      let span = lastItem ? lastItem.span || 12 : 12
      let span = this.state.appType === 'mob' ? 24 : 12
      if (lastItem && lastItem.span) {
        span = lastItem.span
      }
      _columns.forEach(item => { // 循环添加新增字段
        if (item.selected) {
src/templates/zshare/formconfig.jsx
@@ -1908,6 +1908,7 @@
 * @param {*} subtable        // 是否为子表表单
 */
export function getModalForm (card, inputfields = [], tabfields = [], linkableFields, linksupFields, subtable = false) {
  let appType = sessionStorage.getItem('appType')
  let roleList = sessionStorage.getItem('sysRoles')
  if (roleList) {
    try {
@@ -2458,7 +2459,8 @@
      label: '名称宽度',
      initVal: card.labelwidth || 33.3,
      tooltip: '名称占据表单宽度的百分比。注:存在多列表单时,当前表单如果想要占据整行可参照以下比例,两列(16.2)、三列(10.5)、四列(7.7)',
      required: true
      required: true,
      forbid: appType === 'mob'
    },
    {
      type: 'text',
@@ -2521,7 +2523,8 @@
      label: '悬浮提示',
      tooltip: '鼠标悬浮于提示文字上方时,显示提示信息。',
      initVal: card.tooltip || '',
      required: false
      required: false,
      forbid: appType === 'mob'
    },
    {
      type: 'text',
@@ -2529,7 +2532,8 @@
      label: '底部提示',
      tooltip: '显示于表单底部。',
      initVal: card.extra || '',
      required: false
      required: false,
      forbid: appType === 'mob'
    },
    {
      type: 'text',
src/templates/zshare/modalform/index.jsx
@@ -422,7 +422,7 @@
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (!item.show) return
      if (!item.show || item.forbid) return null
      if (item.type === 'text') { // 文本搜索
        let rules = []