| | |
| | | .mk-icon.mk-orange, .mk-icon.mk-border-orange { |
| | | color: orange; |
| | | } |
| | | |
| | | // 链接颜色 |
| | | .mk-link, .mk-link:hover, .mk-link:active, .mk-link:focus { |
| | | background: transparent; |
| | | .anticon { |
| | | margin-left: 5px; |
| | | } |
| | | } |
| | | .mk-link.mk-gray { |
| | | color: #666; |
| | | } |
| | | .mk-link.mk-primary, .mk-link.mk-border-primary { |
| | | color: #1890ff; |
| | | } |
| | | .mk-link.mk-default, .mk-link.mk-dashed { |
| | | color: rgba(0, 0, 0, 0.65); |
| | | } |
| | | .mk-link.mk-danger, .mk-link.mk-red, .mk-link.mk-border-danger { |
| | | color: #ff4d4f; |
| | | } |
| | | .mk-link.mk-green, .mk-link.mk-border-green { |
| | | color: #26C281; |
| | | } |
| | | .mk-link.mk-dgreen, .mk-link.mk-border-dgreen { |
| | | color: #32c5d2; |
| | | } |
| | | .mk-link.mk-purple, .mk-link.mk-border-purple { |
| | | color: #8E44AD; |
| | | } |
| | | .mk-link.mk-yellow, .mk-link.mk-border-yellow { |
| | | color: #c49f47; |
| | | } |
| | | .mk-link.mk-orange, .mk-link.mk-border-orange { |
| | | color: orange; |
| | | } |
| | | } |
| | |
| | | .popview-modal { |
| | | .ant-modal-body { |
| | | min-height: 300px; |
| | | max-height: calc(100vh - 160px); |
| | | max-height: calc(100vh - 190px); |
| | | overflow-y: auto; |
| | | } |
| | | .ant-modal-body::-webkit-scrollbar { |
| | |
| | | .profile { |
| | | color: purple; |
| | | } |
| | | .model-menu-tabs-setting { |
| | | .model-datasource { |
| | | display: inline-block; |
| | | position: unset; |
| | | } |
| | |
| | | position: absolute; |
| | | content: ' '; |
| | | width: 100%; |
| | | height: 10px; |
| | | bottom: -10px; |
| | | height: 12px; |
| | | bottom: -12px; |
| | | left: 0px; |
| | | } |
| | | .ant-popover-inner-content { |
| | |
| | | |
| | | const { TextArea } = Input |
| | | const actionTypeOptions = { |
| | | pop: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'], |
| | | prompt: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'], |
| | | exec: ['label', 'position', 'OpenType', 'intertype', 'Ot', 'icon', 'class', 'execSuccess', 'execError'], |
| | | excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'icon', 'class', 'sheet', 'execSuccess', 'execError'], |
| | | excelOut: ['label', 'OpenType', 'intertype', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'], |
| | | popview: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'tabType', 'linkTab', 'popClose'], |
| | | tab: ['label', 'Ot', 'OpenType', 'icon', 'class', 'position', 'linkmenu'], |
| | | innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'], |
| | | funcbutton: ['label', 'OpenType', 'funcType', 'icon', 'class'] |
| | | pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError'], |
| | | prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError'], |
| | | exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError'], |
| | | excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'sheet', 'execSuccess', 'execError'], |
| | | excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'], |
| | | popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'tabType', 'linkTab', 'popClose'], |
| | | tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'linkmenu'], |
| | | innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'icon', 'class'], |
| | | funcbutton: ['label', 'OpenType', 'funcType', 'show', 'icon', 'class'] |
| | | } |
| | | |
| | | class MainSearch extends Component { |
| | |
| | | openType: null, // 打开方式 |
| | | interType: null, // 接口类型:内部、外部 |
| | | funcType: null, // 功能类型 |
| | | position: null, // 按钮位置 |
| | | requireOptions: [{ |
| | | value: 'notRequired', |
| | | text: this.props.dict['header.form.notRequired'] |
| | |
| | | openType: _opentype, |
| | | menulist: _menulist.options || [], |
| | | interType: _intertype, |
| | | position: card.position || 'toolbar', |
| | | funcType: _funcType, |
| | | formlist: this.props.formlist.map(item => { |
| | | if (item.key === 'class') { |
| | |
| | | } else if (item.key === 'icon') { |
| | | item.options = btnIcons |
| | | } else if (item.key === 'Ot') { |
| | | if (card.position === 'grid' || card.pageTemplate === 'pay') { // 行级按钮、支付按钮,只能选单行 |
| | | if (card.pageTemplate === 'pay') { // 行级按钮、支付按钮,只能选单行 |
| | | item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) |
| | | } else if (['innerpage', 'blank', 'tab', 'popview', 'excelIn'].includes(_opentype)) { |
| | | item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) |
| | |
| | | if (item.key === 'intertype') { |
| | | _fieldval.intertype = this.state.interType |
| | | } else if (item.key === 'Ot') { |
| | | if (this.state.position === 'grid') { |
| | | item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) |
| | | _fieldval.Ot = 'requiredSgl' |
| | | } else if (['innerpage', 'blank', 'tab', 'popview'].includes(value)) { |
| | | if (['innerpage', 'blank', 'tab', 'popview'].includes(value)) { |
| | | item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) |
| | | _fieldval.Ot = 'requiredSgl' |
| | | } else if (value === 'excelIn') { |
| | |
| | | _fieldval.class = 'dgreen' |
| | | } |
| | | |
| | | this.props.form.setFieldsValue(_fieldval) |
| | | }) |
| | | } else if (key === 'position') { |
| | | let _fieldval = {} |
| | | |
| | | this.setState({ |
| | | position: value, |
| | | formlist: this.state.formlist.map(item => { |
| | | if (item.key === 'Ot') { |
| | | if (value === 'grid') { |
| | | item.options = this.state.requireOptions.filter(op => ['requiredSgl'].includes(op.value)) |
| | | _fieldval.Ot = 'requiredSgl' |
| | | } else if (['innerpage', 'blank', 'tab', 'popview'].includes(this.state.openType)) { |
| | | item.options = this.state.requireOptions.filter(op => ['notRequired', 'requiredSgl'].includes(op.value)) |
| | | _fieldval.Ot = 'requiredSgl' |
| | | } else { |
| | | item.options = this.state.requireOptions |
| | | } |
| | | } |
| | | return item |
| | | }) |
| | | }, () => { |
| | | this.props.form.setFieldsValue(_fieldval) |
| | | }) |
| | | } else if (key === 'tabType') { |
| | |
| | | this.props.form.setFieldsValue(_fieldval) |
| | | }) |
| | | } else if (key === 'pageTemplate') { |
| | | let _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class', 'position'] |
| | | let _options = ['label', 'Ot', 'OpenType', 'pageTemplate', 'icon', 'class'] |
| | | let _fieldval = {} |
| | | if (value === 'custom') { |
| | | _options.push('url', 'joint') |
| | |
| | | values.uuid = this.props.card.uuid |
| | | values.verify = this.props.card.verify || null |
| | | |
| | | if (values.OpenType === 'excelIn') { |
| | | values.position = 'toolbar' |
| | | if (values.show === 'icon') { |
| | | |
| | | } else if (values.OpenType === 'excelOut') { |
| | | if (values.intertype === 'system' && setting.interType !== 'system') { |
| | | notification.warning({ |
| | |
| | | return |
| | | } |
| | | |
| | | values.position = 'toolbar' |
| | | values.Ot = 'notRequired' |
| | | } else if (values.OpenType === 'popview' && !values.linkTab) { // 没有关联标签(新建时),创建新标签Id |
| | | values.linkTab = Utils.getuuid() |
| | | values.createTab = true // 用于标记按钮复制时,是否复制原有标签 |
| | | } else if (values.OpenType === 'funcbutton') { // 转换打印时打开方式 |
| | | values.position = 'toolbar' |
| | | if (values.funcType === 'print') { |
| | | values.OpenType = values.execMode |
| | | } |
| | |
| | | import { Icon, Button, Popover } from 'antd' |
| | | import './index.scss' |
| | | |
| | | const Card = ({ id, cardIds, type, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, doubleClickCard }) => { |
| | | const Card = ({ id, cardIds, card, moveCard, findCard, editCard, delCard, copyCard, profileCard, doubleClickCard }) => { |
| | | const originalIndex = findCard(id).index |
| | | const [{ isDragging }, drag] = useDrag({ |
| | | item: { type: 'action', id, originalIndex }, |
| | |
| | | } |
| | | |
| | | let btnElement = null |
| | | if (type === 'chart') { |
| | | btnElement = (<Icon type={card.icon} className={'mk-icon mk-' + card.class} onClick={() => editCard(id)} />) |
| | | if (card.show === 'icon') { |
| | | btnElement = (<Icon type={card.icon} className={'mk-icon mk-' + card.class}/>) |
| | | } else if (card.show === 'link') { |
| | | btnElement = (<span className={'mk-link mk-' + card.class}>{card.label}{card.icon ? <Icon type={card.icon}/> : null}</span>) |
| | | } else { |
| | | btnElement = ( |
| | | <Button |
| | |
| | | newcard.class = 'default' |
| | | newcard.intertype = 'system' |
| | | newcard.method = 'POST' |
| | | newcard.position = 'toolbar' |
| | | newcard.execSuccess = 'grid' |
| | | newcard.execError = 'never' |
| | | newcard.popClose = 'never' |
| | | newcard.errorTime = 10 |
| | | newcard.verify = null |
| | | newcard.show = 'icon' |
| | | |
| | | if (type === 'chart') { |
| | | newcard.show = 'icon' |
| | | } |
| | | |
| | | let targetId = cards.length > 0 ? cards[cards.length - 1].uuid : 0 |
| | | |
| | |
| | | id={card.uuid} |
| | | key={card.uuid} |
| | | cardIds={cardIds} |
| | | type={type} |
| | | card={card} |
| | | moveCard={moveCard} |
| | | copyCard={copyCard} |
| | |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'position', |
| | | label: Formdict['header.form.position'], |
| | | initVal: card.position || 'toolbar', |
| | | required: true, |
| | | options: [{ |
| | | value: 'toolbar', |
| | | text: Formdict['header.form.toolbar'] |
| | | }, { |
| | | value: 'grid', |
| | | text: Formdict['header.form.grid'] |
| | | }] |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'Ot', |
| | | label: Formdict['header.form.isRequired'], |
| | | initVal: card.Ot || 'requiredSgl', |
| | |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'show', |
| | | label: "显示为", |
| | | initVal: card.show || 'icon', |
| | | required: true, |
| | | options: [{ |
| | | value: 'icon', |
| | | text: '图标' |
| | | }, { |
| | | value: 'button', |
| | | text: '按钮' |
| | | }, { |
| | | value: 'link', |
| | | text: '链接' |
| | | }] |
| | | }, |
| | | { |
| | | type: 'select', |
| | | key: 'icon', |
| | | label: Formdict['model.icon'], |
| | | initVal: card.icon, |
| | | required: type === 'chart', // 图表必须使用图标 |
| | | required: false, |
| | | options: [] |
| | | }, |
| | | { |
| | |
| | | // } |
| | | ] |
| | | |
| | | if (type === 'chart') { |
| | | return forms |
| | | } |
| | | // if (type === 'chart') { |
| | | // return forms |
| | | // } |
| | | return forms |
| | | } |
| | |
| | | const { actionlist, visible, card, dict, copying, profVisible } = this.state |
| | | |
| | | return ( |
| | | <div className="model-custom-chart-action-list"> |
| | | <div className="model-menu-action-list"> |
| | | <DragElement |
| | | type={type} |
| | | list={actionlist} |
| | | setting={this.props.config.setting} |
| | | handleList={this.handleList} |
| | | handleMenu={this.handleAction} |
| | | deleteMenu={this.deleteElement} |
| | |
| | | .model-custom-chart-action-list { |
| | | .model-menu-action-list { |
| | | .anticon-question-circle { |
| | | color: #c49f47; |
| | | position: absolute; |
| | |
| | | } |
| | | |
| | | .page-card { |
| | | display: inline-block; |
| | | margin: 0px; |
| | | padding: 0px 5px; |
| | | position: relative; |
| | | |
| | | div { |
| | | display: inline-block; |
| | | cursor: move; |
| | | } |
| | | button { |
| | |
| | | import PropTypes from 'prop-types' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Icon, Popover } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | |
| | | 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 = asyncComponent(() => import('@/menu/datasource')) |
| | | const SettingComponent = asyncIconComponent(() => import('@/menu/datasource')) |
| | | const WrapComponent = asyncIconComponent(() => import('./wrapsetting')) |
| | | const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent')) |
| | | |
| | | class antvBarLineChart extends Component { |
| | | static propTpyes = { |
| | | card: PropTypes.object, |
| | | deletecomponent: PropTypes.func, |
| | | updateConfig: PropTypes.func, |
| | | } |
| | | |
| | |
| | | tabId: card.tabId || '', |
| | | parentId: card.parentId || '', |
| | | format: 'array', // 组件属性 - 数据格式 |
| | | pageable: false, // 组件属性 - 是否可分页 |
| | | switchable: false, // 组件属性 - 数据是否可切换 |
| | | pageable: true, // 组件属性 - 是否可分页 |
| | | switchable: true, // 组件属性 - 数据是否可切换 |
| | | dataName: dataName, |
| | | width: 24, |
| | | name: card.name, |
| | | subtype: card.subtype, |
| | | setting: {span: 24, height: 200, interType: 'system', name: card.name}, |
| | | setting: { interType: 'system' }, |
| | | wrap: { name: card.name, width: 24, height: 200, cardWidth: 6, addable: 'false', switch: 'false' }, |
| | | columns: [], |
| | | scripts: [], |
| | | search: [], |
| | | action: [], |
| | | elements: [] |
| | | } |
| | | this.setState({ |
| | | card: _card |
| | |
| | | this.setState({ |
| | | card: component |
| | | }) |
| | | |
| | | component.width = component.wrap.width |
| | | component.name = component.wrap.name |
| | | |
| | | this.props.updateConfig(component) |
| | | } |
| | | |
| | |
| | | const { card } = this.state |
| | | |
| | | return ( |
| | | <div className="menu-data-card-edit-box" style={{height: card.setting.height || 400}}> |
| | | <SettingComponent |
| | | config={card} |
| | | updateConfig={this.updateComponent} |
| | | /> |
| | | <div className="chart-header"> |
| | | <span className="chart-title">{card.setting.title || ''}</span> |
| | | <div className="menu-data-card-edit-box"> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <WrapComponent config={card} updateConfig={this.updateComponent} /> |
| | | <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} /> |
| | | <SettingComponent config={card} updateConfig={this.updateComponent} /> |
| | | </div> |
| | | } trigger="hover"> |
| | | <Icon type="tool" /> |
| | | </Popover> |
| | | <div className={'ant-col card-item ant-col-' + (card.wrap.cardWidth || 6)} style={{height: card.wrap.height ? card.wrap.height + 'px' : 'auto'}}> |
| | | |
| | | <ActionComponent |
| | | config={card} |
| | | tabs={[]} |
| | | // setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')} |
| | | updateaction={this.updateComponent} |
| | | /> |
| | | </div> |
| | | <ActionComponent |
| | | type="chart" |
| | | config={card} |
| | | tabs={[]} |
| | | // setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')} |
| | | updateaction={this.updateComponent} |
| | | /> |
| | | <div className="canvas" id={card.uuid}></div> |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | box-sizing: border-box; |
| | | background: #ffffff; |
| | | |
| | | .anticon-tool { |
| | | position: absolute; |
| | | z-index: 1; |
| | | font-size: 16px; |
| | | right: 0; |
| | | top: 0; |
| | | cursor: pointer; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .card-item { |
| | | position: relative; |
| | | min-height: 50px; |
| | | border: 1px solid #e8e8e8; |
| | | } |
| | | |
| | | .card-item:hover { |
| | | box-shadow: 0px 0px 2px #e8e8e8; |
| | | } |
| | | } |
| | | .menu-data-card-edit-box::after { |
| | | display: block; |
| | | content: ' '; |
| | | clear: both; |
| | | } |
| | | .menu-data-card-edit-box:hover { |
| | | box-shadow: 0px 0px 2px #e8e8e8; |
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: localStorage.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 { visible, dict, wrap } = this.state |
| | | |
| | | return ( |
| | | <div className="model-menu-setting-wrap"> |
| | | <Icon type="edit" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="popview-modal" |
| | | title={'卡片设置'} |
| | | visible={visible} |
| | | width={700} |
| | | maskClosable={false} |
| | | okText={dict['model.submit']} |
| | | onOk={this.verifySubmit} |
| | | onCancel={() => { this.setState({ visible: false }) }} |
| | | destroyOnClose |
| | | > |
| | | <SettingForm |
| | | dict={dict} |
| | | wrap={wrap} |
| | | 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 } from 'antd' |
| | | |
| | | import './index.scss' |
| | | |
| | | class SettingForm extends Component { |
| | | static propTpyes = { |
| | | dict: PropTypes.object, // 字典项 |
| | | wrap: PropTypes.object, // 数据源配置 |
| | | } |
| | | |
| | | handleConfirm = () => { |
| | | // 表单提交时检查输入值是否正确 |
| | | return new Promise((resolve, reject) => { |
| | | this.props.form.validateFieldsAndScroll((err, values) => { |
| | | if (!err) { |
| | | resolve(values) |
| | | } else { |
| | | reject(err) |
| | | } |
| | | }) |
| | | }) |
| | | } |
| | | |
| | | render() { |
| | | const { wrap } = this.props |
| | | const { getFieldDecorator } = this.props.form |
| | | |
| | | 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={ |
| | | <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" />)} |
| | | </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} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="高度为空时,使用自适应高度。"> |
| | | <Icon type="question-circle" /> |
| | | 高度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('height', { |
| | | initialValue: wrap.height |
| | | })(<InputNumber min={50} max={1000} precision={0} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="单个卡片所占的宽度,栅格布局,每行等分24份。"> |
| | | <Icon type="question-circle" /> |
| | | 卡片宽度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('cardWidth', { |
| | | initialValue: wrap.cardWidth || 6, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '卡片宽度!' |
| | | } |
| | | ] |
| | | })(<InputNumber min={1} max={24} precision={0} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="选择含有添加按钮时,请完善按钮配置信息。"> |
| | | <Icon type="question-circle" /> |
| | | 添加按钮 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('addable', { |
| | | initialValue: wrap.addable || 'false' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="true">有</Radio> |
| | | <Radio value="false">无</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="选择卡片切换时,可向其他组件传递主键值。"> |
| | | <Icon type="question-circle" /> |
| | | 是否切换 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('switch', { |
| | | initialValue: wrap.switch || 'false' |
| | | })( |
| | | <Radio.Group> |
| | | <Radio value="true">是</Radio> |
| | | <Radio value="false">否</Radio> |
| | | </Radio.Group> |
| | | )} |
| | | </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%; |
| | | } |
| | | } |
| | |
| | | |
| | | return [ |
| | | { |
| | | type: 'text', |
| | | key: 'title', |
| | | label: '标题', |
| | | initVal: card.title, |
| | | required: false |
| | | }, |
| | | { |
| | | type: 'text', |
| | | key: 'name', |
| | | label: '组件名称', |
| | | initVal: card.name, |
| | | tooltip: '用于组件间的区分。', |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'number', |
| | | key: 'width', |
| | | label: '宽度', |
| | | initVal: card.width, |
| | | tooltip: '栅格布局,每行等分24份。', |
| | | min: 1, |
| | | max: 24, |
| | | decimal: 0, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'number', |
| | | key: 'height', |
| | | label: '高度', |
| | | initVal: card.height, |
| | | min: 100, |
| | | max: 1000, |
| | | decimal: 0, |
| | | required: true |
| | | }, |
| | | { |
| | | type: 'radio', |
| | | key: 'datatype', |
| | | label: '数据类型', |
| | |
| | | .line-chart-drawer-form { |
| | | position: absolute; |
| | | right: 0px; |
| | | top: 50%; |
| | | |
| | | display: inline-block; |
| | | > .anticon-edit { |
| | | color: #1890ff; |
| | | font-size: 16px; |
| | | margin-right: 5px; |
| | | cursor: pointer; |
| | | } |
| | | } |
| | | .menu-chart-edit-modal { |
| | |
| | | import PropTypes from 'prop-types' |
| | | import {connect} from 'react-redux' |
| | | import { is, fromJS } from 'immutable' |
| | | import { Icon, Popover } from 'antd' |
| | | import { Chart } from '@antv/g2' |
| | | import DataSet from '@antv/data-set' |
| | | |
| | | import MKEmitter from '@/utils/events.js' |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | |
| | | 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 = asyncComponent(() => import('@/menu/datasource')) |
| | | const SettingComponent = asyncIconComponent(() => import('@/menu/datasource')) |
| | | const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent')) |
| | | const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent')) |
| | | const ChartCompileForm = asyncComponent(() => import('./chartcompile')) |
| | | const ChartCompileForm = asyncIconComponent(() => import('./chartcompile')) |
| | | |
| | | class antvBarLineChart extends Component { |
| | | static propTpyes = { |
| | | card: PropTypes.object, |
| | | updateConfig: PropTypes.func, |
| | | deletecomponent: PropTypes.func, |
| | | } |
| | | |
| | | state = { |
| | |
| | | chartType: card.type, // 图表类型 |
| | | enabled: 'false', // 是否使用自定义设置 |
| | | datatype: 'query', // 数据类型查询或统计 |
| | | customs: [] |
| | | customs: [], |
| | | width: 24, |
| | | height: 400, |
| | | name: card.name |
| | | } |
| | | |
| | | if (card.subtype === 'bar') { |
| | |
| | | pageable: false, // 组件属性 - 是否可分页 |
| | | switchable: false, // 组件属性 - 数据是否可切换 |
| | | dataName: dataName, |
| | | width: _plot.width, |
| | | name: _plot.name, |
| | | subtype: card.subtype, |
| | | setting: {span: 24, height: 400, interType: 'system', name: card.name}, |
| | | setting: { interType: 'system' }, |
| | | columns: [], |
| | | scripts: [], |
| | | search: [], |
| | |
| | | |
| | | linerender = () => { |
| | | const { card } = this.state |
| | | let plot = {...card.plot, height: card.setting.height - 70} |
| | | let plot = {...card.plot, height: card.plot.height - 70} // 去除title所占空间 |
| | | |
| | | let transfield = {} |
| | | card.columns.forEach(col => { |
| | |
| | | } |
| | | |
| | | customrender = (data, transfield) => { |
| | | const { plot } = this.props |
| | | const { card } = this.state |
| | | let plot = {...card.plot, height: card.plot.height - 70} // 去除title所占空间 |
| | | |
| | | let barfields = [] |
| | | let fields = [] |
| | |
| | | |
| | | barrender = () => { |
| | | const { card } = this.state |
| | | |
| | | let plot = {...card.plot, height: card.setting.height - 70} |
| | | let plot = {...card.plot, height: card.plot.height - 70} |
| | | |
| | | let transfield = {} |
| | | card.columns.forEach(col => { |
| | |
| | | updateComponent = (component) => { |
| | | const card = fromJS(this.state.card).toJS() |
| | | let refresh = false |
| | | if (card.setting.span !== component.setting.span || card.setting.height !== component.setting.height || !is(fromJS(component.plot), fromJS(card.plot))) { |
| | | if (!is(fromJS(component.plot), fromJS(card.plot))) { |
| | | let _element = document.getElementById(card.uuid) |
| | | if (_element) { |
| | | _element.innerHTML = '' |
| | | } |
| | | refresh = true |
| | | } |
| | | |
| | | component.width = component.plot.width |
| | | component.name = component.plot.name |
| | | |
| | | this.setState({ |
| | | card: component |
| | |
| | | const { card } = this.state |
| | | |
| | | return ( |
| | | <div className="menu-line-chart-edit-box" style={{height: card.setting.height || 400}}> |
| | | <SettingComponent |
| | | config={card} |
| | | updateConfig={this.updateComponent} |
| | | /> |
| | | <div className="menu-line-chart-edit-box" style={{height: card.plot.height || 400}}> |
| | | <div className="chart-header"> |
| | | <span className="chart-title">{card.setting.title || ''}</span> |
| | | <span className="chart-title">{card.plot.title || ''}</span> |
| | | <SearchComponent |
| | | config={card} |
| | | updatesearch={this.updateComponent} |
| | | /> |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/> |
| | | <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} /> |
| | | <SettingComponent config={card} updateConfig={this.updateComponent}/> |
| | | </div> |
| | | } trigger="hover"> |
| | | <Icon type="tool" /> |
| | | </Popover> |
| | | </div> |
| | | <ActionComponent |
| | | type="chart" |
| | |
| | | updateaction={this.updateComponent} |
| | | /> |
| | | <div className="canvas" id={card.uuid}></div> |
| | | <ChartCompileForm |
| | | config={card} |
| | | dict={this.state.dict} |
| | | plotchange={this.updateComponent} |
| | | /> |
| | | |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | } |
| | | |
| | | .chart-header { |
| | | position: relative; |
| | | height: 45px; |
| | | border-bottom: 1px solid #e8e8e8; |
| | | overflow: hidden; |
| | | padding-right: 40px; |
| | | |
| | | >.anticon-tool { |
| | | position: absolute; |
| | | right: 0px; |
| | | top: 0px; |
| | | font-size: 16px; |
| | | padding: 10px; |
| | | cursor: pointer; |
| | | } |
| | | |
| | | .chart-title { |
| | | font-size: 16px; |
| | |
| | | } |
| | | } |
| | | |
| | | .model-custom-chart-action-list { |
| | | .model-menu-action-list { |
| | | position: absolute; |
| | | right: 0px; |
| | | z-index: 4; |
| | |
| | | |
| | | import MKEmitter from '@/utils/events.js' |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import asyncIconComponent from '@/utils/asyncIconComponent' |
| | | |
| | | 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 = asyncComponent(() => import('../tabsetting')) |
| | | const SettingComponent = asyncIconComponent(() => import('../tabsetting')) |
| | | const TabLabelComponent = asyncComponent(() => import('../tablabelform')) |
| | | const TabComponents = asyncComponent(() => import('../tabcomponents')) |
| | | |
| | |
| | | class antvBarLineChart extends Component { |
| | | static propTpyes = { |
| | | tabs: PropTypes.object, |
| | | deleteTabs: PropTypes.func, |
| | | deletecomponent: PropTypes.func, |
| | | updateConfig: PropTypes.func, |
| | | } |
| | | |
| | |
| | | tabId: tabs.tabId || '', |
| | | parentId: tabs.parentId || '', |
| | | subtype: tabs.subtype, |
| | | setting: {span: 24, position: 'top', tabStyle: 'line', name: tabs.name}, |
| | | width: 24, |
| | | name: tabs.name, |
| | | setting: {width: 24, position: 'top', tabStyle: 'line', name: tabs.name}, |
| | | subtabs: [ |
| | | { uuid: Utils.getuuid(), parentId: tabs.uuid, floor: tabs.floor, label: 'Tab 1', icon: '', components: [] }, |
| | | { uuid: Utils.getuuid(), parentId: tabs.uuid, floor: tabs.floor, label: 'Tab 2', icon: '', components: [] }, |
| | |
| | | // 注册事件-标签变化,通知标签内元素 |
| | | MKEmitter.emit('tabsChange', tabs.uuid) |
| | | } |
| | | |
| | | component.width = component.setting.width |
| | | component.name = component.setting.name |
| | | |
| | | this.setState({ |
| | | tabs: component |
| | |
| | | |
| | | return ( |
| | | <div className="menu-tabs-edit-box"> |
| | | {/* <SettingComponent config={tabs} updateConfig={this.updateComponent} /> */} |
| | | <Tabs defaultActiveKey="1" tabPosition={tabs.setting.position} type={tabs.setting.tabStyle}> |
| | | {tabs.subtabs.map((tab, index) => ( |
| | | <TabPane tab={ |
| | |
| | | <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={ |
| | | <div className="mk-popover-control"> |
| | | <Icon className="plus" title="add" type="plus" onClick={this.tabAdd} /> |
| | | <Icon className="close" title="delete" type="delete" onClick={() => this.props.deleteTabs(tabs.uuid)} /> |
| | | <SettingComponent config={tabs} updateConfig={this.updateComponent} /> |
| | | <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(tabs.uuid)} /> |
| | | </div> |
| | | } trigger="hover"> |
| | | <Icon type="tool" /> |
| | | </Popover> |
| | | } key="tool"> |
| | | </TabPane> |
| | | {/* <TabPane className="tab-add" disabled tab={<Icon onClick={this.tabAdd} type="plus" />} key="add"></TabPane> */} |
| | | </Tabs> |
| | | <Modal |
| | | wrapClassName="popview-modal" |
| | |
| | | .ant-tabs-bar { |
| | | margin-bottom: 0px; |
| | | } |
| | | .ant-tabs-content { |
| | | padding-top: 20px; |
| | | } |
| | | |
| | | .ant-tabs .ant-tabs-left-bar .ant-tabs-tab { |
| | | padding: 0px; |
| | | text-align: right; |
| | |
| | | import React from 'react' |
| | | import { useDrag, useDrop } from 'react-dnd' |
| | | import { Icon } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import './index.scss' |
| | | |
| | | const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar')) |
| | | const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs')) |
| | | const DataCard = asyncComponent(() => import('@/menu/components/card/data-card')) |
| | | |
| | | const Card = ({ id, card, moveCard, findCard, delCard, hasDrop, updateConfig }) => { |
| | | const originalIndex = findCard(id).index |
| | |
| | | |
| | | const getCardComponent = () => { |
| | | if (card.type === 'bar' || card.type === 'line') { |
| | | return (<AntvBar card={card} updateConfig={updateConfig} />) |
| | | return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard} />) |
| | | } else if (card.type === 'tabs') { |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deleteTabs={delCard} />) |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard} />) |
| | | } else if (card.type === 'card' && card.subtype === 'datacard') { |
| | | return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />) |
| | | } |
| | | } |
| | | |
| | | return ( |
| | | <div className={'ant-col mk-component-card ant-col-' + (card.setting ? card.setting.span : 24)} ref={node => drag(drop(node))} style={style}> |
| | | <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}> |
| | | {getCardComponent()} |
| | | {card.type !== 'tabs' ? <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} /> : null} |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | } |
| | | |
| | | confirm({ |
| | | title: `确定删除《${card.setting.name}》吗?`, |
| | | title: `确定删除《${card.name}》吗?`, |
| | | content: hasComponent ? '当前组件中含有子组件!' : '', |
| | | onOk() { |
| | | handleList({...config, components: cards.filter(item => item.uuid !== card.uuid)}) |
| | |
| | | |
| | | while (!name && names[item.component]) { |
| | | let _name = names[item.component] + i |
| | | if (config.components.filter(com => com.setting && com.setting.name === _name).length === 0) { |
| | | if (config.components.filter(com => com.name === _name).length === 0) { |
| | | name = _name |
| | | } |
| | | i++ |
| | |
| | | |
| | | .mk-component-card { |
| | | position: relative; |
| | | .remove-component { |
| | | position: absolute; |
| | | right: 42px; |
| | | top: -16px; |
| | | color: #ff4d4f; |
| | | border-radius: 2px; |
| | | font-size: 16px; |
| | | padding: 5px; |
| | | cursor: pointer; |
| | | opacity: 0; |
| | | transition: opacity 0.2s; |
| | | } |
| | | } |
| | | >.mk-component-card:hover { |
| | | >.remove-component { |
| | | opacity: 1; |
| | | } |
| | | > div >.model-datasource .anticon-setting, >.menu-tabs-edit-box > .model-menu-tabs-setting .anticon-setting { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | >.ant-empty { |
| | | padding: 60px 0px 70px; |
| | | } |
| | | |
| | | .model-datasource > .anticon-setting, .model-menu-tabs-setting > .anticon-setting { |
| | | font-size: 16px; |
| | | padding: 5px; |
| | | position: absolute; |
| | | right: 0px; |
| | | top: -30px; |
| | | opacity: 0; |
| | | cursor: pointer; |
| | | transition: opacity 0.2s; |
| | | } |
| | | } |
| | |
| | | const { visible, dict, setting } = this.state |
| | | |
| | | return ( |
| | | <div className="model-menu-tabs-setting"> |
| | | <Icon type="setting" onClick={() => this.editDataSource()} /> |
| | | <div className="model-menu-setting-wrap"> |
| | | <Icon type="edit" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="model-datasource-verify-modal popview-modal" |
| | | wrapClassName="popview-modal" |
| | | title={'标签页配置'} |
| | | visible={visible} |
| | | width={700} |
| | |
| | | .model-menu-tabs-setting { |
| | | position: absolute; |
| | | right: 7px; |
| | | top: 5px; |
| | | z-index: 1; |
| | | .model-menu-setting-wrap { |
| | | display: inline-block; |
| | | |
| | | >.anticon-setting { |
| | | font-size: 18px; |
| | | padding: 10px; |
| | | } |
| | | |
| | | .model-input-group-wrapper { |
| | | padding: 0 20px; |
| | | display: inline-block; |
| | | width: 100%; |
| | | text-align: start; |
| | | vertical-align: top; |
| | | margin-bottom: 15px; |
| | | |
| | | .model-input-wrapper { |
| | | position: relative; |
| | | display: table; |
| | | width: 100%; |
| | | border-collapse: separate; |
| | | border-spacing: 0; |
| | | |
| | | .model-input-value { |
| | | display: table-cell; |
| | | width: 100%; |
| | | border: 1px solid #d9d9d9; |
| | | border-radius: 4px 0px 0px 4px; |
| | | overflow: hidden; |
| | | text-overflow:ellipsis; |
| | | white-space: nowrap; |
| | | padding: 2px 10px; |
| | | color: #ffffff; |
| | | } |
| | | |
| | | .model-input-group-addon { |
| | | display: table-cell; |
| | | width: 1px; |
| | | position: relative; |
| | | padding: 0 11px; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | font-weight: normal; |
| | | font-size: 14px; |
| | | line-height: 1; |
| | | text-align: center; |
| | | background-color: #fafafa; |
| | | border: 1px solid #d9d9d9; |
| | | border-radius: 0px 4px 4px 0px; |
| | | white-space: nowrap; |
| | | } |
| | | |
| | | .model-input-insert { |
| | | display: table-cell; |
| | | width: 100%; |
| | | border: 1px dotted #d9d9d9; |
| | | border-radius: 4px; |
| | | text-align: center; |
| | | cursor: pointer; |
| | | |
| | | .anticon-plus { |
| | | padding: 6px; |
| | | font-size: 16px; |
| | | color: rgb(38, 194, 129); |
| | | } |
| | | } |
| | | } |
| | | .anticon-setting { |
| | | margin-right: 5px; |
| | | padding: 6px; |
| | | cursor: pointer; |
| | | } |
| | | .anticon-setting:hover { |
| | | color: #1890ff; |
| | | } |
| | | .anticon-close { |
| | | padding: 6px; |
| | | cursor: pointer; |
| | | } |
| | | .anticon-close:hover { |
| | | color: #ff4d4f; |
| | | } |
| | | } |
| | | } |
| | | .model-datasource-verify-modal { |
| | | .ant-modal { |
| | | top: 50px; |
| | | .ant-modal-body { |
| | | max-height: calc(100vh - 190px); |
| | | } |
| | | >.anticon-edit { |
| | | color: #1890ff; |
| | | } |
| | | } |
| | |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Input, Radio, Tooltip, Icon, InputNumber, Select } from 'antd' |
| | | |
| | | // import { formRule } from '@/utils/option.js' |
| | | import './index.scss' |
| | | |
| | | class SettingForm extends Component { |
| | |
| | | } |
| | | |
| | | return ( |
| | | <div className="model-datasource-setting-form-box"> |
| | | <Form {...formItemLayout} className="model-setting-form"> |
| | | <div className="model-menu-setting-form"> |
| | | <Form {...formItemLayout}> |
| | | <Row gutter={24}> |
| | | <Col span={12}> |
| | | <Form.Item label={ |
| | |
| | | 宽度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('span', { |
| | | initialValue: setting.span || 12, |
| | | {getFieldDecorator('width', { |
| | | initialValue: setting.width || 24, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | |
| | | .model-datasource-setting-form-box { |
| | | .model-menu-setting-form { |
| | | position: relative; |
| | | |
| | | .model-setting-form { |
| | | .data-source { |
| | | .ant-form-item-label { |
| | | width: 11%; |
| | | } |
| | | .ant-form-item-control-wrapper { |
| | | width: 89%; |
| | | } |
| | | .CodeMirror { |
| | | height: 150px; |
| | | } |
| | | } |
| | | .anticon-question-circle { |
| | | color: #c49f47; |
| | | margin-right: 3px; |
| | | } |
| | | .anticon-question-circle { |
| | | color: #c49f47; |
| | | margin-right: 3px; |
| | | } |
| | | .ant-input-number { |
| | | width: 100%; |
| | |
| | | <div className="model-datasource"> |
| | | <Icon type="setting" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="model-datasource-verify-modal popview-modal" |
| | | wrapClassName="popview-modal" |
| | | title={'数据源配置'} |
| | | visible={visible} |
| | | width={'75vw'} |
| | |
| | | } |
| | | } |
| | | } |
| | | .model-datasource-verify-modal { |
| | | .ant-modal { |
| | | top: 50px; |
| | | .ant-modal-body { |
| | | max-height: calc(100vh - 190px); |
| | | } |
| | | } |
| | | } |
| | |
| | | import React, {Component} from 'react' |
| | | import PropTypes from 'prop-types' |
| | | import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, InputNumber, Select } from 'antd' |
| | | import { Form, Row, Col, Input, Radio, Tooltip, Icon, notification, Select, InputNumber } from 'antd' |
| | | |
| | | import { formRule } from '@/utils/option.js' |
| | | import Utils from '@/utils/utils.js' |
| | |
| | | <div className="model-datasource-setting-form-box"> |
| | | <Form {...formItemLayout} className="model-setting-form"> |
| | | <Row gutter={24}> |
| | | <Col span={8}> |
| | | <Form.Item label="标题"> |
| | | {getFieldDecorator('title', { |
| | | initialValue: setting.title |
| | | })(<Input placeholder={''} autoComplete="off" />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="用于组件间的区分。"> |
| | | <Icon type="question-circle" /> |
| | | 组件名称 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('name', { |
| | | initialValue: setting.name, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '组件名称!' |
| | | } |
| | | ] |
| | | })(<Input placeholder={''} autoComplete="off" />)} |
| | | </Form.Item> |
| | | </Col> |
| | | <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="栅格布局,每行等分24份。"> |
| | | <Icon type="question-circle" /> |
| | | 宽度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('span', { |
| | | initialValue: setting.span || 12, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '宽度!' |
| | | } |
| | | ] |
| | | })(<InputNumber min={1} max={24} precision={0} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | |
| | | <Col span={8}> |
| | | <Form.Item label="表名"> |
| | | {getFieldDecorator('tableName', { |
| | |
| | | })(<CodeMirror />)} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="高度为空时,使用系统自适应设置。"> |
| | | <Icon type="question-circle" /> |
| | | 高度 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('height', { |
| | | initialValue: setting.height || 400 |
| | | })(<InputNumber min={150} max={1500} precision={0} />)} |
| | | </Form.Item> |
| | | </Col> |
| | | {interType === 'system' ? <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title={'查询时,搜索条件以where条件拼接进入sql,统计时,将数据源中以“@+搜索字段+@”的内容,以搜索条件中的值进行替换后,提交查询,注:查询类型仅在使用系统函数时有效。'}> |
| | |
| | | )} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | {config.pageable ? <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title="选择分页时有效。"> |
| | | <Icon type="question-circle" /> |
| | | 每页数量 |
| | | </Tooltip> |
| | | }> |
| | | {getFieldDecorator('pageSize', { |
| | | initialValue: setting.pageSize || 10, |
| | | rules: [ |
| | | { |
| | | required: true, |
| | | message: this.props.dict['form.required.input'] + '每页数量!' |
| | | } |
| | | ] |
| | | })(<InputNumber min={1} max={500} precision={0} />)} |
| | | </Form.Item> |
| | | </Col> : null} |
| | | <Col span={8}> |
| | | <Form.Item label={ |
| | | <Tooltip placement="topLeft" title={'使用主搜索条件(存在时),主搜索条件与组件的搜索条件会一同用作数据过滤(组件的搜索条件优先)。'}> |
| | |
| | | import React from 'react' |
| | | import { useDrag, useDrop } from 'react-dnd' |
| | | import { Icon } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | import './index.scss' |
| | |
| | | |
| | | const getCardComponent = () => { |
| | | if (card.type === 'bar' || card.type === 'line') { |
| | | return (<AntvBar card={card} updateConfig={updateConfig} />) |
| | | return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'tabs') { |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deleteTabs={delCard} />) |
| | | } else if (card.type === 'card') { |
| | | return (<DataCard card={card} updateConfig={updateConfig} />) |
| | | return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } else if (card.type === 'card' && card.subtype === 'datacard') { |
| | | return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) |
| | | } |
| | | } |
| | | |
| | | return ( |
| | | <div className={'ant-col mk-component-card ant-col-' + (card.setting ? card.setting.span : 12)} ref={node => drag(drop(node))} style={style}> |
| | | <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}> |
| | | {getCardComponent()} |
| | | {card.type !== 'tabs' ? <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} /> : null} |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | } |
| | | |
| | | confirm({ |
| | | title: `确定删除《${card.setting.name}》吗?`, |
| | | title: `确定删除《${card.name}》吗?`, |
| | | content: hasComponent ? '当前组件中含有子组件!' : '', |
| | | onOk() { |
| | | handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)}) |
| | |
| | | |
| | | while (!name && names[item.component]) { |
| | | let _name = names[item.component] + i |
| | | if (menu.components.filter(com => com.setting && com.setting.name === _name).length === 0) { |
| | | if (menu.components.filter(com => com.name === _name).length === 0) { |
| | | name = _name |
| | | } |
| | | i++ |
| | |
| | | >.ant-col { |
| | | padding: 8px; |
| | | } |
| | | > .mk-component-card:hover { |
| | | > .remove-component { |
| | | opacity: 1; |
| | | } |
| | | > div { |
| | | > .model-datasource > .anticon-setting, > .model-menu-tabs-setting > .anticon-setting { |
| | | opacity: 1; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | .anticon { |
| | | cursor: unset; |
| | |
| | | |
| | | .mk-component-card { |
| | | position: relative; |
| | | .remove-component { |
| | | position: absolute; |
| | | right: 42px; |
| | | top: -16px; |
| | | color: #ff4d4f; |
| | | border-radius: 2px; |
| | | font-size: 16px; |
| | | padding: 5px; |
| | | cursor: pointer; |
| | | opacity: 0; |
| | | transition: opacity 0.2s; |
| | | } |
| | | } |
| | | |
| | | >.ant-empty { |
| | | padding-top: 150px; |
| | | } |
| | | |
| | | .model-datasource > .anticon-setting, .model-menu-tabs-setting > .anticon-setting { |
| | | font-size: 16px; |
| | | padding: 5px; |
| | | position: absolute; |
| | | right: 0px; |
| | | top: -30px; |
| | | opacity: 0; |
| | | cursor: pointer; |
| | | transition: opacity 0.2s; |
| | | } |
| | | } |
| | |
| | | const MobSourceElement = ({content}) => { |
| | | const [, drag] = useDrag({ item: content }) |
| | | return ( |
| | | <div ref={drag} className="menu-source-item"> |
| | | <img style={{width: '100%'}} src={content.url} alt=""/> |
| | | <div className="menu-source-item"> |
| | | <div className="property"><span>{content.title}</span></div> |
| | | <img ref={drag} src={content.url} alt=""/> |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | display: inline-block; |
| | | width: 100%; |
| | | margin-bottom: 15px; |
| | | cursor: move; |
| | | height: auto; |
| | | box-shadow: 0px 0px 1px #1890ff; |
| | | |
| | | background-size: cover; |
| | | background-position: top center; |
| | | background-repeat: no-repeat; |
| | | // background-size: cover; |
| | | // background-position: top center; |
| | | // background-repeat: no-repeat; |
| | | |
| | | .property { |
| | | font-size: 14px; |
| | | color: rgba(0, 0, 0, 0.65); |
| | | } |
| | | |
| | | img { |
| | | width: 100%; |
| | | cursor: move; |
| | | box-shadow: 0px 0px 1px #1890ff; |
| | | } |
| | | |
| | | .tooltip-block { |
| | | width: 100%; |
| | |
| | | import line1 from '@/assets/mobimg/line1.png' |
| | | import tabs from '@/assets/mobimg/tabs.png' |
| | | import card1 from '@/assets/mobimg/card1.png' |
| | | import card2 from '@/assets/mobimg/card2.png' |
| | | |
| | | // const _dict = sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS |
| | | |
| | | // 组件配置信息 |
| | | export const menuOptions = [ |
| | | { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs' }, |
| | | { type: 'menu', url: card1, component: 'card', subtype: 'card1' }, |
| | | { type: 'menu', url: line, component: 'line', subtype: 'line' }, |
| | | { type: 'menu', url: line1, component: 'line', subtype: 'line1' }, |
| | | { type: 'menu', url: bar, component: 'bar', subtype: 'bar' }, |
| | | { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1' }, |
| | | { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '标签页' }, |
| | | { type: 'menu', url: card1, component: 'card', subtype: 'datacard', title: '数据卡' }, |
| | | { type: 'menu', url: card2, component: 'card', subtype: 'propcard', title: '属性卡' }, |
| | | { type: 'menu', url: line, component: 'line', subtype: 'line', title: '折线图' }, |
| | | { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '阶梯折线图' }, |
| | | { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '柱状图' }, |
| | | { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '条形图' }, |
| | | ] |
| | |
| | | import React from 'react' |
| | | import { useDrag, useDrop } from 'react-dnd' |
| | | import { Icon } from 'antd' |
| | | |
| | | import asyncComponent from '@/utils/asyncComponent' |
| | | |
| | |
| | | return ( |
| | | <div className="mk-component-card" ref={node => drag(drop(node))} style={style}> |
| | | {getCardComponent()} |
| | | <Icon className="remove-component" title="delete" type="delete" onClick={() => delCard(id)} /> |
| | | </div> |
| | | ) |
| | | } |
| | |
| | | .mob-shell-inner { |
| | | .mk-component-card { |
| | | position: relative; |
| | | .remove-component { |
| | | position: absolute; |
| | | right: 2px; |
| | | top: 50%; |
| | | background: #ff4d4f; |
| | | border-radius: 2px; |
| | | padding: 4px; |
| | | color: #ffffff; |
| | | cursor: pointer; |
| | | display: none; |
| | | } |
| | | } |
| | | .mk-component-card:hover { |
| | | .remove-component { |
| | | display: inline-block; |
| | | } |
| | | } |
| | | >.ant-empty { |
| | | padding-top: 150px; |
| | |
| | | } |
| | | |
| | | let showHeader = false |
| | | if (config.setting.title || _config.plot.datatype === 'statistics') { |
| | | if (config.plot.title || _config.plot.datatype === 'statistics') { |
| | | showHeader = true |
| | | } |
| | | |
| | |
| | | arr_field: _config.columns.map(col => col.field).join(','), |
| | | plot: _config.plot, |
| | | sync: _sync, |
| | | title: config.setting.title, |
| | | title: config.plot.title, |
| | | search: Utils.initMainSearch(config.search), |
| | | showHeader |
| | | }, () => { |
| | |
| | | .custom-line-chart-plot-box { |
| | | // margin-bottom: 30px; |
| | | background: #ffffff; |
| | | |
| | | > .chart-header { |
| | |
| | | return config.components.map(item => { |
| | | if (item.type === 'bar' || item.type === 'line') { |
| | | return ( |
| | | <Col span={item.setting.span} key={item.uuid}> |
| | | <Col span={item.width} key={item.uuid}> |
| | | <AntvBarAndLine config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} /> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'tabs') { |
| | | return ( |
| | | <Col span={item.setting.span} key={item.uuid}> |
| | | <Col span={item.width} key={item.uuid}> |
| | | <AntvTabs config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} /> |
| | | </Col> |
| | | ) |
| | |
| | | return config.components.map(item => { |
| | | if (item.type === 'bar' || item.type === 'line') { |
| | | return ( |
| | | <Col span={item.setting.span} key={item.uuid}> |
| | | <Col span={item.width} key={item.uuid}> |
| | | <AntvBarAndLine config={item} data={data} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} /> |
| | | </Col> |
| | | ) |
| | | } else if (item.type === 'tabs') { |
| | | return ( |
| | | <Col span={item.setting.span} key={item.uuid}> |
| | | <Col span={item.width} key={item.uuid}> |
| | | <AntvTabs config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} /> |
| | | </Col> |
| | | ) |
| | |
| | | } |
| | | .ant-table-body { |
| | | overflow-x: auto!important; |
| | | min-height: 90px; |
| | | // min-height: 90px; |
| | | table { |
| | | .ant-table-tbody > tr > td { |
| | | vertical-align: top; |
| | |
| | | <div className="model-datasource"> |
| | | <Icon type="setting" onClick={() => this.editDataSource()} /> |
| | | <Modal |
| | | wrapClassName="model-datasource-verify-modal popview-modal" |
| | | wrapClassName="popview-modal" |
| | | title={'数据源配置'} |
| | | visible={visible} |
| | | width={'75vw'} |
| | |
| | | } |
| | | } |
| | | } |
| | | .model-datasource-verify-modal { |
| | | .ant-modal { |
| | | top: 50px; |
| | | .ant-modal-body { |
| | | max-height: calc(100vh - 190px); |
| | | } |
| | | } |
| | | } |
New file |
| | |
| | | import React, {Component} from 'react' |
| | | import { Icon } from 'antd' |
| | | |
| | | /** |
| | | * @description 异步加载模块 |
| | | * @param {*} importComponent |
| | | */ |
| | | export default function asyncComponent(importComponent) { |
| | | return class extends Component { |
| | | constructor(props) { |
| | | super(props) |
| | | |
| | | this.state = { |
| | | component: null |
| | | } |
| | | } |
| | | |
| | | async componentDidMount() { |
| | | const {default: component} = await importComponent() |
| | | |
| | | this.setState({component}) |
| | | } |
| | | |
| | | render() { |
| | | const C = this.state.component |
| | | |
| | | return C ? <C {...this.props} /> : <Icon type="loading" /> |
| | | } |
| | | } |
| | | } |
| | |
| | | }, { |
| | | value: 'unlock', |
| | | text: 'unlock' |
| | | }, { |
| | | value: 'right', |
| | | text: 'right' |
| | | }, { |
| | | value: 'left', |
| | | text: 'left' |
| | | }, { |
| | | value: 'double-right', |
| | | text: 'double-right' |
| | | }, { |
| | | value: 'double-left', |
| | | text: 'double-left' |
| | | }] |
| | | |
| | | // 按钮颜色集 |