New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Modal, Popover, Icon } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import SettingForm from './settingform' |
| | | |
| | | import Utils from '@/utils/utils.js' |
| | | import MKEmitter from '@/utils/events.js' |
| | | import './index.scss' |
| | | |
| | | const CardCellComponent = asyncComponent(() => import('@/menu/components/card/cardcellcomponent')) |
| | | const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) |
| | | |
| | | class CardBoxComponent extends Component { |
| | | static propTpyes = { |
| | | cards: PropTypes.object, // 卡片行配置信息 |
| | | card: PropTypes.object, // 卡片配置信息 |
| | | move: PropTypes.func, // 卡片移动 |
| | | deleteElement: PropTypes.func, // 卡片删除 |
| | | updateElement: PropTypes.func // 菜单配置更新 |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | card: null, // 卡片信息,包括正反面 |
| | | formlist: null, // 设置表单信息 |
| | | elements: null, // 编辑组 |
| | | visible: false, // 模态框控制 |
| | | settingVisible: false, |
| | | } |
| | | |
| | | /** |
| | | * @description 搜索条件初始化 |
| | | */ |
| | | UNSAFE_componentWillMount () { |
| | | const { card } = this.props |
| | | |
| | | this.setState({ |
| | | card: fromJS(card).toJS(), |
| | | elements: fromJS(card.elements).toJS(), |
| | | }) |
| | | } |
| | | |
| | | componentDidMount () { |
| | | MKEmitter.addListener('submitStyle', this.getStyle) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | const { cards } = this.props |
| | | |
| | | return !is(fromJS(cards), fromJS(nextProps.cards)) || !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('submitStyle', this.getStyle) |
| | | } |
| | | |
| | | getStyle = (comIds, style) => { |
| | | const { cards } = this.props |
| | | const { card } = this.state |
| | | |
| | | if (comIds.length !== 2 || comIds[0] !== cards.uuid || comIds[1] !== card.uuid) return |
| | | |
| | | let _card = fromJS(card).toJS() |
| | | _card.style = style |
| | | |
| | | this.setState({ |
| | | card: _card |
| | | }) |
| | | |
| | | this.props.updateElement(_card) |
| | | } |
| | | |
| | | updateCard = (elements) => { |
| | | const { card } = this.state |
| | | |
| | | let _card = {...card, elements: elements} |
| | | |
| | | this.setState({ |
| | | card: _card |
| | | }) |
| | | |
| | | this.props.updateElement(_card) |
| | | } |
| | | |
| | | addElement = () => { |
| | | const { cards } = this.props |
| | | const { card } = this.state |
| | | |
| | | let newcard = {} |
| | | newcard.uuid = Utils.getuuid() |
| | | newcard.focus = true |
| | | |
| | | newcard.eleType = 'text' |
| | | newcard.datatype = 'dynamic' |
| | | newcard.height = 1 |
| | | |
| | | // 注册事件-添加元素 |
| | | MKEmitter.emit('cardAddElement', [cards.uuid, card.uuid], newcard) |
| | | } |
| | | |
| | | addButton = () => { |
| | | const { cards } = this.props |
| | | const { card } = this.state |
| | | |
| | | let newcard = {} |
| | | newcard.uuid = Utils.getuuid() |
| | | newcard.focus = true |
| | | |
| | | newcard.eleType = 'button' |
| | | newcard.label = 'button' |
| | | newcard.sqlType = '' |
| | | newcard.Ot = 'requiredSgl' |
| | | newcard.OpenType = 'prompt' |
| | | newcard.icon = '' |
| | | newcard.class = 'primary' |
| | | newcard.intertype = 'system' |
| | | newcard.execSuccess = 'grid' |
| | | newcard.execError = 'never' |
| | | newcard.popClose = 'never' |
| | | newcard.errorTime = 10 |
| | | newcard.verify = null |
| | | newcard.show = 'link' |
| | | |
| | | // 注册事件-添加元素 |
| | | MKEmitter.emit('cardAddElement', [cards.uuid, card.uuid], newcard) |
| | | } |
| | | |
| | | changeStyle = () => { |
| | | const { cards } = this.props |
| | | const { card } = this.state |
| | | |
| | | let options = ['background', 'border', 'padding', 'margin', 'shadow'] |
| | | |
| | | MKEmitter.emit('changeStyle', [cards.uuid, card.uuid], options, fromJS(card.style).toJS()) |
| | | } |
| | | |
| | | settingSubmit = () => { |
| | | const { card } = this.state |
| | | |
| | | this.settingRef.handleConfirm().then(res => { |
| | | this.setState({ |
| | | settingVisible: false, |
| | | card: {...card, setting: res} |
| | | }) |
| | | |
| | | this.props.updateElement({...card, setting: res}) |
| | | }) |
| | | } |
| | | |
| | | clickComponent = (e) => { |
| | | if ((sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'propcard') && this.props.cards.subtype === 'propcard') { |
| | | e.stopPropagation() |
| | | MKEmitter.emit('clickComponent', this.state.card, this.props.cards, 'propcard') |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { cards } = this.props |
| | | const { card, elements, settingVisible, dict } = this.state |
| | | |
| | | let _style = {...card.style} |
| | | |
| | | if (_style.shadow) { |
| | | _style.boxShadow = '0 0 4px ' + _style.shadow |
| | | } |
| | | _style.height = cards.style.height |
| | | |
| | | return ( |
| | | <div className="card-item" style={_style} onClick={this.clickComponent} id={card.uuid}> |
| | | <CardCellComponent cards={cards} cardCell={card} side="front" elements={elements} updateElement={this.updateCard}/> |
| | | <div className="card-control"> |
| | | <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" /> |
| | | <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" /> |
| | | <Icon className="edit" title="编辑" type="edit" onClick={() => this.setState({settingVisible: true})} /> |
| | | <CopyComponent type="cardcell" card={card}/> |
| | | <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" /> |
| | | {cards.subtype === 'propcard' ? <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <Icon className="plus" title="左移" type="arrow-left" onClick={() => this.props.move(card, 'left')} /> |
| | | <Icon className="close" title="右移" type="arrow-right" onClick={() => this.props.move(card, 'right')} /> |
| | | </div> |
| | | } trigger="hover" getPopupContainer={() => document.getElementById(card.uuid + 'swap')}> |
| | | <Icon type="swap" id={card.uuid + 'swap'}/> |
| | | </Popover> : null} |
| | | {cards.subtype === 'propcard' ? <Icon className="close" title="删除卡片" type="delete" onClick={() => this.props.deleteElement(card)} /> : null} |
| | | </div> |
| | | } trigger="hover"> |
| | | <Icon type="tool" /> |
| | | </Popover> |
| | | </div> |
| | | <Modal |
| | | wrapClassName="popview-modal" |
| | | title={'卡片设置'} |
| | | visible={settingVisible} |
| | | width={700} |
| | | maskClosable={false} |
| | | okText={dict['model.submit']} |
| | | onOk={this.settingSubmit} |
| | | onCancel={() => { this.setState({ settingVisible: false }) }} |
| | | destroyOnClose |
| | | > |
| | | <SettingForm |
| | | dict={dict} |
| | | cards={cards} |
| | | setting={card.setting} |
| | | inputSubmit={this.settingSubmit} |
| | | wrappedComponentRef={(inst) => this.settingRef = inst} |
| | | /> |
| | | </Modal> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default CardBoxComponent |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Radio, Tooltip, Icon, Input, Cascader, Select } from 'antd' |
| | | |
| | | import './index.scss' |
| | | |
| | | const { TextArea } = Input |
| | | |
| | | class SettingForm extends Component { |
| | | static propTpyes = { |
| | | dict: PropTypes.object, // 字典项 |
| | | cards: PropTypes.object, // 卡片集 |
| | | setting: PropTypes.object, // 数据源配置 |
| | | inputSubmit: PropTypes.func // 回车事件 |
| | | } |
| | | |
| | | state = { |
| | | type: this.props.setting.type || 'simple', |
| | | click: this.props.setting.click || '', |
| | | isApp: sessionStorage.getItem('appType') === 'pc', |
| | | menulist: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount() { |
| | | const { isApp } = this.state |
| | | let menulist = null |
| | | |
| | | if (isApp) { |
| | | menulist = sessionStorage.getItem('appMenus') |
| | | } else { |
| | | menulist = sessionStorage.getItem('fstMenuList') |
| | | } |
| | | |
| | | if (menulist) { |
| | | try { |
| | | menulist = JSON.parse(menulist) |
| | | } catch { |
| | | menulist = [] |
| | | } |
| | | } else { |
| | | menulist = [] |
| | | } |
| | | |
| | | this.setState({menulist}) |
| | | } |
| | | |
| | | handleConfirm = () => { |
| | | // 表单提交时检查输入值是否正确 |
| | | return new Promise((resolve, reject) => { |
| | | this.props.form.validateFieldsAndScroll((err, values) => { |
| | | if (!err) { |
| | | resolve(values) |
| | | } else { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | handleSubmit = (e) => { |
| | | e.preventDefault() |
| | | |
| | | if (this.props.inputSubmit) { |
| | | this.props.inputSubmit() |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { setting, cards } = this.props |
| | | const { getFieldDecorator } = this.props.form |
| | | const { click, menulist, isApp } = this.state |
| | | |
| | | const formItemLayout = { |
| | | labelCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 8 } |
| | | }, |
| | | wrapperCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 16 } |
| | | } |
| | | } |
| | | |
| | | return ( |
| | | <div className="model-menu-setting-form"> |
| | | <Form {...formItemLayout}> |
| | | <Row gutter={24}> |
| | | {cards.subtype === 'propcard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="卡片点击时,向其他组件传递的BID值。"> |
| | | <Icon type="question-circle" /> |
| | | 主键值 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('primaryId', { |
| | | initialValue: setting.primaryId || '' |
| | | })(<Input placeholder="" autoComplete="off" onPressEnter={this.handleSubmit}/>)} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | <Col span={12}> |
| | | <Form.Item label="点击事件"> |
| | | {getFieldDecorator('click', { |
| | | initialValue: click |
| | | })( |
| | | <Radio.Group onChange={(e) => this.setState({click: e.target.value})}> |
| | | <Radio value="">无</Radio> |
| | | <Radio value="menu">菜单</Radio> |
| | | <Radio value="link">链接</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | {!isApp && click === 'menu' ? <Col span={12}> |
| | | <Form.Item label="菜单"> |
| | | {getFieldDecorator('menu', { |
| | | initialValue: setting.menu || [], |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.select'] + '菜单!' |
| | | } |
| | | ] |
| | | })( |
| | | <Cascader options={menulist} placeholder=""/> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {isApp && click === 'menu' ? <Col span={12}> |
| | | <Form.Item label="关联菜单"> |
| | | {getFieldDecorator('menu', { |
| | | initialValue: setting.menu || '', |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.select'] + '关联菜单!' |
| | | } |
| | | ] |
| | | })( |
| | | <Select |
| | | showSearch |
| | | filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} |
| | | > |
| | | {menulist.map(option => |
| | | <Select.Option key={option.MenuID} value={option.MenuID}>{option.MenuName}</Select.Option> |
| | | )} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {click === 'link' ? <Col span={24} className="textarea"> |
| | | <Form.Item label="链接"> |
| | | {getFieldDecorator('linkurl', { |
| | | initialValue: setting.linkurl || '', |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '链接!' |
| | | } |
| | | ] |
| | | })( <TextArea rows={2}/> )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {isApp ? <Col span={12}> |
| | | <Form.Item label="打开方式"> |
| | | {getFieldDecorator('open', { |
| | | initialValue: setting.open || 'blank' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="blank">新窗口</Radio> |
| | | <Radio value="self">当前窗口</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {click !== '' ? <Col span={12}> |
| | | <Form.Item label="参数拼接"> |
| | | {getFieldDecorator('joint', { |
| | | initialValue: setting.joint || 'true' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="true">是</Radio> |
| | | <Radio value="false">否</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | </Row> |
| | | </Form> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Form.create()(SettingForm) |
New file |
| | |
| | | .model-menu-setting-form { |
| | | position: relative; |
| | | |
| | | .anticon-question-circle { |
| | | color: #c49f47; |
| | | margin-right: 3px; |
| | | } |
| | | .ant-input-number { |
| | | width: 100%; |
| | | } |
| | | } |
New file |
| | |
| | | import React from 'react' |
| | | import { useDrag, useDrop } from 'react-dnd' |
| | | import { Icon, Select, DatePicker, Input, InputNumber, Button, Popover, Switch, Radio, Checkbox } from 'antd' |
| | | import moment from 'moment' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import './index.scss' |
| | | |
| | | const { MonthPicker } = DatePicker |
| | | const { TextArea } = Input |
| | | |
| | | const Editor = asyncComponent(() => import('@/components/editor')) |
| | | const ColorSketch = asyncComponent(() => import('@/mob/colorsketch')) |
| | | const CheckCard = asyncComponent(() => import('@/templates/modalconfig/checkCard')) |
| | | |
| | | const Card = ({ id, card, cols, 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 labelCol = 'ant-col-sm-8' |
| | | let wrapCol = 'ant-col-sm-16' |
| | | let isEntireLine = false |
| | | |
| | | if (card.entireLine === 'true' || ['textarea', 'hint', 'checkcard', 'brafteditor'].includes(card.type)) { |
| | | isEntireLine = true |
| | | } |
| | | |
| | | if (isEntireLine) { |
| | | if (cols === '2') { |
| | | labelCol = 'ant-col-sm-4' |
| | | wrapCol = 'ant-col-sm-20' |
| | | } else if (cols === '3') { |
| | | labelCol = 'ant-col-cuslabel' |
| | | wrapCol = 'ant-col-cuswrap' |
| | | } else if (cols === '4') { |
| | | labelCol = 'ant-col-sm-2' |
| | | wrapCol = 'ant-col-sm-22' |
| | | } |
| | | if (card.hidelabel === 'true') { |
| | | wrapCol = 'ant-col-sm-24' |
| | | } |
| | | } |
| | | |
| | | let formItem = null |
| | | if (card.type === 'text') { |
| | | formItem = (<Input style={{marginTop: '4px'}} value={card.initval} />) |
| | | } else if (card.type === 'number') { |
| | | formItem = (<InputNumber value={card.initval} precision={card.decimal} />) |
| | | } else if (card.type === 'multiselect' || card.type === 'select' || card.type === 'link') { |
| | | formItem = (<Select value={selectval}></Select>) |
| | | } 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 = (<TextArea value={card.initval} autoSize={{ minRows: 2, maxRows: 6 }} />) |
| | | } 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 = (<Input style={{marginTop: '4px'}} value={card.linkfield} />) |
| | | } else if (card.type === 'linkMain') { |
| | | formItem = (<Input style={{marginTop: '4px'}} />) |
| | | } 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)'}}>{card.message}</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))}> |
| | | {<div className="ant-row ant-form-item"> |
| | | {card.hidelabel !== 'true' ? <div className={'ant-col ant-form-item-label ant-col-xs-24 ' + labelCol}> |
| | | {card.label ? <label className={card.required === 'true' ? 'required' : ''}>{card.tooltip ? |
| | | <Icon type="question-circle" /> : null} |
| | | {card.label}</label> : null} |
| | | </div> : null} |
| | | <div className={'ant-col ant-form-item-control-wrapper ant-col-xs-24 ' + wrapCol}> |
| | | {formItem} |
| | | {showField ? card.field : ''} |
| | | </div> |
| | | </div>} |
| | | </div> |
| | | </div> |
| | | </Popover> |
| | | ) |
| | | } |
| | | export default Card |
New file |
| | |
| | | import React, { useState } from 'react' |
| | | import { useDrop } from 'react-dnd' |
| | | import { is, fromJS } from 'immutable' |
| | | import update from 'immutability-helper' |
| | | import { Col } from 'antd' |
| | | import Utils from '@/utils/utils.js' |
| | | import Card from './card' |
| | | import './index.scss' |
| | | |
| | | const Container = ({list, group, 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]] }) |
| | | |
| | | if (!group) { |
| | | handleList(_cards) |
| | | } else { |
| | | handleList(_cards, group) |
| | | } |
| | | } |
| | | |
| | | 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) |
| | | 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) |
| | | |
| | | if (!group) { |
| | | handleList(_cards, null, null, _card) |
| | | } else { |
| | | handleList(_cards, group, null, _card) |
| | | } |
| | | } |
| | | |
| | | const [, drop] = useDrop({ |
| | | accept: 'form', |
| | | drop(item) { |
| | | if (item.hasOwnProperty('originalIndex') && group) { |
| | | const { card } = findCard(item.id) |
| | | if (!card) { |
| | | handleList(cards, group, item.id) |
| | | } |
| | | } |
| | | 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) |
| | | |
| | | if (!group) { |
| | | handleList(_cards, null, null, newcard) |
| | | } else { |
| | | handleList(_cards, group, null, newcard) |
| | | } |
| | | } |
| | | }) |
| | | |
| | | let _cols = 24 / (setting.cols || 2) |
| | | |
| | | return ( |
| | | <div ref={drop} className="ant-row modal-fields-row"> |
| | | {cards.map(card => { |
| | | let isEntireLine = false |
| | | |
| | | if (card.entireLine === 'true' || ['textarea', 'hint', 'checkcard', 'brafteditor'].includes(card.type)) { |
| | | isEntireLine = true |
| | | } |
| | | |
| | | return <Col key={card.uuid} className={isEntireLine ? 'textarea' + setting.cols : ''} span={isEntireLine ? 24 : _cols}> |
| | | <Card |
| | | id={card.uuid} |
| | | cols={setting.cols} |
| | | card={card} |
| | | showField={showField} |
| | | moveCard={moveCard} |
| | | editCard={editCard} |
| | | closeCard={closeCard} |
| | | copyCard={copyCard} |
| | | findCard={findCard} |
| | | /> |
| | | </Col> |
| | | })} |
| | | {cards.length === 0 && |
| | | <div className="modal-drawarea-placeholder"> |
| | | {placeholder} |
| | | </div> |
| | | } |
| | | </div> |
| | | ) |
| | | } |
| | | export default Container |
New file |
| | |
| | | .modal-source-item { |
| | | display: block; |
| | | box-shadow: 0px 0px 2px #bcbcbc; |
| | | padding: 0.4rem 0.7rem; |
| | | background-color: white; |
| | | margin: 0px 0px 10px; |
| | | cursor: move; |
| | | border-radius: 4px; |
| | | } |
| | | .modal-drawarea-placeholder { |
| | | width: 100%; |
| | | line-height: 65px; |
| | | text-align: center; |
| | | color: #bcbcbc; |
| | | } |
| | | .modal-fields-row { |
| | | padding-bottom: 35px; |
| | | .ant-col { |
| | | padding-left: 12px; |
| | | padding-right: 12px; |
| | | } |
| | | >.ant-col { |
| | | display: inline-block; |
| | | float: none; |
| | | vertical-align: top; |
| | | } |
| | | } |
New file |
| | |
| | | import React from 'react' |
| | | import { useDrag } from 'react-dnd' |
| | | import './index.scss' |
| | | |
| | | const SourceElement = ({content}) => { |
| | | const [, drag] = useDrag({ item: content }) |
| | | return ( |
| | | <div ref={drag} className="modal-source-item"> |
| | | {content.label} |
| | | </div> |
| | | ) |
| | | } |
| | | export default SourceElement |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Icon, Popover, Modal, Carousel } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | |
| | | import MKEmitter from '@/utils/events.js' |
| | | import Utils from '@/utils/utils.js' |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import './index.scss' |
| | | |
| | | const SettingComponent = asyncIconComponent(() => import('@/menu/datasource')) |
| | | const WrapComponent = asyncIconComponent(() => import('@/menu/components/form/wrapsetting')) |
| | | const CardComponent = asyncComponent(() => import('../dragelement')) |
| | | const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) |
| | | const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent')) |
| | | const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent')) |
| | | |
| | | const { confirm } = Modal |
| | | |
| | | class PropCardEditComponent extends Component { |
| | | static propTpyes = { |
| | | card: PropTypes.object, |
| | | deletecomponent: PropTypes.func, |
| | | updateConfig: PropTypes.func, |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | card: null, |
| | | back: false |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { card } = this.props |
| | | |
| | | if (card.isNew) { |
| | | let _card = { |
| | | uuid: card.uuid, |
| | | type: card.type, |
| | | floor: card.floor, |
| | | tabId: card.tabId || '', |
| | | parentId: card.parentId || '', |
| | | format: 'object', // 组件属性 - 数据格式 |
| | | pageable: false, // 组件属性 - 是否可分页 |
| | | switchable: false, // 组件属性 - 数据是否可切换 |
| | | dataName: card.dataName || '', |
| | | width: card.width || 24, |
| | | name: card.name, |
| | | subtype: card.subtype, |
| | | setting: { }, |
| | | wrap: { name: card.name, width: card.width || 24, datatype: 'static' }, |
| | | style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' }, |
| | | columns: [], |
| | | scripts: [], |
| | | subcards: [{ |
| | | uuid: Utils.getuuid(), |
| | | setting: {}, |
| | | style: {}, |
| | | fields: [], |
| | | }], |
| | | } |
| | | |
| | | if (card.config) { |
| | | let config = fromJS(card.config).toJS() |
| | | |
| | | _card.wrap = config.wrap |
| | | _card.wrap.name = card.name |
| | | _card.style = config.style |
| | | |
| | | _card.subcards = config.subcards.map(scard => { |
| | | scard.uuid = Utils.getuuid() |
| | | scard.fields = scard.fields.map(elem => { |
| | | elem.uuid = Utils.getuuid() |
| | | return elem |
| | | }) |
| | | return scard |
| | | }) |
| | | } |
| | | this.setState({ |
| | | card: _card |
| | | }) |
| | | this.props.updateConfig(_card) |
| | | } else { |
| | | this.setState({ |
| | | card: fromJS(card).toJS() |
| | | }) |
| | | } |
| | | } |
| | | |
| | | componentDidMount () { |
| | | MKEmitter.addListener('submitStyle', this.getStyle) |
| | | MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.state), fromJS(nextState)) || (!this.props.menu && nextProps.menu) |
| | | } |
| | | |
| | | /** |
| | | * @description 组件销毁,清除state更新,清除快捷键设置 |
| | | */ |
| | | componentWillUnmount () { |
| | | this.setState = () => { |
| | | return |
| | | } |
| | | MKEmitter.removeListener('submitStyle', this.getStyle) |
| | | MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle) |
| | | } |
| | | |
| | | updateComponentStyle = (parentId, keys, style) => { |
| | | const { card } = this.state |
| | | |
| | | if (card.uuid !== parentId) return |
| | | |
| | | let subcards = card.subcards.map(item => { |
| | | if (keys.includes(item.uuid)) { |
| | | item.style = {...item.style, ...style} |
| | | } |
| | | return item |
| | | }) |
| | | |
| | | this.setState({card: {...card, subcards: []}}, () => { |
| | | this.updateComponent({...card, subcards: subcards}) |
| | | }) |
| | | } |
| | | |
| | | /** |
| | | * @description 卡片行外层信息更新(数据源,样式等) |
| | | */ |
| | | updateComponent = (component) => { |
| | | this.setState({ |
| | | card: component |
| | | }) |
| | | |
| | | component.width = component.wrap.width |
| | | component.name = component.wrap.name |
| | | |
| | | this.props.updateConfig(component) |
| | | } |
| | | |
| | | /** |
| | | * @description 单个卡片信息更新 |
| | | */ |
| | | updateCard = (cell) => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | |
| | | card.subcards = card.subcards.map(item => { |
| | | if (item.uuid === cell.uuid) return cell |
| | | return item |
| | | }) |
| | | |
| | | this.setState({card}) |
| | | |
| | | this.props.updateConfig(card) |
| | | } |
| | | |
| | | /** |
| | | * @description 单个卡片信息更新 |
| | | */ |
| | | deleteCard = (cell) => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | let _this = this |
| | | |
| | | confirm({ |
| | | content: '确定删除表单吗?', |
| | | onOk() { |
| | | card.subcards = card.subcards.filter(item => item.uuid !== cell.uuid) |
| | | |
| | | let uuids = [] |
| | | cell.elements && cell.elements.forEach(c => { |
| | | if (c.eleType === 'button') { |
| | | uuids.push(c.uuid) |
| | | } |
| | | }) |
| | | MKEmitter.emit('delButtons', uuids) |
| | | |
| | | _this.setState({card}) |
| | | _this.props.updateConfig(card) |
| | | }, |
| | | onCancel() {} |
| | | }) |
| | | } |
| | | |
| | | changeStyle = () => { |
| | | const { card } = this.state |
| | | |
| | | MKEmitter.emit('changeStyle', [card.uuid], ['height', 'background', 'border', 'padding', 'margin'], card.style) |
| | | } |
| | | |
| | | getStyle = (comIds, style) => { |
| | | const { card } = this.state |
| | | |
| | | if (comIds.length !== 1 || comIds[0] !== card.uuid) return |
| | | |
| | | let _card = {...card, style} |
| | | |
| | | this.setState({ |
| | | card: _card |
| | | }) |
| | | |
| | | this.props.updateConfig(_card) |
| | | } |
| | | |
| | | addCard = () => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | |
| | | let newcard = { |
| | | uuid: Utils.getuuid(), |
| | | setting: {}, |
| | | style: {}, |
| | | elements: [], |
| | | } |
| | | |
| | | if (card.subcards.length > 0) { |
| | | newcard = fromJS(card.subcards.slice(-1)[0]).toJS() |
| | | newcard.uuid = Utils.getuuid() |
| | | newcard.elements = newcard.elements.map(elem => { |
| | | elem.uuid = Utils.getuuid() |
| | | return elem |
| | | }) |
| | | } |
| | | |
| | | card.subcards.push(newcard) |
| | | |
| | | this.setState({card}) |
| | | this.props.updateConfig(card) |
| | | } |
| | | |
| | | move = (item, direction) => { |
| | | let card = fromJS(this.state.card).toJS() |
| | | |
| | | let dragIndex = card.subcards.findIndex(c => c.uuid === item.uuid) |
| | | let hoverIndex = null |
| | | |
| | | if (direction === 'left') { |
| | | hoverIndex = dragIndex - 1 |
| | | } else { |
| | | hoverIndex = dragIndex + 1 |
| | | } |
| | | |
| | | if (hoverIndex === -1 || hoverIndex === card.subcards.length) return |
| | | |
| | | card.subcards.splice(hoverIndex, 0, ...card.subcards.splice(dragIndex, 1)) |
| | | |
| | | this.setState({card: {...card, subcards: []}}, () => { |
| | | this.setState({card}) |
| | | }) |
| | | this.props.updateConfig(card) |
| | | } |
| | | |
| | | clickComponent = (e) => { |
| | | if (sessionStorage.getItem('style-control') === 'true' || sessionStorage.getItem('style-control') === 'component') { |
| | | e.stopPropagation() |
| | | MKEmitter.emit('clickComponent', this.state.card) |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { card } = this.state |
| | | |
| | | return ( |
| | | <div className="menu-normal-form-edit-box" style={{...card.style}} onClick={this.clickComponent} id={card.uuid}> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <Icon className="plus" title="添加分组" onClick={this.addCard} type="plus" /> |
| | | <WrapComponent config={card} updateConfig={this.updateComponent} /> |
| | | <CopyComponent type="propcard" card={card}/> |
| | | <PasteComponent config={card} options={['cardcell']} updateConfig={this.updateComponent} /> |
| | | <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" /> |
| | | <UserComponent config={card}/> |
| | | <Icon className="close" title="删除组件" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} /> |
| | | {card.wrap.datatype !== 'static' ? <SettingComponent config={card} updateConfig={this.updateComponent} /> : null} |
| | | {card.wrap.datatype === 'static' ? <Icon style={{color: '#eeeeee', cursor: 'not-allowed'}} type="setting"/> : null} |
| | | </div> |
| | | } trigger="hover"> |
| | | <Icon type="tool" /> |
| | | </Popover> |
| | | {card.subcards.length > 0 ? <Carousel dotPosition={card.wrap.dotPosition || 'bottom'} effect={card.wrap.effect || 'scrollx'}> |
| | | {card.subcards.map((subcard) => (<CardComponent key={subcard.uuid} cards={card} card={subcard} move={this.move} updateElement={this.updateCard} deleteElement={this.deleteCard}/>))} |
| | | </Carousel> : null} |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | const mapStateToProps = (state) => { |
| | | return { |
| | | menu: state.customMenu |
| | | } |
| | | } |
| | | |
| | | const mapDispatchToProps = () => { |
| | | return {} |
| | | } |
| | | |
| | | export default connect(mapStateToProps, mapDispatchToProps)(PropCardEditComponent) |
New file |
| | |
| | | .menu-normal-form-edit-box { |
| | | position: relative; |
| | | box-sizing: border-box; |
| | | background: #ffffff; |
| | | background-position: center center; |
| | | background-repeat: no-repeat; |
| | | background-size: cover; |
| | | min-height: 30px; |
| | | |
| | | .card-control { |
| | | position: absolute; |
| | | top: 0px; |
| | | left: 0px; |
| | | .anticon-tool { |
| | | right: auto; |
| | | left: 1px; |
| | | padding: 1px; |
| | | } |
| | | } |
| | | .anticon-tool { |
| | | position: absolute; |
| | | z-index: 2; |
| | | font-size: 16px; |
| | | right: 1px; |
| | | top: 1px; |
| | | cursor: pointer; |
| | | padding: 5px; |
| | | background: rgba(255, 255, 255, 0.55); |
| | | } |
| | | |
| | | .card-item { |
| | | overflow: hidden; |
| | | position: relative; |
| | | background-position: center center; |
| | | background-repeat: no-repeat; |
| | | background-size: cover; |
| | | min-height: 20px; |
| | | height: 100%; |
| | | } |
| | | .ant-carousel:not(.ant-carousel-vertical) { |
| | | .slick-dots li button { |
| | | height: 8px; |
| | | } |
| | | } |
| | | .ant-carousel.ant-carousel-vertical { |
| | | .slick-dots li button { |
| | | width: 8px; |
| | | } |
| | | } |
| | | .ant-carousel { |
| | | .slick-dots li button { |
| | | background: #1890ff; |
| | | } |
| | | } |
| | | |
| | | .card-item:hover { |
| | | box-shadow: 0px 0px 2px #1890ff; |
| | | } |
| | | |
| | | .model-menu-card-cell-list .card-detail-row > .anticon-plus { |
| | | position: absolute; |
| | | right: -30px; |
| | | font-size: 16px; |
| | | } |
| | | .model-menu-action-list { |
| | | line-height: 40px; |
| | | .ant-row > .anticon-plus { |
| | | position: absolute; |
| | | right: -30px; |
| | | font-size: 16px; |
| | | } |
| | | } |
| | | .card-add-button { |
| | | text-align: right; |
| | | clear: left; |
| | | .anticon-plus { |
| | | font-size: 20px; |
| | | color: #26C281; |
| | | padding: 5px; |
| | | margin-right: 10px; |
| | | } |
| | | } |
| | | } |
| | | .menu-normal-form-edit-box::after { |
| | | display: block; |
| | | content: ' '; |
| | | clear: both; |
| | | } |
| | | .menu-normal-form-edit-box:hover { |
| | | z-index: 1; |
| | | box-shadow: 0px 0px 4px #1890ff; |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Icon, Modal } from 'antd' |
| | | |
| | | import zhCN from '@/locales/zh-CN/model.js' |
| | | import enUS from '@/locales/en-US/model.js' |
| | | import SettingForm from './settingform' |
| | | import './index.scss' |
| | | |
| | | class DataSource extends Component { |
| | | static propTpyes = { |
| | | config: PropTypes.any, |
| | | updateConfig: PropTypes.func |
| | | } |
| | | |
| | | state = { |
| | | dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, |
| | | visible: false, |
| | | wrap: null |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | const { config } = this.props |
| | | |
| | | this.setState({wrap: fromJS(config.wrap).toJS()}) |
| | | } |
| | | |
| | | shouldComponentUpdate (nextProps, nextState) { |
| | | return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState)) |
| | | } |
| | | |
| | | editDataSource = () => { |
| | | this.setState({ |
| | | visible: true |
| | | }) |
| | | } |
| | | |
| | | verifySubmit = () => { |
| | | const { config } = this.props |
| | | |
| | | this.verifyRef.handleConfirm().then(res => { |
| | | |
| | | this.setState({ |
| | | wrap: res, |
| | | visible: false |
| | | }) |
| | | this.props.updateConfig({...config, wrap: res}) |
| | | }) |
| | | } |
| | | |
| | | render () { |
| | | const { config } = this.props |
| | | const { visible, dict, wrap } = this.state |
| | | |
| | | return ( |
| | | <div className="model-menu-setting-wrap"> |
| | | <Icon type="edit" title="编辑" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="popview-modal" |
| | | title={config.type === 'table' ? '表格设置' : '卡片设置'} |
| | | visible={visible} |
| | | width={800} |
| | | maskClosable={false} |
| | | okText={dict['model.submit']} |
| | | onOk={this.verifySubmit} |
| | | onCancel={() => { this.setState({ visible: false }) }} |
| | | destroyOnClose |
| | | > |
| | | <SettingForm |
| | | dict={dict} |
| | | wrap={wrap} |
| | | config={config} |
| | | inputSubmit={this.verifySubmit} |
| | | wrappedComponentRef={(inst) => this.verifyRef = inst} |
| | | /> |
| | | </Modal> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default DataSource |
New file |
| | |
| | | .model-menu-setting-wrap { |
| | | display: inline-block; |
| | | |
| | | >.anticon-edit { |
| | | color: #1890ff; |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select } from 'antd' |
| | | |
| | | import './index.scss' |
| | | |
| | | class SettingForm extends Component { |
| | | static propTpyes = { |
| | | dict: PropTypes.object, // 字典项 |
| | | config: PropTypes.object, // 卡片行信息 |
| | | wrap: PropTypes.object, // 数据源配置 |
| | | inputSubmit: PropTypes.func // 回车事件 |
| | | } |
| | | |
| | | state = { |
| | | roleList: [] |
| | | } |
| | | |
| | | UNSAFE_componentWillMount () { |
| | | let roleList = sessionStorage.getItem('sysRoles') |
| | | if (roleList) { |
| | | try { |
| | | roleList = JSON.parse(roleList) |
| | | } catch { |
| | | roleList = [] |
| | | } |
| | | } else { |
| | | roleList = [] |
| | | } |
| | | |
| | | this.setState({roleList}) |
| | | } |
| | | |
| | | handleConfirm = () => { |
| | | // 表单提交时检查输入值是否正确 |
| | | return new Promise((resolve, reject) => { |
| | | this.props.form.validateFieldsAndScroll((err, values) => { |
| | | if (!err) { |
| | | resolve(values) |
| | | } else { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | handleSubmit = (e) => { |
| | | e.preventDefault() |
| | | |
| | | if (this.props.inputSubmit) { |
| | | this.props.inputSubmit() |
| | | } |
| | | } |
| | | |
| | | render() { |
| | | const { wrap, config } = this.props |
| | | const { getFieldDecorator } = this.props.form |
| | | const { roleList } = this.state |
| | | |
| | | const formItemLayout = { |
| | | labelCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 8 } |
| | | }, |
| | | wrapperCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 16 } |
| | | } |
| | | } |
| | | |
| | | return ( |
| | | <div className="model-menu-setting-form"> |
| | | <Form {...formItemLayout}> |
| | | <Row gutter={24}> |
| | | <Col span={12}> |
| | | <Form.Item label="标题"> |
| | | {getFieldDecorator('title', { |
| | | initialValue: wrap.title || '' |
| | | })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="用于组件间的区分。"> |
| | | <Icon type="question-circle" /> |
| | | 组件名称 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('name', { |
| | | initialValue: wrap.name, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '组件名称!' |
| | | } |
| | | ] |
| | | })(<Input placeholder={''} autoComplete="off" onPressEnter={this.handleSubmit} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="栅格布局,每行等分为24列。"> |
| | | <Icon type="question-circle" /> |
| | | 宽度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('width', { |
| | | initialValue: wrap.width || 24, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '宽度!' |
| | | } |
| | | ] |
| | | })(<InputNumber min={1} max={24} precision={0} onPressEnter={this.handleSubmit} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | {config.subtype === 'propcard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="选择静态值,无需配置数据源。"> |
| | | <Icon type="question-circle" /> |
| | | 数据来源 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('datatype', { |
| | | initialValue: wrap.datatype || 'dynamic' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="dynamic">动态</Radio> |
| | | <Radio value="static">静态</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype === 'datacard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="数据源中选择分页时有效。"> |
| | | <Icon type="question-circle" /> |
| | | 分页风格 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('pagestyle', { |
| | | initialValue: wrap.pagestyle || 'page' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="page">页码</Radio> |
| | | <Radio value="switch">左右切换</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype !== 'tablecard' ? <Col span={12}> |
| | | <Form.Item label="卡片属性"> |
| | | {getFieldDecorator('cardType', { |
| | | initialValue: wrap.cardType || '' |
| | | })( |
| | | <Radio.Group style={{whiteSpace: 'nowrap'}}> |
| | | <Radio key="" value=""> 不可选 </Radio> |
| | | <Radio key="radio" value={'radio'}> 单选 </Radio> |
| | | {config.subtype !== 'propcard' ? <Radio key="checkbox" value={'checkbox'}> 多选 </Radio> : null} |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype !== 'tablecard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="设置为居中对齐或右对齐,只在卡片为1行时有效。"> |
| | | <Icon type="question-circle" /> |
| | | 卡片排列 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('cardFloat', { |
| | | initialValue: wrap.cardFloat || 'left' |
| | | })( |
| | | <Radio.Group style={{whiteSpace: 'nowrap'}}> |
| | | <Radio key="left" value="left"> 左对齐 </Radio> |
| | | <Radio key="center" value="center"> 居中 </Radio> |
| | | <Radio key="right" value="right"> 右对齐 </Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype !== 'tablecard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="鼠标悬浮于卡片上方时,卡片放大1.05倍。"> |
| | | <Icon type="question-circle" /> |
| | | 卡片放大 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('scale', { |
| | | initialValue: wrap.scale || 'false' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio key="false" value="false"> 否 </Radio> |
| | | <Radio key="true" value="true"> 是 </Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype === 'tablecard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="表格高度,超出时滚动,高度为空时根据内容自适应。"> |
| | | <Icon type="question-circle" /> |
| | | 高度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('height', { |
| | | initialValue: wrap.height |
| | | })(<InputNumber min={100} max={2000} precision={0} onPressEnter={this.handleSubmit} />)} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.subtype === 'propcard' ? <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="选择类型为《页眉/页脚》时,打印的每页里都会带有该组件。"> |
| | | <Icon type="question-circle" /> |
| | | 组件类型 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('printType', { |
| | | initialValue: wrap.printType || 'content' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="content">内容</Radio> |
| | | <Radio value="headerOrfooter">页眉/页脚</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | <Col span={12}> |
| | | <Form.Item label="黑名单"> |
| | | {getFieldDecorator('blacklist', { |
| | | initialValue: wrap.blacklist || [] |
| | | })( |
| | | <Select |
| | | showSearch |
| | | mode="multiple" |
| | | filterOption={(input, option) => option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0} |
| | | > |
| | | {roleList.map(option => |
| | | <Select.Option key={option.uuid} value={option.value}>{option.text}</Select.Option> |
| | | )} |
| | | </Select> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | </Row> |
| | | </Form> |
| | | </div> |
| | | ) |
| | | } |
| | | } |
| | | |
| | | export default Form.create()(SettingForm) |
New file |
| | |
| | | .model-menu-setting-form { |
| | | position: relative; |
| | | |
| | | .anticon-question-circle { |
| | | color: #c49f47; |
| | | margin-right: 3px; |
| | | } |
| | | .ant-input-number { |
| | | width: 100%; |
| | | } |
| | | } |
| | |
| | | const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card')) |
| | | const TableCard = asyncComponent(() => import('@/menu/components/card/table-card')) |
| | | const NormalTable = asyncComponent(() => import('@/menu/components/table/normal-table')) |
| | | const NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form')) |
| | | const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group')) |
| | | const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor')) |
| | | const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox')) |
| | |
| | | return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'pie') { |
| | | return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'form') { |
| | | return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'tabs') { |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'card' && card.subtype === 'datacard') { |
| | |
| | | editor: '富文本', |
| | | code: '自定义', |
| | | carousel: '轮播', |
| | | form: '表单', |
| | | card: '卡片' |
| | | } |
| | | let i = 1 |
| | |
| | | if (_config.groups.length > 0) { |
| | | _config.groups.forEach(group => { |
| | | group.sublist = group.sublist.map(item => { |
| | | if (item.uuid !== res.uuid && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | fieldrepet = true |
| | | } else if (item.uuid !== res.uuid && item.label === res.label) { |
| | | labelrepet = true |
| | |
| | | }) |
| | | } else { |
| | | _config.fields = _config.fields.map(item => { |
| | | if (item.uuid !== res.uuid && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | fieldrepet = true |
| | | } else if (item.uuid !== res.uuid && item.label === res.label) { |
| | | labelrepet = true |
| | |
| | | width: 100%; |
| | | margin-top: 4px; |
| | | } |
| | | .normal-braft-editor { |
| | | border: 1px solid #d9d9d9; |
| | | border-radius: 4px; |
| | | } |
| | | } |
| | | .ant-form-item-control-wrapper::after { |
| | | content: ''; |
| | |
| | | import Mainsearch from '@/assets/mobimg/mainsearch.png' |
| | | import Carousel from '@/assets/mobimg/carousel.png' |
| | | import Carousel1 from '@/assets/mobimg/carousel1.png' |
| | | import form from '@/assets/mobimg/form.png' |
| | | |
| | | // 组件配置信息 |
| | | export const menuOptions = [ |
| | |
| | | { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '搜索条件', width: 24, forbid: ['billPrint'] }, |
| | | { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '数据卡', width: 24 }, |
| | | { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '属性卡', width: 24 }, |
| | | { type: 'menu', url: form, component: 'form', subtype: 'form', title: '表单', width: 24 }, |
| | | { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '轮播-动态数据', width: 24, forbid: ['billPrint'] }, |
| | | { type: 'menu', url: Carousel1, component: 'carousel', subtype: 'propcard', title: '轮播-静态数据', width: 24, forbid: ['billPrint'] }, |
| | | { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '常用表', width: 24 }, |
| | |
| | | render() { |
| | | const { cols } = this.state |
| | | const formItemLayout = { |
| | | labelCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 8 } |
| | | }, |
| | | wrapperCol: { |
| | | xs: { span: 24 }, |
| | | sm: { span: 16 } |
| | | } |
| | | // labelCol: { |
| | | // xs: { span: 24 }, |
| | | // sm: { span: 8 } |
| | | // }, |
| | | // wrapperCol: { |
| | | // xs: { span: 24 }, |
| | | // sm: { span: 16 } |
| | | // } |
| | | } |
| | | |
| | | return ( |
| | |
| | | if (_ismutil && group.sublist.length === 0) { |
| | | _config.enabled = false |
| | | } |
| | | let arr = group.sublist.filter(item => item.field.toLowerCase() === _primary) |
| | | let arr = group.sublist.filter(item => item.field && item.field.toLowerCase() === _primary) |
| | | |
| | | if (arr.length > 0) { |
| | | _config.enabled = false |
| | |
| | | let primaryrepeat = false |
| | | |
| | | config.groups.forEach(group => { |
| | | let arr = group.sublist.filter(item => item.field.toLowerCase() === _primary) |
| | | let arr = group.sublist.filter(item => item.field && item.field.toLowerCase() === _primary) |
| | | |
| | | if (arr.length > 0) { |
| | | primaryrepeat = true |
| | |
| | | if (_config.groups.length > 0) { |
| | | _config.groups.forEach(group => { |
| | | group.sublist = group.sublist.map(item => { |
| | | if (item.uuid !== res.uuid && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | fieldrepet = true |
| | | } else if (item.uuid !== res.uuid && item.label === res.label) { |
| | | labelrepet = true |
| | |
| | | }) |
| | | } else { |
| | | _config.fields = _config.fields.map(item => { |
| | | if (item.uuid !== res.uuid && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | if (item.uuid !== res.uuid && res.field && item.field && item.field.toLowerCase() === res.field.toLowerCase()) { |
| | | fieldrepet = true |
| | | } else if (item.uuid !== res.uuid && item.label === res.label) { |
| | | labelrepet = true |
| | |
| | | if (config.groups.length > 1) { |
| | | config.groups.forEach(group => { |
| | | group.sublist.forEach(item => { |
| | | if (columns.has(item.field.toLowerCase())) { |
| | | if (item.field && columns.has(item.field.toLowerCase())) { |
| | | let _datatype = columns.get(item.field.toLowerCase()).datatype |
| | | columns.set(item.field.toLowerCase(), {...item, selected: true, datatype: _datatype}) |
| | | } |
| | |
| | | }) |
| | | } else { |
| | | config.fields.forEach(item => { |
| | | if (columns.has(item.field.toLowerCase())) { |
| | | if (item.field && columns.has(item.field.toLowerCase())) { |
| | | let _datatype = columns.get(item.field.toLowerCase()).datatype |
| | | columns.set(item.field.toLowerCase(), {...item, selected: true, datatype: _datatype}) |
| | | } |
| | |
| | | config.groups.forEach(group => { |
| | | let _items = [] |
| | | group.sublist.forEach(item => { |
| | | if (columnsMap.has(item.field.toLowerCase())) { |
| | | if (item.field && columnsMap.has(item.field.toLowerCase())) { |
| | | let cell = columnsMap.get(item.field.toLowerCase()) |
| | | |
| | | if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加 |
| | |
| | | config.groups[config.groups.length - 1].sublist = [...config.groups.slice(-1)[0].sublist, ..._additems] |
| | | } else { |
| | | config.fields.forEach(item => { |
| | | if (columnsMap.has(item.field.toLowerCase())) { |
| | | if (item.field && columnsMap.has(item.field.toLowerCase())) { |
| | | let cell = columnsMap.get(item.field.toLowerCase()) |
| | | |
| | | if (cell.selected && cell.type === item.type) { // 数据选择状态及类型未修改时,直接添加 |
| | |
| | | if (_config.groups.length > 0) { |
| | | _config.groups.forEach(group => { |
| | | group.sublist.forEach(item => { |
| | | fields.push(item.field.toLowerCase()) |
| | | item.field && fields.push(item.field.toLowerCase()) |
| | | labels.push(item.label) |
| | | }) |
| | | if (group.default) { |
| | |
| | | }) |
| | | } else { |
| | | _config.fields.forEach(item => { |
| | | fields.push(item.field.toLowerCase()) |
| | | item.field && fields.push(item.field.toLowerCase()) |
| | | labels.push(item.label) |
| | | }) |
| | | _config.fields.push(res) |
| | | } |
| | | |
| | | if (fields.includes(res.field.toLowerCase())) { |
| | | if (res.field && fields.includes(res.field.toLowerCase())) { |
| | | notification.warning({ |
| | | top: 92, |
| | | message: '字段已存在!', |