src/menu/components/form/normal-form/index.jsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/mob/components/formdragelement/card.jsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/mob/components/formdragelement/index.jsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/mob/components/formdragelement/index.scss | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/templates/sharecomponent/fieldscomponent/index.jsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/templates/zshare/formconfig.jsx | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
src/templates/zshare/modalform/index.jsx | ●●●●● 补丁 | 查看 | 原始文档 | 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 = []