From 4b5b5a0f13adceaa4a759580b5dc4ac3179f884d Mon Sep 17 00:00:00 2001 From: king <18310653075@163.com> Date: 星期三, 10 三月 2021 18:26:29 +0800 Subject: [PATCH] 2021-03-10 --- src/pc/modulesource/option.jsx | 3 src/menu/components/carousel/prop-card/index.scss | 87 + src/menu/components/card/cardcomponent/settingform/index.jsx | 119 ++ src/menu/components/carousel/cardcomponent/settingform/index.scss | 11 src/menu/components/carousel/data-card/wrapsetting/index.scss | 7 src/tabviews/custom/components/carousel/data-card/index.scss | 49 + src/pc/menushell/index.jsx | 1 src/menu/components/carousel/cardcomponent/index.scss | 0 src/menu/components/carousel/data-card/wrapsetting/index.jsx | 83 + src/tabviews/custom/components/carousel/data-card/index.jsx | 357 +++++++ src/tabviews/custom/components/carousel/prop-card/index.scss | 42 src/menu/components/tabs/tabcomponents/index.jsx | 1 src/menu/menushell/card.jsx | 6 src/menu/stylecombcontroller/index.jsx | 2 src/menu/components/carousel/cardcomponent/index.jsx | 229 ++++ src/tabviews/custom/components/card/data-card/index.scss | 3 src/menu/components/carousel/data-card/index.jsx | 287 +++++ src/views/menudesign/index.jsx | 9 src/menu/modulesource/option.jsx | 3 src/tabviews/custom/components/card/data-card/index.jsx | 100 + src/tabviews/custom/components/card/prop-card/index.scss | 3 src/menu/components/carousel/cardcomponent/settingform/index.jsx | 194 +++ src/tabviews/custom/components/card/prop-card/index.jsx | 99 + src/menu/components/carousel/data-card/wrapsetting/settingform/index.scss | 11 src/assets/mobimg/carousel.png | 0 src/menu/components/card/cardcellcomponent/index.jsx | 2 src/menu/stylecontroller/index.jsx | 4 src/tabviews/custom/components/carousel/cardItem/index.jsx | 56 + src/pc/menushell/card.jsx | 6 src/menu/components/carousel/prop-card/index.jsx | 369 +++++++ src/menu/components/card/cardcomponent/settingform/index.scss | 8 src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx | 214 ++++ src/tabviews/custom/components/carousel/prop-card/index.jsx | 363 +++++++ src/tabviews/custom/index.jsx | 16 src/tabviews/custom/components/carousel/cardItem/index.scss | 58 + src/menu/components/card/prop-card/index.jsx | 2 src/menu/components/carousel/data-card/index.scss | 87 + src/menu/components/tabs/tabcomponents/card.jsx | 6 src/menu/menushell/index.jsx | 1 39 files changed, 2,884 insertions(+), 14 deletions(-) diff --git a/src/assets/mobimg/carousel.png b/src/assets/mobimg/carousel.png new file mode 100644 index 0000000..58750da --- /dev/null +++ b/src/assets/mobimg/carousel.png Binary files differ diff --git a/src/menu/components/card/cardcellcomponent/index.jsx b/src/menu/components/card/cardcellcomponent/index.jsx index 286bed6..c37edfa 100644 --- a/src/menu/components/card/cardcellcomponent/index.jsx +++ b/src/menu/components/card/cardcellcomponent/index.jsx @@ -152,7 +152,7 @@ const { cards, cardCell } = this.props const { card, elements } = this.state - if (comIds.length !== 3 || comIds[0] !== cards.uuid || comIds[1] !== cardCell.uuid) return + if (comIds.length !== 3 || comIds[0] !== cards.uuid || comIds[1] !== cardCell.uuid || !card) return let _card = this.resetCardStyle(card, style) diff --git a/src/menu/components/card/cardcomponent/settingform/index.jsx b/src/menu/components/card/cardcomponent/settingform/index.jsx index 4045ba3..738bd50 100644 --- a/src/menu/components/card/cardcomponent/settingform/index.jsx +++ b/src/menu/components/card/cardcomponent/settingform/index.jsx @@ -1,8 +1,10 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' -import { Form, Row, Col, Radio, Tooltip, Icon, Input, InputNumber, Select } from 'antd' +import { Form, Row, Col, Radio, Tooltip, Icon, Input, InputNumber, Select, Cascader } from 'antd' import './index.scss' + +const { TextArea } = Input class SettingForm extends Component { static propTpyes = { @@ -13,7 +15,32 @@ } state = { - type: this.props.setting.type || 'simple' + 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 = () => { @@ -40,6 +67,7 @@ render() { const { setting, cards } = this.props const { getFieldDecorator } = this.props.form + const { menulist, click, isApp } = this.state const formItemLayout = { labelCol: { @@ -126,6 +154,93 @@ })(<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> diff --git a/src/menu/components/card/cardcomponent/settingform/index.scss b/src/menu/components/card/cardcomponent/settingform/index.scss index 159130b..8898344 100644 --- a/src/menu/components/card/cardcomponent/settingform/index.scss +++ b/src/menu/components/card/cardcomponent/settingform/index.scss @@ -8,4 +8,12 @@ .ant-input-number { width: 100%; } + .textarea { + .ant-form-item-label { + width: 16%; + } + .ant-form-item-control-wrapper { + width: 84%; + } + } } \ No newline at end of file diff --git a/src/menu/components/card/prop-card/index.jsx b/src/menu/components/card/prop-card/index.jsx index 04b042a..bf52a3c 100644 --- a/src/menu/components/card/prop-card/index.jsx +++ b/src/menu/components/card/prop-card/index.jsx @@ -55,7 +55,7 @@ name: card.name, subtype: card.subtype, setting: { interType: 'system' }, - wrap: { name: card.name, width: card.width || 24, title: '', addable: 'false', switch: 'false', datatype: 'static' }, + wrap: { name: card.name, width: card.width || 24, title: '', switch: 'false', datatype: 'static' }, style: { marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px' }, headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' }, columns: [], diff --git a/src/menu/components/carousel/cardcomponent/index.jsx b/src/menu/components/carousel/cardcomponent/index.jsx new file mode 100644 index 0000000..5a3909e --- /dev/null +++ b/src/menu/components/carousel/cardcomponent/index.jsx @@ -0,0 +1,229 @@ +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 \ No newline at end of file diff --git a/src/menu/components/carousel/cardcomponent/index.scss b/src/menu/components/carousel/cardcomponent/index.scss new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/menu/components/carousel/cardcomponent/index.scss diff --git a/src/menu/components/carousel/cardcomponent/settingform/index.jsx b/src/menu/components/carousel/cardcomponent/settingform/index.jsx new file mode 100644 index 0000000..d8046cc --- /dev/null +++ b/src/menu/components/carousel/cardcomponent/settingform/index.jsx @@ -0,0 +1,194 @@ +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) \ No newline at end of file diff --git a/src/menu/components/carousel/cardcomponent/settingform/index.scss b/src/menu/components/carousel/cardcomponent/settingform/index.scss new file mode 100644 index 0000000..159130b --- /dev/null +++ b/src/menu/components/carousel/cardcomponent/settingform/index.scss @@ -0,0 +1,11 @@ +.model-menu-setting-form { + position: relative; + + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + .ant-input-number { + width: 100%; + } +} \ No newline at end of file diff --git a/src/menu/components/carousel/data-card/index.jsx b/src/menu/components/carousel/data-card/index.jsx new file mode 100644 index 0000000..b96cfe1 --- /dev/null +++ b/src/menu/components/carousel/data-card/index.jsx @@ -0,0 +1,287 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { connect } from 'react-redux' +import { is, fromJS } from 'immutable' +import { Icon, Popover, Modal, notification } 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('./wrapsetting')) +const CardComponent = asyncComponent(() => import('../cardcomponent')) +const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent')) +const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) +const UserComponent = asyncIconComponent(() => import('@/menu/components/share/usercomponent')) + +const { confirm } = Modal + +class DataCardEditComponent 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: 'array', // 缁勪欢灞炴�� - 鏁版嵁鏍煎紡 + pageable: false, // 缁勪欢灞炴�� - 鏄惁鍙垎椤� + switchable: false, // 缁勪欢灞炴�� - 鏁版嵁鏄惁鍙垏鎹� + dataName: card.dataName || '', + width: card.width || 24, + name: card.name, + subtype: card.subtype, + setting: { interType: 'system' }, + wrap: { name: card.name, width: card.width || 24, autoplay: 'false', dots: 'true' }, + style: { borderWidth: '1px', borderColor: '#e8e8e8', marginTop: '8px', marginBottom: '8px', height: '300px' }, + columns: [], + scripts: [], + btnlog: [], + subcards: [{ + uuid: Utils.getuuid(), + setting: {}, + style: { + paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px', + }, + elements: [] + }] + } + + 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.elements = scard.elements.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('logButton', this.logButton) + } + + 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('logButton', this.logButton) + } + + logButton = (id, item) => { + const { card } = this.state + + if (id !== card.uuid) return + + let btnlog = card.btnlog || [] + btnlog.push(item) + + this.setState({ + card: {...card, btnlog} + }) + this.props.updateConfig({...card, btnlog}) + } + + /** + * @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) + + if (card.btnlog) { + card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid) + } + + _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) + } + + handleLog = (type, logs, item) => { + let card = fromJS(this.state.card).toJS() + + if (type === 'revert') { + card.subcards.forEach(col => { + col.elements = [...col.elements, item] + if (item.$parentId === col.uuid) { + col.elements = [...col.elements, item] + } + }) + + card.btnlog = logs + + this.setState({ card }) + this.props.updateConfig(card) + notification.success({ + top: 92, + message: '鎭㈠鎴愬姛锛�', + duration: 2 + }) + } else { + card.btnlog = logs + this.setState({ card }) + this.props.updateConfig(card) + notification.success({ + top: 92, + message: '娓呴櫎鎴愬姛锛�', + duration: 2 + }) + } + } + + 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-data-carousel-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"> + <WrapComponent config={card} updateConfig={this.updateComponent}/> + <CopyComponent type="datacard" card={card}/> + <Icon className="style" title="璋冩暣鏍峰紡" onClick={this.changeStyle} type="font-colors"/> + <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog}/> + <UserComponent config={card}/> + <Icon className="close" title="鍒犻櫎缁勪欢" type="delete" onClick={() => this.props.deletecomponent(card.uuid)}/> + <SettingComponent config={card} updateConfig={this.updateComponent}/> + </div> + } trigger="hover"> + <Icon type="tool"/> + </Popover> + <CardComponent cards={card} card={card.subcards[0]} updateElement={this.updateCard} deleteElement={this.deleteCard}/> + </div> + ) + } +} + +const mapStateToProps = (state) => { + return { + menu: state.customMenu + } +} + +const mapDispatchToProps = () => { + return {} +} + +export default connect(mapStateToProps, mapDispatchToProps)(DataCardEditComponent) \ No newline at end of file diff --git a/src/menu/components/carousel/data-card/index.scss b/src/menu/components/carousel/data-card/index.scss new file mode 100644 index 0000000..b62bd6b --- /dev/null +++ b/src/menu/components/carousel/data-card/index.scss @@ -0,0 +1,87 @@ +.menu-data-carousel-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%; + } + + .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; + } + } + .ant-pagination { + float: right; + margin: 10px; + } + + .model-menu-action-list { + .page-card { + line-height: 55px; + } + } +} +.menu-carousel-edit-box::after { + display: block; + content: ' '; + clear: both; +} +.menu-carousel-edit-box:hover { + z-index: 1; + box-shadow: 0px 0px 4px #1890ff; +} diff --git a/src/menu/components/carousel/data-card/wrapsetting/index.jsx b/src/menu/components/carousel/data-card/wrapsetting/index.jsx new file mode 100644 index 0000000..7b28116 --- /dev/null +++ b/src/menu/components/carousel/data-card/wrapsetting/index.jsx @@ -0,0 +1,83 @@ +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="鍗$墖璁剧疆" + 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 \ No newline at end of file diff --git a/src/menu/components/carousel/data-card/wrapsetting/index.scss b/src/menu/components/carousel/data-card/wrapsetting/index.scss new file mode 100644 index 0000000..04372e6 --- /dev/null +++ b/src/menu/components/carousel/data-card/wrapsetting/index.scss @@ -0,0 +1,7 @@ +.model-menu-setting-wrap { + display: inline-block; + + >.anticon-edit { + color: #1890ff; + } +} \ No newline at end of file diff --git a/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx new file mode 100644 index 0000000..0007143 --- /dev/null +++ b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.jsx @@ -0,0 +1,214 @@ +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={ + <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} + <Col span={12}> + <Form.Item label="鑷姩鍒囨崲"> + {getFieldDecorator('autoplay', { + initialValue: wrap.autoplay || 'false' + })( + <Radio.Group> + <Radio value="false">鍚�</Radio> + <Radio value="true">鏄�</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={12}> + <Form.Item label={ + <Tooltip placement="topLeft" title="浣跨敤鑷姩鍒囨崲鏃舵湁鏁堬紝榛樿涓�3绉掋��"> + <Icon type="question-circle" /> + 鏃堕棿闂撮殧 + </Tooltip> + }> + {getFieldDecorator('speed', { + initialValue: wrap.speed || 3 + })(<InputNumber min={1} max={100} precision={0} onPressEnter={this.handleSubmit} />)} + </Form.Item> + </Col> + <Col span={12}> + <Form.Item label="鎸囩ず鐐�"> + {getFieldDecorator('dots', { + initialValue: wrap.dots || 'true' + })( + <Radio.Group> + <Radio value="true">鏄剧ず</Radio> + <Radio value="false">闅愯棌</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={12}> + <Form.Item label="鎸囩ず鐐逛綅缃�"> + {getFieldDecorator('dotPosition', { + initialValue: wrap.dotPosition || 'bottom' + })( + <Radio.Group> + <Radio value="top">涓�</Radio> + <Radio value="bottom">涓�</Radio> + <Radio value="left">宸�</Radio> + <Radio value="right">鍙�</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <Col span={12}> + <Form.Item label="鍔ㄧ敾鏁堟灉"> + {getFieldDecorator('effect', { + initialValue: wrap.effect || 'scrollx' + })( + <Radio.Group> + <Radio value="scrollx">鍒囨崲</Radio> + <Radio value="fade">娓愭樉</Radio> + </Radio.Group> + )} + </Form.Item> + </Col> + <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) \ No newline at end of file diff --git a/src/menu/components/carousel/data-card/wrapsetting/settingform/index.scss b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.scss new file mode 100644 index 0000000..159130b --- /dev/null +++ b/src/menu/components/carousel/data-card/wrapsetting/settingform/index.scss @@ -0,0 +1,11 @@ +.model-menu-setting-form { + position: relative; + + .anticon-question-circle { + color: #c49f47; + margin-right: 3px; + } + .ant-input-number { + width: 100%; + } +} \ No newline at end of file diff --git a/src/menu/components/carousel/prop-card/index.jsx b/src/menu/components/carousel/prop-card/index.jsx new file mode 100644 index 0000000..2bdb7d0 --- /dev/null +++ b/src/menu/components/carousel/prop-card/index.jsx @@ -0,0 +1,369 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import {connect} from 'react-redux' +import { is, fromJS } from 'immutable' +import { Icon, Popover, Modal, notification, 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('../data-card/wrapsetting')) +const CardComponent = asyncComponent(() => import('../cardcomponent')) +const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent')) +const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent')) +const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent')) +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', autoplay: 'false', dots: 'true' }, + style: { borderWidth: '1px', borderColor: '#e8e8e8', marginLeft: '0px', marginRight: '0px', marginTop: '8px', marginBottom: '8px', height: '300px' }, + columns: [], + scripts: [], + subcards: [{ + uuid: Utils.getuuid(), + setting: {}, + style: {}, + elements: [], + }], + btnlog: [], + } + + 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.elements = scard.elements.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('logButton', this.logButton) + 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('logButton', this.logButton) + 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}) + }) + } + + logButton = (id, item) => { + const { card } = this.state + + if (id !== card.uuid) return + + let btnlog = card.btnlog || [] + btnlog.push(item) + + this.setState({ + card: {...card, btnlog} + }) + this.props.updateConfig({...card, btnlog}) + } + + /** + * @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) + + if (card.btnlog) { + card.btnlog = card.btnlog.filter(c => c.$parentId !== cell.uuid) + } + + _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) + } + + handleLog = (type, logs, item) => { + let card = fromJS(this.state.card).toJS() + + if (type === 'revert') { + let done = false + if (item.$parentId) { + card.subcards.forEach(col => { + if (item.$parentId === col.uuid) { + col.elements = [...col.elements, item] + done = true + } + }) + } + + card.btnlog = logs + + this.setState({ card: {...card, subcards: []} }, () => { + this.setState({ card }) + this.props.updateConfig(card) + }) + if (!done) { + notification.warning({ + top: 92, + message: '闄勫睘鍗$墖宸插垹闄わ紒', + duration: 2 + }) + } else { + notification.success({ + top: 92, + message: '鎭㈠鎴愬姛锛�', + duration: 2 + }) + } + } else { + card.btnlog = logs + this.setState({ card }) + this.props.updateConfig(card) + notification.success({ + top: 92, + message: '娓呴櫎鎴愬姛锛�', + duration: 2 + }) + } + } + + 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-prop-carousel-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" /> + <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} /> + <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) \ No newline at end of file diff --git a/src/menu/components/carousel/prop-card/index.scss b/src/menu/components/carousel/prop-card/index.scss new file mode 100644 index 0000000..a53e20c --- /dev/null +++ b/src/menu/components/carousel/prop-card/index.scss @@ -0,0 +1,87 @@ +.menu-prop-carousel-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: 5px; + } + } + .ant-carousel.ant-carousel-vertical { + .slick-dots li button { + width: 5px; + } + } + + .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-prop-card-edit-box::after { + display: block; + content: ' '; + clear: both; +} +.menu-prop-card-edit-box:hover { + z-index: 1; + box-shadow: 0px 0px 4px #1890ff; +} diff --git a/src/menu/components/tabs/tabcomponents/card.jsx b/src/menu/components/tabs/tabcomponents/card.jsx index 416ca65..ca9c1fe 100644 --- a/src/menu/components/tabs/tabcomponents/card.jsx +++ b/src/menu/components/tabs/tabcomponents/card.jsx @@ -10,6 +10,8 @@ const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs')) const DataCard = asyncComponent(() => import('@/menu/components/card/data-card')) const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card')) +const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card')) +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 NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group')) @@ -61,6 +63,10 @@ return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard} />) } else if (card.type === 'card' && card.subtype === 'propcard') { return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'datacard') { + return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'propcard') { + return (<CarouselPropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'tablecard') { return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'normaltable') { diff --git a/src/menu/components/tabs/tabcomponents/index.jsx b/src/menu/components/tabs/tabcomponents/index.jsx index 6bf8943..60a625c 100644 --- a/src/menu/components/tabs/tabcomponents/index.jsx +++ b/src/menu/components/tabs/tabcomponents/index.jsx @@ -97,6 +97,7 @@ table: '琛ㄦ牸', group: '鍒嗙粍', editor: '瀵屾枃鏈�', + carousel: '杞挱', card: '鍗$墖' } let i = 1 diff --git a/src/menu/menushell/card.jsx b/src/menu/menushell/card.jsx index 1413357..8150032 100644 --- a/src/menu/menushell/card.jsx +++ b/src/menu/menushell/card.jsx @@ -10,6 +10,8 @@ const AntvTabs = asyncComponent(() => import('@/menu/components/tabs/antv-tabs')) const DataCard = asyncComponent(() => import('@/menu/components/card/data-card')) const PropCard = asyncComponent(() => import('@/menu/components/card/prop-card')) +const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card')) +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 NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group')) @@ -62,6 +64,10 @@ return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'card' && card.subtype === 'propcard') { return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'datacard') { + return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'propcard') { + return (<CarouselPropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'tablecard') { return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'normaltable') { diff --git a/src/menu/menushell/index.jsx b/src/menu/menushell/index.jsx index cb51df3..fc5d648 100644 --- a/src/menu/menushell/index.jsx +++ b/src/menu/menushell/index.jsx @@ -91,6 +91,7 @@ group: '鍒嗙粍', editor: '瀵屾枃鏈�', code: '鑷畾涔�', + carousel: '杞挱', card: '鍗$墖' } let i = 1 diff --git a/src/menu/modulesource/option.jsx b/src/menu/modulesource/option.jsx index 9c0a333..1996e96 100644 --- a/src/menu/modulesource/option.jsx +++ b/src/menu/modulesource/option.jsx @@ -14,6 +14,7 @@ import Pie1 from '@/assets/mobimg/ring.png' import Pie2 from '@/assets/mobimg/nightingale.png' import Mainsearch from '@/assets/mobimg/mainsearch.png' +import Carousel from '@/assets/mobimg/carousel.png' // 缁勪欢閰嶇疆淇℃伅 export const menuOptions = [ @@ -21,6 +22,8 @@ { 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: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24, forbid: ['billPrint'] }, + { type: 'menu', url: Carousel, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24, forbid: ['billPrint'] }, { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 }, { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 }, { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 }, diff --git a/src/menu/stylecombcontroller/index.jsx b/src/menu/stylecombcontroller/index.jsx index b69ffb2..6a9d18a 100644 --- a/src/menu/stylecombcontroller/index.jsx +++ b/src/menu/stylecombcontroller/index.jsx @@ -260,7 +260,7 @@ label={<Icon title="楂樺害" type="column-height" />} labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } > - <StyleInput defaultValue={''} options={['px']} onChange={this.changeHeight}/> + <StyleInput defaultValue={''} options={['px', 'vh', 'vw']} onChange={this.changeHeight}/> </Form.Item> </Col> </Panel> : null} diff --git a/src/menu/stylecontroller/index.jsx b/src/menu/stylecontroller/index.jsx index cc674a1..595e8ff 100644 --- a/src/menu/stylecontroller/index.jsx +++ b/src/menu/stylecontroller/index.jsx @@ -329,7 +329,7 @@ label={<Icon title="瀹藉害" type="column-width" />} labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } > - <StyleInput defaultValue={card.width || ''} options={['px']} onChange={this.changeWidth}/> + <StyleInput defaultValue={card.width || ''} options={['px', 'vh', 'vw']} onChange={this.changeWidth}/> </Form.Item> </Col> </Panel> : null} @@ -340,7 +340,7 @@ label={<Icon title="楂樺害" type="column-height" />} labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} } > - <StyleInput defaultValue={card.height || ''} options={['px']} onChange={this.changeHeight}/> + <StyleInput defaultValue={card.height || ''} options={['px', 'vh', 'vw']} onChange={this.changeHeight}/> </Form.Item> </Col> </Panel> : null} diff --git a/src/pc/menushell/card.jsx b/src/pc/menushell/card.jsx index 06beb23..aef7d95 100644 --- a/src/pc/menushell/card.jsx +++ b/src/pc/menushell/card.jsx @@ -16,6 +16,8 @@ const BraftEditor = asyncComponent(() => import('@/menu/components/editor/braft-editor')) const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox')) const NormalNavbar = asyncComponent(() => import('@/pc/components/navbar/normal-navbar')) +const CarouselDataCard = asyncComponent(() => import('@/menu/components/carousel/data-card')) +const CarouselPropCard = asyncComponent(() => import('@/menu/components/carousel/prop-card')) const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => { const originalIndex = findCard(id).index @@ -69,6 +71,10 @@ return (<DataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'card' && card.subtype === 'propcard') { return (<PropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'datacard') { + return (<CarouselDataCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) + } else if (card.type === 'carousel' && card.subtype === 'propcard') { + return (<CarouselPropCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'tablecard') { return (<TableCard card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'table' && card.subtype === 'normaltable') { diff --git a/src/pc/menushell/index.jsx b/src/pc/menushell/index.jsx index 714e6c9..f8e35be 100644 --- a/src/pc/menushell/index.jsx +++ b/src/pc/menushell/index.jsx @@ -101,6 +101,7 @@ editor: '瀵屾枃鏈�', code: '鑷畾涔�', navbar: '瀵艰埅鏍�', + carousel: '杞挱', card: '鍗$墖' } let i = 1 diff --git a/src/pc/modulesource/option.jsx b/src/pc/modulesource/option.jsx index 81ce70d..2627a6c 100644 --- a/src/pc/modulesource/option.jsx +++ b/src/pc/modulesource/option.jsx @@ -15,6 +15,7 @@ import Pie2 from '@/assets/mobimg/nightingale.png' import Mainsearch from '@/assets/mobimg/mainsearch.png' import Navbar from '@/assets/mobimg/navbar.png' +import Carousel from '@/assets/mobimg/carousel.png' // 缁勪欢閰嶇疆淇℃伅 export const menuOptions = [ @@ -23,6 +24,8 @@ { type: 'menu', url: Mainsearch, component: 'search', subtype: 'mainsearch', title: '鎼滅储鏉′欢', width: 24 }, { 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: Carousel, component: 'carousel', subtype: 'datacard', title: '杞挱-鍔ㄦ�佹暟鎹�', width: 24 }, + { type: 'menu', url: Carousel, component: 'carousel', subtype: 'propcard', title: '杞挱-闈欐�佹暟鎹�', width: 24 }, { type: 'menu', url: NormalTable, component: 'table', subtype: 'normaltable', title: '甯哥敤琛�', width: 24 }, { type: 'menu', url: TableCard, component: 'table', subtype: 'tablecard', title: '琛ㄦ牸', width: 12 }, { type: 'menu', url: line, component: 'line', subtype: 'line', title: '鎶樼嚎鍥�', width: 24 }, diff --git a/src/tabviews/custom/components/card/data-card/index.jsx b/src/tabviews/custom/components/card/data-card/index.jsx index 30ba645..313cd88 100644 --- a/src/tabviews/custom/components/card/data-card/index.jsx +++ b/src/tabviews/custom/components/card/data-card/index.jsx @@ -1,6 +1,7 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' +import { connect } from 'react-redux' import { Spin, Empty, notification, Col, Pagination } from 'antd' import Api from '@/api' @@ -10,6 +11,7 @@ import nextImg from '@/assets/img/next.png' import MKEmitter from '@/utils/events.js' import asyncComponent from '@/utils/asyncComponent' +import { modifyTabview } from '@/store/action' import './index.scss' const CardItem = asyncComponent(() => import('../cardItem')) @@ -394,8 +396,10 @@ changeCard = (index, item) => { const { config, selectKeys, selectedData, activeKey } = this.state - if (!config.wrap.cardType) return + this.openView(item) + if (!config.wrap.cardType) return + let _selectKeys = [] let _selectedData = [] let _activeKey = '' @@ -430,6 +434,83 @@ }) MKEmitter.emit('resetSelectLine', config.uuid, (_item ? _item.$$uuid : ''), _item) + } + + openView = (item) => { + const { card } = this.state + + if (card.setting.click === 'menu') { + let menu = null + + if (card.setting.menu && card.setting.menu.length > 0) { + let menu_id = card.setting.menu.slice(-1)[0] + menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' + } + + if (!menu) { + notification.warning({ + top: 92, + message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�', + duration: 5 + }) + return + } + + let newtab = { + ...menu, + selected: true, + param: {} + } + + if (card.setting.joint === 'true') { + newtab.param.BID = item.$$uuid + } + + if (['linkage_navigation', 'linkage'].includes(window.GLOB.navBar)) { + this.props.modifyTabview([newtab]) + } else { + let tabs = this.props.tabviews.filter((tab, i) => { + tab.selected = false + return tab.MenuID !== newtab.MenuID + }) + + if (this.props.tabviews.length !== tabs.length) { + this.props.modifyTabview(fromJS(tabs).toJS()) + } + + this.setState({}, () => { + tabs.push(newtab) + this.props.modifyTabview(tabs) + }) + } + } else if (card.setting.click === 'link') { + let src = card.setting.linkurl + + if (src.indexOf('paramsmain/') > -1) { + try { + let _url = src.split('paramsmain/')[0] + 'paramsmain/' + let _param = JSON.parse(window.decodeURIComponent(window.atob(src.split('paramsmain/')[1]))) + + _param.UserID = sessionStorage.getItem('UserID') + _param.LoginUID = sessionStorage.getItem('LoginUID') + _param.User_Name = sessionStorage.getItem('User_Name') + _param.param = { BID: item.$$uuid } + src = _url + window.btoa(window.encodeURIComponent(JSON.stringify(_param))) + } catch { + console.warn('鑿滃崟鍙傛暟瑙f瀽閿欒锛�') + } + } else if (card.setting.joint === 'true') { + let con = '?' + + if (/\?/ig.test(src)) { + con = '&' + } + + src = src + `${con}id=${item.$$uuid}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}` + } + + window.open(src) + } } render() { @@ -475,7 +556,7 @@ {switchable ? <div className={'prev-page ' + (pageIndex === 1 ? 'disabled' : '')} onClick={this.prevPage}><div><div><img src={preImg} alt=""/></div></div></div> : null} {data && data.length > 0 ? <div className="card-row-list"> {data.map((item, index) => ( - <Col className={activeKey === index ? 'active' : (selectKeys.indexOf(index) > -1 ? 'selected' : '')} key={index} span={card.setting.width} offset={!index ? offset : 0} onClick={() => {this.changeCard(index, item)}}> + <Col className={(activeKey === index ? 'active' : (selectKeys.indexOf(index) > -1 ? 'selected' : '')) + (card.setting.click ? ' pointer' : '')} key={index} span={card.setting.width} offset={!index ? offset : 0} onClick={() => {this.changeCard(index, item)}}> <CardItem card={card} cards={config} data={item}/> </Col> ))} @@ -489,4 +570,17 @@ } } -export default DataCard \ No newline at end of file +const mapStateToProps = (state) => { + return { + permMenus: state.permMenus, + tabviews: state.tabviews, + } +} + +const mapDispatchToProps = (dispatch) => { + return { + modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(DataCard) \ No newline at end of file diff --git a/src/tabviews/custom/components/card/data-card/index.scss b/src/tabviews/custom/components/card/data-card/index.scss index c9e972b..49e69ef 100644 --- a/src/tabviews/custom/components/card/data-card/index.scss +++ b/src/tabviews/custom/components/card/data-card/index.scss @@ -74,6 +74,9 @@ background-color: #ffffff; transition: all 0.3s; } + >.pointer { + cursor: pointer; + } >.active >.card-item-box { border-color: #1890ff!important; box-shadow: 0 0 4px #1890ff; diff --git a/src/tabviews/custom/components/card/prop-card/index.jsx b/src/tabviews/custom/components/card/prop-card/index.jsx index f621976..bce3459 100644 --- a/src/tabviews/custom/components/card/prop-card/index.jsx +++ b/src/tabviews/custom/components/card/prop-card/index.jsx @@ -1,18 +1,20 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { is, fromJS } from 'immutable' +import { connect } from 'react-redux' import { Spin, notification, Col } from 'antd' import asyncComponent from '@/utils/asyncComponent' import Api from '@/api' import UtilsDM from '@/utils/utils-datamanage.js' import MKEmitter from '@/utils/events.js' +import { modifyTabview } from '@/store/action' import './index.scss' const CardItem = asyncComponent(() => import('../cardItem')) const NormalHeader = asyncComponent(() => import('@/tabviews/custom/components/share/normalheader')) -class DataCard extends Component { +class PropCard extends Component { static propTpyes = { BID: PropTypes.any, // 鐖剁骇Id data: PropTypes.array, // 缁熶竴鏌ヨ鏁版嵁 @@ -257,6 +259,8 @@ changeCard = (index, item) => { const { config, data, activeKey } = this.state + this.openView(item) + if (!config.wrap.cardType || activeKey === index) return this.setState({ @@ -265,6 +269,82 @@ MKEmitter.emit('resetSelectLine', config.uuid, (item.setting.primaryId || ''), data) } + + openView = (item) => { + if (item.setting.click === 'menu') { + let menu = null + + if (item.setting.menu && item.setting.menu.length > 0) { + let menu_id = item.setting.menu.slice(-1)[0] + menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' + } + + if (!menu) { + notification.warning({ + top: 92, + message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�', + duration: 5 + }) + return + } + + let newtab = { + ...menu, + selected: true, + param: {} + } + + if (item.setting.joint === 'true') { + newtab.param.BID = item.setting.primaryId + } + + if (['linkage_navigation', 'linkage'].includes(window.GLOB.navBar)) { + this.props.modifyTabview([newtab]) + } else { + let tabs = this.props.tabviews.filter((tab, i) => { + tab.selected = false + return tab.MenuID !== newtab.MenuID + }) + + if (this.props.tabviews.length !== tabs.length) { + this.props.modifyTabview(fromJS(tabs).toJS()) + } + + this.setState({}, () => { + tabs.push(newtab) + this.props.modifyTabview(tabs) + }) + } + } else if (item.setting.click === 'link') { + let src = item.setting.linkurl + + if (src.indexOf('paramsmain/') > -1) { + try { + let _url = src.split('paramsmain/')[0] + 'paramsmain/' + let _param = JSON.parse(window.decodeURIComponent(window.atob(src.split('paramsmain/')[1]))) + + _param.UserID = sessionStorage.getItem('UserID') + _param.LoginUID = sessionStorage.getItem('LoginUID') + _param.User_Name = sessionStorage.getItem('User_Name') + _param.param = { BID: item.setting.primaryId } + src = _url + window.btoa(window.encodeURIComponent(JSON.stringify(_param))) + } catch { + console.warn('鑿滃崟鍙傛暟瑙f瀽閿欒锛�') + } + } else if (item.setting.joint === 'true') { + let con = '?' + + if (/\?/ig.test(src)) { + con = '&' + } + + src = src + `${con}id=${item.setting.primaryId}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}` + } + + window.open(src) + } + } + render() { const { config, loading, data, activeKey } = this.state @@ -280,7 +360,7 @@ <NormalHeader config={config}/> <div className={`card-row-list ${config.wrap.cardType || ''} ${config.wrap.scale || ''}`}> {config.subcards.map((item, index) => ( - <Col className={activeKey === index ? 'active' : ''} key={index} span={item.setting.width || 6} offset={item.offset || 0} onClick={() => {this.changeCard(index, item)}}> + <Col className={(activeKey === index ? 'active' : '') + (item.setting.click ? ' pointer' : '')} key={index} span={item.setting.width || 6} offset={item.offset || 0} onClick={() => {this.changeCard(index, item)}}> <CardItem card={item} cards={config} data={data}/> </Col> ))} @@ -290,4 +370,17 @@ } } -export default DataCard \ No newline at end of file +const mapStateToProps = (state) => { + return { + permMenus: state.permMenus, + tabviews: state.tabviews, + } +} + +const mapDispatchToProps = (dispatch) => { + return { + modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(PropCard) \ No newline at end of file diff --git a/src/tabviews/custom/components/card/prop-card/index.scss b/src/tabviews/custom/components/card/prop-card/index.scss index 7ec304d..12c5e88 100644 --- a/src/tabviews/custom/components/card/prop-card/index.scss +++ b/src/tabviews/custom/components/card/prop-card/index.scss @@ -17,6 +17,9 @@ background-color: #ffffff; transition: all 0.3s; } + >.pointer { + cursor: pointer; + } >.active >.card-item-box { border-color: #1890ff!important; box-shadow: 0 0 4px #1890ff; diff --git a/src/tabviews/custom/components/carousel/cardItem/index.jsx b/src/tabviews/custom/components/carousel/cardItem/index.jsx new file mode 100644 index 0000000..8b06726 --- /dev/null +++ b/src/tabviews/custom/components/carousel/cardItem/index.jsx @@ -0,0 +1,56 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' + +import asyncComponent from '@/utils/asyncComponent' +import zhCN from '@/locales/zh-CN/model.js' +import enUS from '@/locales/en-US/model.js' + +import './index.scss' + +const CardCellComponent = asyncComponent(() => import('@/tabviews/custom/components/card/cardcellList')) + +class CardBoxComponent extends Component { + static propTpyes = { + cards: PropTypes.object, // 鍗$墖琛岄厤缃俊鎭� + card: PropTypes.object, // 鍗$墖閰嶇疆淇℃伅 + data: PropTypes.object, + } + + state = { + dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, + card: null, // 鍗$墖淇℃伅锛屽寘鎷鍙嶉潰 + } + + /** + * @description 鎼滅储鏉′欢鍒濆鍖� + */ + UNSAFE_componentWillMount () { + + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.state), fromJS(nextState)) || !is(fromJS(this.props), fromJS(nextProps)) + } + + /** + * @description 缁勪欢閿�姣侊紝娓呴櫎state鏇存柊锛屾竻闄ゅ揩鎹烽敭璁剧疆 + */ + componentWillUnmount () { + this.setState = () => { + return + } + } + + render() { + const { card, data, cards } = this.props + + return ( + <div className="card-item-box" style={card.style}> + <CardCellComponent data={data} cards={cards} cardCell={card} elements={card.elements}/> + </div> + ) + } +} + +export default CardBoxComponent \ No newline at end of file diff --git a/src/tabviews/custom/components/carousel/cardItem/index.scss b/src/tabviews/custom/components/carousel/cardItem/index.scss new file mode 100644 index 0000000..605a96b --- /dev/null +++ b/src/tabviews/custom/components/carousel/cardItem/index.scss @@ -0,0 +1,58 @@ +.card-item-box { + position: relative; + overflow: hidden; + + .back-side { + position: absolute; + top: 0px; + left: 0px; + right: 0px; + bottom: 0px; + background-color: #ffffff; + transition: all 0.3s; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + } + .back-side.up { + transform: translate(0, 100%); + } + .back-side.down { + transform: translate(0, -100%); + } + .back-side.left { + transform: translate(100%, 0); + } + .back-side.right { + transform: translate(-100%, 0); + } + .back-side.opacity { + opacity: 0; + } + .back-side.rotateX { + transform: rotateX(90deg); + } + .back-side.rotateY { + transform: rotateY(90deg); + } + .back-side.scale { + transform: scale(0, 0); + } +} +.card-item-box:hover { + .back-side.up, .back-side.down, .back-side.left, .back-side.right { + transform: translate(0, 0); + } + .back-side.opacity { + opacity: 1; + } + .back-side.rotateX { + transform: rotateX(0deg); + } + .back-side.rotateY { + transform: rotateY(0deg); + } + .back-side.scale { + transform: scale(1, 1); + } +} \ No newline at end of file diff --git a/src/tabviews/custom/components/carousel/data-card/index.jsx b/src/tabviews/custom/components/carousel/data-card/index.jsx new file mode 100644 index 0000000..56b9535 --- /dev/null +++ b/src/tabviews/custom/components/carousel/data-card/index.jsx @@ -0,0 +1,357 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { connect } from 'react-redux' +import { Spin, Empty, notification, Carousel } from 'antd' + +import Api from '@/api' +import UtilsDM from '@/utils/utils-datamanage.js' +import MKEmitter from '@/utils/events.js' +import asyncComponent from '@/utils/asyncComponent' +import { modifyTabview } from '@/store/action' +import './index.scss' + +const CardItem = asyncComponent(() => import('../cardItem')) + +class DataCard extends Component { + static propTpyes = { + BID: PropTypes.any, // 鐖剁骇Id + data: PropTypes.array, // 缁熶竴鏌ヨ鏁版嵁 + config: PropTypes.object, // 缁勪欢閰嶇疆淇℃伅 + mainSearch: PropTypes.any, // 澶栧眰鎼滅储鏉′欢 + menuType: PropTypes.any, // 鑿滃崟绫诲瀷 + } + + state = { + BID: '', // 涓婄骇ID + config: null, // 鍥捐〃閰嶇疆淇℃伅 + loading: false, // 鏁版嵁鍔犺浇鐘舵�� + sync: false, // 鏄惁缁熶竴璇锋眰鏁版嵁 + card: null, // 鍗$墖璁剧疆 + data: null, // 鏁版嵁 + } + + UNSAFE_componentWillMount () { + const { data, initdata, BID } = this.props + let _config = fromJS(this.props.config).toJS() + let _card = _config.subcards[0] + let _cols = new Map() + + let _data = null + let _sync = _config.setting.sync === 'true' + + if (_config.setting.sync === 'true' && data) { + _data = data[_config.dataName] || [] + _sync = false + } else if (_config.setting.sync === 'true' && initdata) { + _data = initdata || [] + _sync = false + } + + if (_data) { + _data = _data.map((item, index) => { + item.key = index + item.$$uuid = item[_config.setting.primaryKey] || '' + item.$$BID = BID || '' + return item + }) + } + + _config.columns.forEach(item => { + _cols.set(item.field, item) + }) + + _card.style.height = _config.style.height + + if (_card.setting.click) { + _card.style.cursor = 'pointer' + } + + _card.elements = _card.elements.map(item => { + if (item.field && _cols.has(item.field)) { + item.col = _cols.get(item.field) + } + return item + }) + + _config.wrap.speed = (_config.wrap.speed || 3) * 1000 + + this.setState({ + sync: _sync, + data: _data, + BID: BID || '', + config: _config, + card: _card, + arr_field: _config.columns.map(col => col.field).join(','), + }, () => { + if (_config.setting.sync !== 'true' && _config.setting.onload === 'true') { + this.loadData() + } + }) + } + + componentDidMount () { + MKEmitter.addListener('resetSelectLine', this.resetParentParam) + MKEmitter.addListener('getexceloutparam', this.getexceloutparam) + MKEmitter.addListener('refreshByButtonResult', this.refreshByButtonResult) + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.state), fromJS(nextState)) + } + + UNSAFE_componentWillReceiveProps (nextProps) { + const { sync, config, BID } = this.state + + if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) { + let _data = [] + if (nextProps.data && nextProps.data[config.dataName]) { + _data = nextProps.data[config.dataName] || [] + } + + _data = _data.map((item, index) => { + item.key = index + item.$$uuid = item[config.setting.primaryKey] || '' + item.$$BID = BID || '' + return item + }) + + this.setState({sync: false, data: _data}) + } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { + if (config.setting.syncRefresh === 'true') { + this.setState({}, () => { + this.loadData() + }) + } + } + } + + componentWillUnmount () { + this.setState = () => { + return + } + MKEmitter.removeListener('resetSelectLine', this.resetParentParam) + MKEmitter.removeListener('getexceloutparam', this.getexceloutparam) + MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult) + } + + /** + * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂� + * @param {*} menuId // 鑿滃崟Id + * @param {*} position // 鍒锋柊浣嶇疆 + * @param {*} btn // 鎵ц鐨勬寜閽� + */ + refreshByButtonResult = (menuId, position, btn) => { + const { config, BID } = this.state + + if (config.uuid !== menuId) return + + this.loadData(btn) // 鏁版嵁鍒锋柊 + + if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) { + MKEmitter.emit('reloadData', btn.syncComponentId) // 鍚岀骇鏍囩鍒锋柊 + } + + if (position === 'mainline' && config.setting.supModule) { // 涓昏〃琛屽埛鏂� + MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) + } else if (position === 'popclose') { // 鏍囩鍏抽棴鍒锋柊 + config.setting.supModule && MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) + btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId) + } + } + + resetParentParam = (MenuID, id, data) => { + const { config } = this.state + + if (!config.setting.supModule || config.setting.supModule !== MenuID) return + if (id !== this.state.BID) { + this.setState({ BID: id }, () => { + this.loadData() + }) + } + } + + /** + * @description 瀵煎嚭Excel鏃讹紝鑾峰彇椤甸潰鎼滅储鎺掑簭绛夊弬鏁� + */ + getexceloutparam = (menuId, btnId) => { + const { mainSearch } = this.props + const { arr_field, config } = this.state + + if (config.uuid !== menuId) return + + let searches = mainSearch ? fromJS(mainSearch).toJS() : [] + + MKEmitter.emit('execExcelout', config.uuid, btnId, { + arr_field: arr_field, + orderBy: config.setting.order || '', + search: searches, + menuName: config.name + }) + } + + async loadData () { + const { mainSearch, menuType } = this.props + const { config, arr_field, BID } = this.state + + if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇� + this.setState({ + data: [], + loading: false + }) + return + } + + let searches = mainSearch ? fromJS(mainSearch).toJS() : [] + + this.setState({ + loading: true + }) + + let _orderBy = config.setting.order || '' + let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, '', '', BID, menuType) + + let result = await Api.genericInterface(param) + if (result.status) { + this.setState({ + data: result.data.map((item, index) => { + item.key = index + item.$$uuid = item[config.setting.primaryKey] || '' + item.$$BID = BID || '' + return item + }), + loading: false + }) + } else { + this.setState({ + loading: false + }) + notification.error({ + top: 92, + message: result.message, + duration: 10 + }) + } + } + + openView = (item) => { + const { card } = this.state + + if (card.setting.click === 'menu') { + let menu = null + + if (card.setting.menu && card.setting.menu.length > 0) { + let menu_id = card.setting.menu.slice(-1)[0] + menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' + } + + if (!menu) { + notification.warning({ + top: 92, + message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�', + duration: 5 + }) + return + } + + let newtab = { + ...menu, + selected: true, + param: {} + } + + if (card.setting.joint === 'true') { + newtab.param.BID = item.$$uuid + } + + if (['linkage_navigation', 'linkage'].includes(window.GLOB.navBar)) { + this.props.modifyTabview([newtab]) + } else { + let tabs = this.props.tabviews.filter((tab, i) => { + tab.selected = false + return tab.MenuID !== newtab.MenuID + }) + + if (this.props.tabviews.length !== tabs.length) { + this.props.modifyTabview(fromJS(tabs).toJS()) + } + + this.setState({}, () => { + tabs.push(newtab) + this.props.modifyTabview(tabs) + }) + } + } else if (card.setting.click === 'link') { + let src = card.setting.linkurl + + if (src.indexOf('paramsmain/') > -1) { + try { + let _url = src.split('paramsmain/')[0] + 'paramsmain/' + let _param = JSON.parse(window.decodeURIComponent(window.atob(src.split('paramsmain/')[1]))) + + _param.UserID = sessionStorage.getItem('UserID') + _param.LoginUID = sessionStorage.getItem('LoginUID') + _param.User_Name = sessionStorage.getItem('User_Name') + _param.param = { BID: item.$$uuid } + src = _url + window.btoa(window.encodeURIComponent(JSON.stringify(_param))) + } catch { + console.warn('鑿滃崟鍙傛暟瑙f瀽閿欒锛�') + } + } else if (card.setting.joint === 'true') { + let con = '?' + + if (/\?/ig.test(src)) { + con = '&' + } + + src = src + `${con}id=${item.$$uuid}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}` + } + + window.open(src) + } + } + + render() { + const { config, loading, data, card } = this.state + + return ( + <div className="custom-data-carousel-box" style={{...config.style, minHeight: config.wrap.minHeight}}> + {loading ? + <div className="loading-mask"> + {data ? <div className="ant-spin-blur"></div> : null} + <Spin /> + </div> : null + } + {data && data.length > 0 ? <Carousel + autoplay={config.wrap.autoplay !== 'false'} + dots={config.wrap.dots !== 'false'} + dotPosition={config.wrap.dotPosition || 'bottom'} + effect={config.wrap.effect || 'scrollx'} + autoplaySpeed={config.wrap.speed} + > + {data.map((item, index) => ( + <div key={index} onClick={() => {this.openView(item)}}> + <CardItem card={card} cards={config} data={item}/> + </div> + ))} + </Carousel> : null} + {!data || data.length === 0 ? <Empty description={false}/> : null} + </div> + ) + } +} + +const mapStateToProps = (state) => { + return { + permMenus: state.permMenus, + tabviews: state.tabviews, + } +} + +const mapDispatchToProps = (dispatch) => { + return { + modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(DataCard) \ No newline at end of file diff --git a/src/tabviews/custom/components/carousel/data-card/index.scss b/src/tabviews/custom/components/carousel/data-card/index.scss new file mode 100644 index 0000000..15319b2 --- /dev/null +++ b/src/tabviews/custom/components/carousel/data-card/index.scss @@ -0,0 +1,49 @@ +.custom-data-carousel-box { + background: #ffffff; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + min-height: 30px; + + .card-item-box { + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + } + + .ant-empty { + width: 100%; + min-height: 100px; + padding-top: 15px; + + .ant-empty-image { + height: 60px; + } + } + .loading-mask { + position: absolute; + left: 0px; + top: 0; + right: 0px; + bottom: 0px; + display: flex; + align-items: center; + justify-content: center; + text-align: justify; + z-index: 1; + + .ant-spin-blur { + position: absolute; + width: 100%; + height: 100%; + opacity: 0.5; + background: #ffffff; + } + } +} + +.custom-data-carousel-box::after { + content: ' '; + display: block; + clear: both; +} diff --git a/src/tabviews/custom/components/carousel/prop-card/index.jsx b/src/tabviews/custom/components/carousel/prop-card/index.jsx new file mode 100644 index 0000000..4387d0c --- /dev/null +++ b/src/tabviews/custom/components/carousel/prop-card/index.jsx @@ -0,0 +1,363 @@ +import React, {Component} from 'react' +import PropTypes from 'prop-types' +import { is, fromJS } from 'immutable' +import { connect } from 'react-redux' +import { Spin, notification, Carousel } from 'antd' + +import asyncComponent from '@/utils/asyncComponent' +import Api from '@/api' +import UtilsDM from '@/utils/utils-datamanage.js' +import MKEmitter from '@/utils/events.js' +import { modifyTabview } from '@/store/action' +import './index.scss' + +const CardItem = asyncComponent(() => import('../cardItem')) + +class PropCard extends Component { + static propTpyes = { + BID: PropTypes.any, // 鐖剁骇Id + data: PropTypes.array, // 缁熶竴鏌ヨ鏁版嵁 + config: PropTypes.object, // 缁勪欢閰嶇疆淇℃伅 + mainSearch: PropTypes.any, // 澶栧眰鎼滅储鏉′欢 + menuType: PropTypes.any, // 鑿滃崟绫诲瀷 + } + + state = { + BID: '', // 涓婄骇ID + config: null, // 鍥捐〃閰嶇疆淇℃伅 + loading: false, // 鏁版嵁鍔犺浇鐘舵�� + sync: false, // 鏄惁缁熶竴璇锋眰鏁版嵁 + data: {} // 鏁版嵁 + } + + UNSAFE_componentWillMount () { + const { data, initdata, BID } = this.props + let _config = fromJS(this.props.config).toJS() + let _cols = new Map() + + let _data = {} + let _sync = false + + if (_config.setting && _config.wrap.datatype !== 'static') { + _sync = _config.setting.sync === 'true' + + if (_sync && data) { + _data = data[_config.dataName] || {} + if (_data && Array.isArray(_data)) { + _data = _data[0] || {} + } + _sync = false + } else if (_sync && initdata) { + _data = initdata || {} + if (_data && Array.isArray(_data)) { + _data = _data[0] || {} + } + _sync = false + } + } else { + _data = {} + } + + if (_data) { + _data.$$BID = BID || '' + } + + _config.columns.forEach(item => { + _cols.set(item.field, item) + }) + + _config.subcards.forEach(card => { + card.style.height = _config.style.height + if (card.setting.click) { + card.style.cursor = 'pointer' + } + card.elements = card.elements.map(item => { + if (item.field && _cols.has(item.field)) { + item.col = _cols.get(item.field) + } + return item + }) + }) + + _config.wrap.speed = (_config.wrap.speed || 3) * 1000 + + this.setState({ + sync: _sync, + data: _data, + BID: BID || '', + config: _config, + arr_field: _config.columns.map(col => col.field).join(','), + }, () => { + if (_config.wrap.datatype !== 'static' && _config.setting && _config.setting.sync !== 'true' && _config.setting.onload === 'true') { + this.loadData() + } + }) + } + + componentDidMount () { + MKEmitter.addListener('reloadData', this.reloadData) + MKEmitter.addListener('resetSelectLine', this.resetParentParam) + MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult) + } + + shouldComponentUpdate (nextProps, nextState) { + return !is(fromJS(this.state), fromJS(nextState)) + } + + componentWillUnmount () { + this.setState = () => { + return + } + MKEmitter.removeListener('reloadData', this.reloadData) + MKEmitter.removeListener('resetSelectLine', this.resetParentParam) + MKEmitter.removeListener('refreshByButtonResult', this.refreshByButtonResult) + } + + /** + * @description 鍥捐〃鏁版嵁鏇存柊锛屽埛鏂板唴瀹� + */ + UNSAFE_componentWillReceiveProps (nextProps) { + const { sync, config, BID } = this.state + + if (sync && !is(fromJS(this.props.data), fromJS(nextProps.data))) { + let _data = {} + if (nextProps.data && nextProps.data[config.dataName]) { + _data = nextProps.data[config.dataName] + if (_data && Array.isArray(_data)) { + _data = _data[0] + } + } + + if (_data) { + _data.$$BID = BID || '' + } + + this.setState({sync: false, data: _data}) + } else if (nextProps.mainSearch && !is(fromJS(this.props.mainSearch), fromJS(nextProps.mainSearch))) { + if (config.wrap.datatype !== 'static' && config.setting.syncRefresh === 'true') { + this.setState({}, () => { + this.loadData() + }) + } + } + } + + /** + * @description 鎸夐挳鎵ц瀹屾垚鍚庨〉闈㈠埛鏂� + * @param {*} menuId // 鑿滃崟Id + * @param {*} position // 鍒锋柊浣嶇疆 + * @param {*} btn // 鎵ц鐨勬寜閽� + */ + refreshByButtonResult = (menuId, position, btn) => { + const { config, BID } = this.state + + if (config.uuid !== menuId) return + + this.loadData() // 鏁版嵁鍒锋柊 + + if (btn.syncComponentId && btn.syncComponentId !== config.uuid && btn.syncComponentId !== config.setting.supModule) { + MKEmitter.emit('reloadData', btn.syncComponentId) // 鍚岀骇鏍囩鍒锋柊 + } + + if (position === 'mainline' && config.setting.supModule) { // 涓昏〃琛屽埛鏂� + MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) + } else if (position === 'popclose') { // 鏍囩鍏抽棴鍒锋柊 + config.setting.supModule && MKEmitter.emit('reloadData', config.setting.supModule, (BID || 'empty')) + btn.$tabId && MKEmitter.emit('refreshPopButton', btn.$tabId) + } + } + + resetParentParam = (MenuID, id) => { + const { config } = this.state + + if (config.wrap.datatype === 'static' || !config.setting.supModule || config.setting.supModule !== MenuID) return + if (id !== this.state.BID) { + this.setState({ BID: id }, () => { + this.loadData() + }) + } + } + + reloadData = (menuId) => { + const { config } = this.state + + if (menuId !== config.uuid) return + + this.loadData() + } + + async loadData () { + const { mainSearch, menuType } = this.props + const { config, arr_field, BID } = this.state + + if (config.wrap.datatype === 'static') { + this.setState({ + data: {$$BID: BID || ''}, + loading: false + }) + return + } else if (config.setting.supModule && !BID) { // BID 涓嶅瓨鍦ㄦ椂锛屼笉鍋氭煡璇� + this.setState({ + data: {$$BID: BID || ''}, + loading: false + }) + return + } + + let searches = [] + if (mainSearch && mainSearch.length > 0) { // 涓昏〃鎼滅储鏉′欢 + let keys = searches.map(item => item.key) + mainSearch.forEach(item => { + if (!keys.includes(item.key)) { + searches.push(item) + } + }) + } + + this.setState({ + loading: true + }) + + let _orderBy = config.setting.order || '' + let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, 1, BID, menuType) + + let result = await Api.genericInterface(param) + if (result.status) { + let _data = result.data && result.data[0] ? result.data[0] : {} + _data.$$BID = BID || '' + + this.setState({ + data: _data, + loading: false + }) + } else { + this.setState({ + loading: false + }) + notification.error({ + top: 92, + message: result.message, + duration: 10 + }) + } + } + + openView = (item) => { + if (item.setting.click === 'menu') { + let menu = null + + if (item.setting.menu && item.setting.menu.length > 0) { + let menu_id = item.setting.menu.slice(-1)[0] + menu = this.props.permMenus.filter(m => m.MenuID === menu_id)[0] || '' + } + + if (!menu) { + notification.warning({ + top: 92, + message: '鑿滃崟宸插垹闄ゆ垨娌℃湁璁块棶鏉冮檺锛�', + duration: 5 + }) + return + } + + let newtab = { + ...menu, + selected: true, + param: {} + } + + if (item.setting.joint === 'true') { + newtab.param.BID = item.setting.primaryId + } + + if (['linkage_navigation', 'linkage'].includes(window.GLOB.navBar)) { + this.props.modifyTabview([newtab]) + } else { + let tabs = this.props.tabviews.filter((tab, i) => { + tab.selected = false + return tab.MenuID !== newtab.MenuID + }) + + if (this.props.tabviews.length !== tabs.length) { + this.props.modifyTabview(fromJS(tabs).toJS()) + } + + this.setState({}, () => { + tabs.push(newtab) + this.props.modifyTabview(tabs) + }) + } + } else if (item.setting.click === 'link') { + let src = item.setting.linkurl + + if (src.indexOf('paramsmain/') > -1) { + try { + let _url = src.split('paramsmain/')[0] + 'paramsmain/' + let _param = JSON.parse(window.decodeURIComponent(window.atob(src.split('paramsmain/')[1]))) + + _param.UserID = sessionStorage.getItem('UserID') + _param.LoginUID = sessionStorage.getItem('LoginUID') + _param.User_Name = sessionStorage.getItem('User_Name') + _param.param = { BID: item.setting.primaryId } + src = _url + window.btoa(window.encodeURIComponent(JSON.stringify(_param))) + } catch { + console.warn('鑿滃崟鍙傛暟瑙f瀽閿欒锛�') + } + } else if (item.setting.joint === 'true') { + let con = '?' + + if (/\?/ig.test(src)) { + con = '&' + } + + src = src + `${con}id=${item.setting.primaryId}&appkey=${window.GLOB.appkey}&userid=${sessionStorage.getItem('UserID')}&LoginUID=${sessionStorage.getItem('LoginUID') || ''}` + } + + window.open(src) + } + } + + + render() { + const { config, loading, data } = this.state + + return ( + <div className="custom-prop-carousel-box" style={config.style}> + {loading ? + <div className="loading-mask"> + <div className="ant-spin-blur"></div> + <Spin /> + </div> : null + } + <Carousel + autoplay={config.wrap.autoplay !== 'false'} + dots={config.wrap.dots !== 'false'} + dotPosition={config.wrap.dotPosition || 'bottom'} + effect={config.wrap.effect || 'scrollx'} + autoplaySpeed={config.wrap.speed} + > + {config.subcards.map((item, index) => ( + <div key={index} onClick={() => {this.openView(item)}}> + <CardItem card={item} cards={config} data={data}/> + </div> + ))} + </Carousel> + </div> + ) + } +} + +const mapStateToProps = (state) => { + return { + permMenus: state.permMenus, + tabviews: state.tabviews, + } +} + +const mapDispatchToProps = (dispatch) => { + return { + modifyTabview: (tabviews) => dispatch(modifyTabview(tabviews)) + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(PropCard) \ No newline at end of file diff --git a/src/tabviews/custom/components/carousel/prop-card/index.scss b/src/tabviews/custom/components/carousel/prop-card/index.scss new file mode 100644 index 0000000..b5e46e6 --- /dev/null +++ b/src/tabviews/custom/components/carousel/prop-card/index.scss @@ -0,0 +1,42 @@ +.custom-prop-carousel-box { + background: #ffffff; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + min-height: 30px; + position: relative; + + .card-item-box { + position: relative; + background-position: center center; + background-repeat: no-repeat; + background-size: cover; + } + + .loading-mask { + position: absolute; + left: 40px; + top: 0; + right: 40px; + bottom: 0px; + display: flex; + align-items: center; + justify-content: center; + text-align: justify; + z-index: 1; + + .ant-spin-blur { + position: absolute; + width: 100%; + height: 100%; + opacity: 0.5; + background: #ffffff; + } + } +} + +.custom-prop-carousel-box::after { + content: ' '; + display: block; + clear: both; +} diff --git a/src/tabviews/custom/index.jsx b/src/tabviews/custom/index.jsx index 1cf5080..d3f6298 100644 --- a/src/tabviews/custom/index.jsx +++ b/src/tabviews/custom/index.jsx @@ -23,6 +23,8 @@ const AntvTabs = asyncComponent(() => import('./components/tabs/antv-tabs')) const DataCard = asyncComponent(() => import('./components/card/data-card')) const PropCard = asyncComponent(() => import('./components/card/prop-card')) +const CarouselDataCard = asyncComponent(() => import('./components/carousel/data-card')) +const CarouselPropCard = asyncComponent(() => import('./components/carousel/prop-card')) const TableCard = asyncComponent(() => import('./components/card/table-card')) const MainSearch = asyncComponent(() => import('@/tabviews/zshare/topSearch')) const NormalTable = asyncComponent(() => import('./components/table/normal-table')) @@ -547,7 +549,7 @@ return cell.eleType !== 'button' || isHS || permAction[cell.uuid] }) }) - } else if (item.type === 'table' && item.subtype === 'tablecard') { + } else if ((item.type === 'table' && item.subtype === 'tablecard') || item.type === 'carousel') { item.subcards.forEach(card => { let _hasheight = card.style.height && card.style.height !== 'auto' card.elements = card.elements.filter(cell => { @@ -995,6 +997,18 @@ <PropCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} /> </Col> ) + } else if (item.type === 'carousel' && item.subtype === 'datacard') { + return ( + <Col span={item.width} key={item.uuid}> + <CarouselDataCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} /> + </Col> + ) + } else if (item.type === 'carousel' && item.subtype === 'propcard') { + return ( + <Col span={item.width} key={item.uuid}> + <CarouselPropCard config={item} data={data} BID={_bid} mainSearch={mainSearch} menuType={menuType} /> + </Col> + ) } else if (item.type === 'table' && item.subtype === 'tablecard') { return ( <Col span={item.width} key={item.uuid}> diff --git a/src/views/menudesign/index.jsx b/src/views/menudesign/index.jsx index f227a6a..07d3ad2 100644 --- a/src/views/menudesign/index.jsx +++ b/src/views/menudesign/index.jsx @@ -384,6 +384,15 @@ _sort++ }) }) + } else if (item.type === 'carousel') { + item.subcards.forEach(card => { + card.elements && card.elements.forEach(cell => { + if (cell.eleType !== 'button') return + this.checkBtn(cell) + buttons.push(`select '${cell.uuid}' as menuid, '${item.name + '-' + cell.label}' as menuname, '${_sort * 10}' as Sort`) + _sort++ + }) + }) } else if (item.type === 'line' || item.type === 'bar') { item.action && item.action.forEach(btn => { this.checkBtn(btn) -- Gitblit v1.8.0