src/assets/mobimg/mobile.pngBinary files differ
src/assets/mobimg/navbar-mob.png
src/menu/menushell/index.jsx
@@ -1,6 +1,5 @@ import React, { useState } from 'react' import { useDrop } from 'react-dnd' import { is, fromJS } from 'immutable' import update from 'immutability-helper' import { Empty, notification, Modal } from 'antd' @@ -18,10 +17,7 @@ const { card, index } = findCard(id) const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) handleList({...menu, components: _cards}) } if (!is(fromJS(cards), fromJS(menu.components))) { setCards(menu.components) setCards(_cards) } const findCard = id => { @@ -33,7 +29,9 @@ } const updateConfig = (element) => { handleList({...menu, components: cards.map(item => item.uuid === element.uuid ? element : item)}) const _cards = cards.map(item => item.uuid === element.uuid ? element : item) handleList({...menu, components: _cards}) setCards(_cards) } const deleteCard = (id) => { @@ -54,8 +52,10 @@ title: `确定删除《${card.name}》吗?`, content: hasComponent ? '当前组件中含有子组件!' : '', onOk() { const _cards = cards.filter(item => item.uuid !== card.uuid) MKEmitter.emit('delButtons', uuids) handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)}) handleList({...menu, components: _cards}) setCards(_cards) }, onCancel() {} }) @@ -130,6 +130,7 @@ const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] }) handleList({...menu, components: _cards}) setCards(_cards) } }) src/mob/contdelete/index.jsx
File was deleted src/mob/contdelete/index.scss
File was deleted src/mob/controller/index.jsx
File was deleted src/mob/controller/index.scss
File was deleted src/mob/contupdate/index.jsx
File was deleted src/mob/contupdate/index.scss
File was deleted src/mob/datasource/index.jsx
File was deleted src/mob/datasource/index.scss
File was deleted src/mob/datasource/verifycard/columnform/index.jsx
File was deleted src/mob/datasource/verifycard/columnform/index.scss
src/mob/datasource/verifycard/customscript/index.jsx
File was deleted src/mob/datasource/verifycard/customscript/index.scss
File was deleted src/mob/datasource/verifycard/index.jsx
File was deleted src/mob/datasource/verifycard/index.scss
File was deleted src/mob/datasource/verifycard/settingform/index.jsx
File was deleted src/mob/datasource/verifycard/settingform/index.scss
File was deleted src/mob/datasource/verifycard/settingform/utils.jsx
File was deleted src/mob/datasource/verifycard/utils.jsx
File was deleted src/mob/mobcard/index.jsx
File was deleted src/mob/mobcard/index.scss
File was deleted src/mob/mobcard/mutilform/index.jsx
File was deleted src/mob/mobcard/mutilform/index.scss
File was deleted src/mob/mobshell/card.jsx
@@ -2,56 +2,86 @@ import { useDrag, useDrop } from 'react-dnd' import asyncComponent from '@/utils/asyncComponent' import './index.scss' // const Home = asyncComponent(() => import('@/mob/home')) const MobLogin1 = asyncComponent(() => import('@/mob/components/login/mob-login-1')) const MobLogin2 = asyncComponent(() => import('@/mob/components/login/mob-login-2')) const AntvBar = asyncComponent(() => import('@/menu/components/chart/antv-bar')) const MainSearch = asyncComponent(() => import('@/menu/components/search/main-search')) const AntvPie = asyncComponent(() => import('@/menu/components/chart/antv-pie')) 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 NormalForm = asyncComponent(() => import('@/menu/components/form/normal-form')) const NormalGroup = asyncComponent(() => import('@/menu/components/group/normal-group')) const CodeSandbox = asyncComponent(() => import('@/menu/components/code/sandbox')) const Card = ({ id, card, moveCard, findCard, editId, editCard, delCard, doubleClickCard, updateConfig }) => { const Card = ({ id, card, moveCard, findCard, delCard, updateConfig }) => { const originalIndex = findCard(id).index const [{ isDragging }, drag] = useDrag({ item: { type: 'mob', id, originalIndex }, item: { type: 'menu', id, originalIndex, floor: card.floor }, collect: monitor => ({ isDragging: monitor.isDragging(), }), }) const [, drop] = useDrop({ accept: 'mob', accept: 'menu', canDrop: () => true, drop: (item) => { const { id: draggedId, originalIndex } = item const { id: draggedId, originalIndex, floor } = item if (originalIndex === undefined) { item.dropTargetId = id } else if (draggedId && draggedId !== id) { } else if (draggedId && floor === card.floor) { if (draggedId === id) return const { index: originIndex } = findCard(draggedId) if (originIndex === -1) return const { index: overIndex } = findCard(id) moveCard(draggedId, overIndex) } } }) let style = { opacity: 1} if (isDragging && card.type !== 'login') { if (isDragging) { style = { opacity: 0.3} } if (card.type === 'login') { style.height = '100%' } const getCardComponent = () => { if (card.type === 'login') { if (card.subtype === 'mob-login-1') { return (<MobLogin1 card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />) } else if (card.subtype === 'mob-login-2') { return (<MobLogin2 card={card} triggerEdit={editCard} editId={editId} onDoubleClick={doubleClickCard} updateConfig={updateConfig} />) if (card.type === 'bar' || card.type === 'line') { return (<AntvBar card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'search') { return (<MainSearch card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'pie') { return (<AntvPie card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'form') { return (<NormalForm card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'tabs') { return (<AntvTabs tabs={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'card' && card.subtype === 'datacard') { 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') { return (<NormalTable card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'group' && card.subtype === 'normalgroup') { return (<NormalGroup group={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } else if (card.type === 'code') { return (<CodeSandbox card={card} updateConfig={updateConfig} deletecomponent={delCard}/>) } } } return ( <div className="mk-component-card" ref={node => drag(drop(node))} style={style}> <div className={'ant-col mk-component-card ant-col-' + (card.width || 24)} ref={node => drag(drop(node))} style={style}> {getCardComponent()} </div> ) src/mob/mobshell/index.jsx
@@ -1,23 +1,23 @@ import React, { useState } from 'react' import { useDrop } from 'react-dnd' import { is, fromJS } from 'immutable' import update from 'immutability-helper' import { message, Empty } from 'antd' import { Empty, notification, Modal } from 'antd' import Utils from '@/utils/utils.js' import MKEmitter from '@/utils/events.js' import MenuUtils from '@/utils/utils-custom.js' import Card from './card' import './index.scss' const Container = ({config, editId, handleList, editCard, deleteCard, doubleClickCard }) => { const [cards, setCards] = useState(config.components) const { confirm } = Modal const Container = ({menu, handleList }) => { const [cards, setCards] = useState(menu.components) const moveCard = (id, atIndex) => { const { card, index } = findCard(id) const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) handleList({...config, components: _cards}) } if (!is(fromJS(cards), fromJS(config.components))) { setCards(config.components) handleList({...menu, components: _cards}) setCards(_cards) } const findCard = id => { @@ -29,25 +29,92 @@ } const updateConfig = (element) => { handleList({...config, components: cards.map(item => item.uuid === element.uuid ? element : item)}) const _cards = cards.map(item => item.uuid === element.uuid ? element : item) handleList({...menu, components: _cards}) setCards(_cards) } const deleteCard = (id) => { const { card } = findCard(id) let hasComponent = false if (card.type === 'tabs') { card.subtabs.forEach(tab => { if (tab.components.length > 0) { hasComponent = true } }) } let uuids = MenuUtils.getDelButtonIds(card) confirm({ title: `确定删除《${card.name}》吗?`, content: hasComponent ? '当前组件中含有子组件!' : '', onOk() { MKEmitter.emit('delButtons', uuids) const _cards = cards.filter(item => item.uuid !== card.uuid) handleList({...menu, components: _cards}) setCards(_cards) }, onCancel() {} }) } const [, drop] = useDrop({ accept: 'mob', accept: 'menu', drop(item) { if (item.hasOwnProperty('originalIndex')) { if (item.hasOwnProperty('originalIndex') || item.added) { delete item.added // 删除组件添加标记 return } if (cards.length > 0 && cards[0].type === 'login') { message.warning('登录页不可添加其他元素!') if (item.component === 'search') { // 搜索组件不可重复添加 if (cards.filter(card => card.type === 'search').length > 0) { notification.warning({ top: 92, message: '搜索条件不可重复添加!', duration: 5 }) return } } let name = '' let names = { bar: '柱状图', line: '折线图', tabs: '标签组', pie: '饼图', search: '搜索', table: '表格', group: '分组', editor: '富文本', code: '自定义', carousel: '轮播', form: '表单', card: '卡片' } let i = 1 while (!name && names[item.component]) { let _name = names[item.component] + i if (menu.components.filter(com => com.name === _name).length === 0) { name = _name } i++ } let newcard = { uuid: Utils.getuuid(), type: item.componentType, type: item.component, subtype: item.subtype, config: item.config, width: item.width || 24, dataName: Utils.getdataName(), name: name, floor: 1, // 组件的层级 isNew: true // 新添加标志,用于初始化 } let targetId = '' @@ -59,29 +126,29 @@ targetId = cards.slice(-1)[0].uuid } const { index: overIndex } = findCard(`${targetId}`) // cards为空时 overIndex 为 -1 const { index: overIndex } = findCard(`${targetId}`) const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] }) handleList({...config, components: _cards}) handleList({...menu, components: _cards}) setCards(_cards) } }) return ( <div ref={drop} className="mob-shell-inner"> <div ref={drop} className="mob-shell-inner" id="menu-shell-inner" style={menu.style}> <div className="ant-row"> {cards.map(card => ( <Card id={card.uuid} key={card.uuid} card={card} editId={editId} moveCard={moveCard} editCard={editCard} delCard={deleteCard} findCard={findCard} updateConfig={updateConfig} doubleClickCard={doubleClickCard} /> ))} </div> {cards.length === 0 ? <Empty description="请添加组件" /> : null } @@ -89,3 +156,4 @@ ) } export default Container src/mob/modelsource/dragsource/index.jsx
File was deleted src/mob/modelsource/dragsource/index.scss
File was deleted src/mob/modelsource/index.jsx
File was deleted src/mob/modelsource/option.jsx
File was deleted src/mob/modulesource/dragsource/index.jsx
New file @@ -0,0 +1,15 @@ import React from 'react' import { useDrag } from 'react-dnd' import { Icon } from 'antd' import './index.scss' const MobSourceElement = ({item, triggerDel}) => { const [, drag] = useDrag({ item }) return ( <div className="menu-source-item"> <div className="property"><span>{item.title}</span>{item.config ? <Icon onClick={() => triggerDel(item)} type="close-circle" /> : null}</div> <img ref={drag} src={item.url} alt=""/> </div> ) } export default MobSourceElement src/mob/modulesource/dragsource/index.scss
New file @@ -0,0 +1,46 @@ .menu-source-item { display: inline-block; width: 100%; margin-bottom: 15px; height: auto; min-height: 70px; .property { font-size: 14px; color: rgba(0, 0, 0, 0.65); margin-bottom: 2px; .anticon-close-circle { opacity: 0; cursor: pointer; padding: 0 3px; color: #ff4d4f; transition: all 0.3s; } } img { width: 100%; cursor: move; box-shadow: 0px 0px 1px #1890ff; } .tooltip-block { width: 100%; height: 100%; background: transparent; } } .menu-source-item:hover .property { .anticon-close-circle { opacity: 1; } } .menu-source-tooltip-box { margin-left: 20px; .ant-tooltip-content { width: 250px; } } src/mob/modulesource/index.jsx
New file @@ -0,0 +1,93 @@ import React, {Component} from 'react' import { is, fromJS } from 'immutable' import { Modal, notification } from 'antd' import Api from '@/api' import { menuOptions } from './option' import SourceWrap from './dragsource' import MKEmitter from '@/utils/events.js' import './index.scss' const { confirm } = Modal class ModelSource extends Component { state = { menuOptions: null, } UNSAFE_componentWillMount () { const { components } = this.props let options = [] if (components) { options = fromJS(components).toJS() } else { options = fromJS(menuOptions).toJS() } this.setState({ menuOptions: options }) } UNSAFE_componentWillReceiveProps (nextProps) { if (nextProps.components && !is(fromJS(this.props.components), fromJS(nextProps.components))) { this.setState({ menuOptions: fromJS(nextProps.components).toJS() }) } } shouldComponentUpdate (nextProps, nextState) { return !is(fromJS(this.state), fromJS(nextState)) } triggerDel = (item) => { confirm({ title: `确定删除<${item.title}>吗?`, content: '', onOk() { return new Promise(resolve => { Api.getSystemConfig({ func: 's_custom_components_adduptdel', c_id: item.uuid, images: '', c_name: item.title, long_param: '', del_type: 'Y' }).then(result => { if (result.status) { notification.success({ top: 92, message: '删除成功!', duration: 5 }) MKEmitter.emit('updateCustomComponent') } else { notification.warning({ top: 92, message: result.message, duration: 5 }) } resolve() }) }) }, onCancel() {} }) } render() { const { menuOptions } = this.state return ( <div className="mob-card-source-box"> {menuOptions.map((item, index) => (<SourceWrap key={index} item={item} triggerDel={this.triggerDel} />))} </div> ) } } export default ModelSource src/mob/modulesource/index.scss
File was renamed from src/mob/modelsource/index.scss @@ -1,5 +1,5 @@ .mob-card-source-box { padding: 20px 0px 20px 15px; padding: 20px 0px; position: relative; p { src/mob/modulesource/option.jsx
New file @@ -0,0 +1,42 @@ import bar from '@/assets/mobimg/bar.png' import bar1 from '@/assets/mobimg/bar1.png' import line from '@/assets/mobimg/line.png' import line1 from '@/assets/mobimg/line1.png' import tabs from '@/assets/mobimg/tabs.png' import group from '@/assets/mobimg/group.png' import card1 from '@/assets/mobimg/card1.png' import card2 from '@/assets/mobimg/card2.png' import TableCard from '@/assets/mobimg/table-card.png' import NormalTable from '@/assets/mobimg/normal-table.png' import Pie from '@/assets/mobimg/pie.png' import SandBox from '@/assets/mobimg/sandbox.png' import Pie1 from '@/assets/mobimg/ring.png' import Pie2 from '@/assets/mobimg/nightingale.png' import Mainsearch from '@/assets/mobimg/mainsearch.png' import Navbar from '@/assets/mobimg/navbar-mob.png' import Carousel from '@/assets/mobimg/carousel.png' import Carousel1 from '@/assets/mobimg/carousel1.png' import form from '@/assets/mobimg/form.png' // 组件配置信息 export const menuOptions = [ { type: 'menu', url: Navbar, component: 'navbar', subtype: 'mobnavbar', title: '导航栏', width: 1200 }, { type: 'menu', url: tabs, component: 'tabs', subtype: 'tabs', title: '标签页', width: 24 }, { 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: form, component: 'form', subtype: 'stepform', title: '表单', width: 24 }, { type: 'menu', url: Carousel, component: 'carousel', subtype: 'datacard', title: '轮播-动态数据', width: 24 }, { type: 'menu', url: Carousel1, 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 }, { type: 'menu', url: line1, component: 'line', subtype: 'line1', title: '阶梯折线图', width: 24 }, { type: 'menu', url: bar, component: 'bar', subtype: 'bar', title: '柱状图', width: 24 }, { type: 'menu', url: bar1, component: 'bar', subtype: 'bar1', title: '条形图', width: 24 }, { type: 'menu', url: Pie, component: 'pie', subtype: 'pie', title: '饼图', width: 12 }, { type: 'menu', url: Pie1, component: 'pie', subtype: 'ring', title: '环图', width: 12 }, { type: 'menu', url: SandBox, component: 'code', subtype: 'sandbox', title: '自定义', width: 24 }, { type: 'menu', url: Pie2, component: 'pie', subtype: 'nightingale', title: '南丁格尔图', width: 12 }, { type: 'menu', url: group, component: 'group', subtype: 'normalgroup', title: '分组', width: 24 }, ] src/pc/menushell/index.jsx
@@ -1,6 +1,5 @@ import React, { useState } from 'react' import { useDrop } from 'react-dnd' import { is, fromJS } from 'immutable' import update from 'immutability-helper' import { Empty, notification, Modal } from 'antd' @@ -18,10 +17,7 @@ const { card, index } = findCard(id) const _cards = update(cards, { $splice: [[index, 1], [atIndex, 0, card]] }) handleList({...menu, components: _cards}) } if (!is(fromJS(cards), fromJS(menu.components))) { setCards(menu.components) setCards(_cards) } const findCard = id => { @@ -33,7 +29,9 @@ } const updateConfig = (element) => { handleList({...menu, components: cards.map(item => item.uuid === element.uuid ? element : item)}) const _cards = cards.map(item => item.uuid === element.uuid ? element : item) handleList({...menu, components: _cards}) setCards(_cards) } const deleteCard = (id) => { @@ -55,7 +53,9 @@ content: hasComponent ? '当前组件中含有子组件!' : '', onOk() { MKEmitter.emit('delButtons', uuids) handleList({...menu, components: cards.filter(item => item.uuid !== card.uuid)}) const _cards = cards.filter(item => item.uuid !== card.uuid) handleList({...menu, components: _cards}) setCards(_cards) }, onCancel() {} }) @@ -139,6 +139,7 @@ const _cards = update(cards, { $splice: [[overIndex + 1, 0, newcard]] }) handleList({...menu, components: _cards}) setCards(_cards) } }) src/tabviews/zshare/mutilform/index.jsx
@@ -76,6 +76,7 @@ formlist = formlist.map(item => { if (item.labelwidth) { item.labelCol = {style: {width: item.labelwidth + '%'}} item.wrapperCol = {style: {width: (100 - item.labelwidth) + '%'}} } if (item.type === 'split' || item.type === 'hint') return item @@ -716,7 +717,13 @@ } else if (item.type === 'hint') { fields.push( <Col span={item.span || 24} key={index}> <Form.Item colon={!!item.label} label={item.label || ' '} labelCol={item.labelCol} className="hint"> <Form.Item colon={!!item.label} label={item.label || ' '} labelCol={item.labelCol} wrapperCol={item.wrapperCol} className="hint" > <div className="message">{item.message}</div> </Form.Item> </Col> @@ -754,12 +761,17 @@ fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval + '', rules: [ @@ -782,12 +794,17 @@ fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -810,12 +827,17 @@ } else if (item.type === 'color') { // 颜色选择 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval || 'transparent', rules: [ @@ -833,12 +855,18 @@ } else if (item.type === 'checkcard') { // 多选框 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item className="checkcard" extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label } className="checkcard"> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -854,12 +882,17 @@ } else if (item.type === 'switch') { // 多选框 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -877,12 +910,17 @@ fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: _initval, rules: [ @@ -902,12 +940,17 @@ } else if (item.type === 'radio') { // 单选框 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -927,12 +970,17 @@ } else if (item.type === 'select' || item.type === 'link') { // 下拉搜索 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -961,12 +1009,17 @@ let _initval = item.initval ? item.initval.split(',').filter(Boolean) : [] fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: _initval, rules: [ @@ -993,12 +1046,17 @@ } else if (item.type === 'date') { // 时间搜索 fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -1016,12 +1074,17 @@ } else if (item.type === 'datemonth') { fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -1039,12 +1102,17 @@ } else if (item.type === 'datetime') { fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -1081,12 +1149,17 @@ fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: filelist, rules: [ @@ -1104,12 +1177,17 @@ } else if (item.type === 'linkMain') { fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -1135,12 +1213,17 @@ } fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : item.label }> } > {getFieldDecorator(item.field, { initialValue: item.initval, rules: [ @@ -1163,12 +1246,17 @@ fields.push( <Col span={item.span || 24} key={index}> <Form.Item extra={item.extra || null} labelCol={item.labelCol} label={item.hidelabel !== 'true' && item.tooltip ? <Form.Item extra={item.extra || null} labelCol={item.labelCol} wrapperCol={item.wrapperCol} label={item.hidelabel !== 'true' && item.tooltip ? <Tooltip placement="topLeft" title={item.tooltip}> <Icon type="question-circle" /> {item.label} </Tooltip> : (item.hidelabel !== 'true' ? item.label : '') }> } > {getFieldDecorator(item.field, { initialValue: item.initval || '', rules: [ src/templates/sharecomponent/columncomponent/index.jsx
@@ -186,7 +186,7 @@ _columnlist = _columnlist.filter(item => !item.origin || item.uuid === res.uuid) // 去除初始列 _columnlist = _columnlist.map(item => { if (item.uuid !== res.uuid && res.field && item.field) { if (item.field === res.field) { if (item.field.toLowerCase() === res.field.toLowerCase()) { fieldrepet = true } } src/views/mobdesign/index.jsx
@@ -1,46 +1,130 @@ import React, { Component } from 'react' import { connect } from 'react-redux' import { DndProvider } from 'react-dnd' import { fromJS } from 'immutable' import { withRouter } from 'react-router' import { is, fromJS } from 'immutable' import moment from 'moment' import HTML5Backend from 'react-dnd-html5-backend' import { Icon, Tabs, notification, Modal } from 'antd' // import html2canvas from 'html2canvas' import { ConfigProvider, notification, Modal, Collapse, Switch, Button, message, Spin } from 'antd' import Api from '@/api' import Utils from '@/utils/utils.js' import zhCN from '@/locales/zh-CN/mob.js' import enUS from '@/locales/en-US/mob.js' import antdEnUS from 'antd/es/locale/en_US' import antdZhCN from 'antd/es/locale/zh_CN' import MKEmitter from '@/utils/events.js' import MenuUtils from '@/utils/utils-custom.js' import asyncComponent from '@/utils/asyncComponent' import { modifyCustomMenu } from '@/store/action' import './index.scss' const { TabPane } = Tabs const { Panel } = Collapse const { confirm } = Modal const Header = asyncComponent(() => import('@/mob/header')) const Controller = asyncComponent(() => import('@/mob/controller')) const MenuForm = asyncComponent(() => import('./menuform')) const MobShell = asyncComponent(() => import('@/mob/mobshell')) const SourceWrap = asyncComponent(() => import('@/mob/modelsource')) const DataSource = asyncComponent(() => import('@/mob/datasource')) const SourceWrap = asyncComponent(() => import('@/mob/modulesource')) const BgController = asyncComponent(() => import('@/pc/bgcontroller')) const SysInterface = asyncComponent(() => import('@/menu/sysinterface')) const Quotecomponent = asyncComponent(() => import('@/pc/quotecomponent')) const PasteController = asyncComponent(() => import('@/menu/pastecontroller')) const StyleController = asyncComponent(() => import('@/menu/stylecontroller')) const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent')) const PictureController = asyncComponent(() => import('@/menu/picturecontroller')) const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller')) const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller')) const StyleCombControlButton = asyncComponent(() => import('@/menu/stylecombcontrolbutton')) const TableComponent = asyncComponent(() => import('@/templates/sharecomponent/tablecomponent')) class Mobile extends Component { sessionStorage.setItem('isEditState', 'true') sessionStorage.setItem('editMenuType', 'menu') // 编辑菜单类型 sessionStorage.setItem('appType', 'mob') // 应用类型 document.body.className = '' window.GLOB.UserComponentMap = new Map() // 缓存用户自定义组件 window.GLOB.CacheIndependent = new Map() window.GLOB.urlFields = [] // url变量 class MobDesign extends Component { state = { localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS, dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, appId: this.props.match.params.appId, appType: this.props.match.params.appType, appCode: this.props.match.params.appCode, appName: this.props.match.params.appName, loading: true, MenuId: '', MenuName: '', MenuNo: '', delButtons: [], copyButtons: [], thawButtons: [], activeKey: 'basedata', menuloading: false, oriConfig: null, parentId: '', openEdition: '', config: null, pageIndex: 0, editElem: null visible: false, customComponents: [], } UNSAFE_componentWillMount() { this.getAppParam(this.props.match.params.appId) if (this.props.memberLevel < 30) return try { let param = JSON.parse(window.decodeURIComponent(window.atob(this.props.match.params.param))) if (param.type === 'app') { sessionStorage.setItem('appId', param.ID || '') sessionStorage.setItem('lang', param.lang || 'zh-CN') sessionStorage.setItem('kei_no', param.kei_no || '') sessionStorage.setItem('link_type', param.link_type || 'true') sessionStorage.setItem('role_type', param.role_type || 'true') sessionStorage.setItem('login_types', param.login_types || 'true') this.setState({ localedict: sessionStorage.getItem('lang') !== 'en-US' ? antdZhCN : antdEnUS, dict: sessionStorage.getItem('lang') !== 'en-US' ? zhCN : enUS }) this.getAppMessage() } else if (param.type === 'view') { this.setState({ MenuId: param.MenuID }, () => { this.getMenuParam(param) }) } } catch { notification.warning({ top: 92, message: '菜单信息解析错误!', duration: 5 }) } } UNSAFE_componentWillReceiveProps(nextProps) { if (this.props.match.params.param !== nextProps.match.params.param) { window.location.reload() } } shouldComponentUpdate (nextProps, nextState) { return !is(fromJS(this.state), fromJS(nextState)) } componentDidMount () { if (this.props.memberLevel < 30) { document.getElementById('mk-mob-design-view').innerHTML = '<div style="text-align: center; font-size: 30px; margin-top: 40vh; height: 100vh; background: #fff;">本应用没有PC端页面的编辑权限,请联系管理员!</div>' return } MKEmitter.addListener('delButtons', this.delButtons) MKEmitter.addListener('thawButtons', this.thawButtons) MKEmitter.addListener('copyButtons', this.copyButtons) MKEmitter.addListener('changeEditMenu', this.changeEditMenu) MKEmitter.addListener('submitComponentStyle', this.updateComponentStyle) MKEmitter.addListener('updateCustomComponent', this.updateCustomComponent) setTimeout(() => { this.updateCustomComponent() this.getAppPictures() }, 1000) } /** @@ -50,214 +134,1324 @@ this.setState = () => { return } MKEmitter.removeListener('delButtons', this.delButtons) MKEmitter.removeListener('thawButtons', this.thawButtons) MKEmitter.removeListener('copyButtons', this.copyButtons) MKEmitter.removeListener('changeEditMenu', this.changeEditMenu) MKEmitter.removeListener('submitComponentStyle', this.updateComponentStyle) MKEmitter.removeListener('updateCustomComponent', this.updateCustomComponent) } triggerSave = () => { const { config, openEdition, parentId } = this.state changeEditMenu = (menu) => { const { oriConfig, config } = this.state let param = { func: 'sPC_TrdMenu_AddUpt', ParentID: config.entrance ? '' : parentId, MenuID: config.uuid, MenuNo: config.MenuNo, EasyCode: '', Template: '', MenuName: '', PageParam: '', LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(config))), // LText: _vals.func.map(item => `select '${menu.MenuID}' as MenuID,'${item.func}' as ProcName,'${item.label}' as MenuName`), // LTexttb: _tables.map(item => `select '${menu.MenuID}' as MenuID,'${item}' as tbName`), TypeCharOne: 'mob' } let _LText = '' // _LText = _LText.join(' union all ') let _LTexttb = '' // _LTexttb = _LTexttb.join(' union all ') param.LText = Utils.formatOptions(_LText) param.LTexttb = Utils.formatOptions(_LTexttb) param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') param.secretkey = Utils.encrypt(param.LText, param.timestamp) if (openEdition) { // 版本管理 param.open_edition = openEdition } Api.getSystemConfig(param).then(response => { if (response.status) { this.setState({ oriConfig: fromJS(config).toJS(), openEdition: response.open_edition || '', }) } else { if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) { notification.warning({ top: 92, message: response.message, message: '配置信息未保存!', duration: 5 }) } }) return } getAppParam = (id) => { let param = { MenuID: menu.MenuID, copyMenuId: menu.copyMenuId || '', type: 'view' } if (menu.fixed && menu.MenuNo && menu.MenuName) { param.fixed = true param.MenuNo = menu.MenuNo param.MenuName = menu.MenuName } param = window.btoa(window.encodeURIComponent(JSON.stringify(param))) if (param === this.props.match.params.param) return this.props.history.push('/mobdesign/' + param) } getAppMessage = () => { Api.getSystemConfig({ func: 'sPC_Get_LongParam', MenuID: id, TypeCharOne: 'mob' }).then(result => { if (result.status) { let config = null if (result.LongParam) { try { config = JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) } catch (e) { console.warn('Parse Failure') config = null } } if (!config) { config = { version: 1.0, entrance: true, label: '', uuid: this.props.match.params.appId, pageIndex: 0, MenuNo: this.props.match.params.appCode, sourcelist: [], components: [] } } this.setState({ oriConfig: config, config: fromJS(config).toJS(), openEdition: result.open_edition || '', func: 's_get_keyids', bid: sessionStorage.getItem('appId') }).then(res => { if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) } else { return } let homeId = '' let appViewList = [] if (res.data && res.data.length > 0) { appViewList = res.data appViewList.forEach(item => { if (item.keys_type === 'index') { homeId = item.keys_id } }) } if (!homeId) { homeId = Utils.getuuid() let param = { func: 's_kei_link_keyids_addupt', BID: sessionStorage.getItem('appId'), exec_type: 'y', LText: '' } appViewList.unshift({ appkey: window.GLOB.appkey || '', bid: sessionStorage.getItem('appId') || '', kei_no: sessionStorage.getItem('kei_no') || '', keys_id: homeId, keys_type: 'index', remark: '首页' }) param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`) param.LText = param.LText.join(' union all ') param.LText = Utils.formatOptions(param.LText) param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') param.secretkey = Utils.encrypt('', param.timestamp) Api.getSystemConfig(param).then(result => { if (!result.status) { notification.warning({ top: 92, message: result.message, duration: 5 }) } else { sessionStorage.setItem('appViewList', JSON.stringify(appViewList)) sessionStorage.setItem('appHomeId', homeId) this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'})))) } }) } else { sessionStorage.setItem('appViewList', JSON.stringify(appViewList)) sessionStorage.setItem('appHomeId', homeId) this.props.history.replace('/mobdesign/' + window.btoa(window.encodeURIComponent(JSON.stringify({MenuID: homeId, type: 'view'})))) } }) } deleteCard = (id) => { let _this = this getAppPictures = () => { if (sessionStorage.getItem('app_videos') || sessionStorage.getItem('app_pictures')) return Api.getSystemConfig({ func: 's_url_db_adduptdel', PageIndex: 0, // 0 代表全部 PageSize: 0, // 0 代表全部 typecharone: 'image', type: 'search' }).then(res => { if (res.status) { sessionStorage.setItem('app_pictures', JSON.stringify(res.data || [])) } Api.getSystemConfig({ func: 's_url_db_adduptdel', PageIndex: 0, // 0 代表全部 PageSize: 0, // 0 代表全部 typecharone: 'video', type: 'search' }).then(res => { if (res.status) { sessionStorage.setItem('app_videos', JSON.stringify(res.data || [])) } }) }) } updateCustomComponent = () => { Api.getSystemConfig({ func: 's_get_custom_components', typecharone: '' }).then(res => { let coms = [] if (res.cus_list && res.cus_list.length > 0) { res.cus_list.forEach(item => { let config = '' try { config = JSON.parse(window.decodeURIComponent(window.atob(item.long_param))) } catch (e) { console.warn('Parse Failure') config = '' } if (!config || !item.c_name) return window.GLOB.UserComponentMap.set(item.c_id, item.c_name) coms.push({ uuid: item.c_id, type: 'menu', title: item.c_name, url: item.images, component: config.type, subtype: config.subtype, width: config.width || 24, config }) }) } this.setState({customComponents: coms}) this.getRoleFields() }) } updateComponentStyle = (parentId, keys, style) => { const { config } = this.state if (config.uuid !== parentId) return let components = config.components.map(item => { if (keys.includes(item.uuid)) { item.style = {...item.style, ...style} } return item }) this.setState({ config: {...config, components: []} }, () => { this.setState({ config: {...config, components: components} }) }) } delButtons = (items) => { const { copyButtons, delButtons } = this.state this.setState({ delButtons: [...delButtons, ...items], copyButtons: copyButtons.filter(item => !items.includes(item.uuid)) }) } copyButtons = (items) => { this.setState({copyButtons: [...this.state.copyButtons, ...items]}) } thawButtons = (item) => { this.setState({thawButtons: [...this.state.thawButtons, item]}) } closeView = () => { const { oriConfig, config } = this.state if (!config) { window.close() return } if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) { confirm({ title: '配置信息未保存,确定关闭吗?', content: '', onOk() { window.close() }, onCancel() {} }) } else { window.close() } } getMenuParam = (urlParam) => { const { MenuId } = this.state let param = { func: 'sPC_Get_LongParam', TypeCharOne: sessionStorage.getItem('kei_no'), typename: 'mob', MenuID: MenuId } Api.getSystemConfig(param).then(result => { if (!result.status) { notification.warning({ top: 92, message: result.message, duration: 5 }) this.setState({loading: false}) return } else if (!result.LongParam && urlParam.copyMenuId) { this.getCopyParam(urlParam) } else { let config = null let isCreate = false try { config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null } catch (e) { console.warn('Parse Failure') config = null } if (!config) { isCreate = true config = { version: 1.0, uuid: MenuId, MenuID: MenuId, Template: 'webPage', enabled: false, MenuName: '', MenuNo: '', tables: [], components: [], viewType: 'menu', style: { backgroundColor: '#ffffff', backgroundImage: '', paddingLeft: '20px', paddingRight: '20px' } } } config.uuid = MenuId config.MenuID = MenuId config.open_edition = result.open_edition || '' window.GLOB.urlFields = config.urlFields || [] if (urlParam.fixed) { config.fixed = true config.MenuName = urlParam.MenuName config.MenuNo = urlParam.MenuNo } let indeComs = [] config.components.forEach(item => { if (item.type === 'navbar') { indeComs.push(fromJS(item).toJS()) } }) if (indeComs.length === 0) { this.setState({ oriConfig: isCreate ? null : config, config: fromJS(config).toJS(), loading: false }) this.props.modifyCustomMenu(config) } else { this.jointComponents(config, indeComs, isCreate) } } }) this.getAppMenus() } getAppMenus = () => { let _param = { func: 's_get_app_menus', TypeCharOne: sessionStorage.getItem('kei_no'), typename: 'mob', LText: `select '${window.GLOB.appkey}'`, timestamp: moment().format('YYYY-MM-DD HH:mm:ss') } _param.secretkey = Utils.encrypt(_param.LText, _param.timestamp) Api.getSystemConfig(_param).then(res => { if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) return } let appIndeList = sessionStorage.getItem('appViewList') appIndeList = JSON.parse(appIndeList) appIndeList = appIndeList.map(item => (item.keys_type !== 'index' ? item.keys_id : '')).join(',') let menus = res.menus.filter(item => appIndeList.indexOf(item.MenuID) === -1) sessionStorage.setItem('appMenus', JSON.stringify(menus)) }) } getCopyParam = (urlParam) => { const { MenuId } = this.state let param = { func: 'sPC_Get_LongParam', TypeCharOne: sessionStorage.getItem('kei_no'), typename: 'mob', MenuID: urlParam.copyMenuId } Api.getSystemConfig(param).then(result => { if (!result.status) { notification.warning({ top: 92, message: result.message, duration: 5 }) this.setState({loading: false}) return } else if (!result.LongParam) { notification.warning({ top: 92, message: '未查询到复制菜单配置信息!', duration: 5 }) } let config = null try { config = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : null } catch (e) { console.warn('Parse Failure') config = null } if (!config) { config = { version: 1.0, uuid: MenuId, MenuID: MenuId, Template: 'webPage', enabled: false, MenuName: '', MenuNo: '', tables: [], components: [], viewType: 'menu', style: { backgroundColor: '#ffffff', backgroundImage: '', paddingLeft: '20px', paddingRight: '20px' } } } else { config.components = MenuUtils.resetConfig(config.components) message.success('复制成功,保存后生效。') } config.uuid = MenuId config.MenuID = MenuId config.open_edition = '' let indeComs = [] config.components.forEach(item => { if (item.type === 'navbar') { indeComs.push(fromJS(item).toJS()) } }) if (indeComs.length === 0) { this.setState({ oriConfig: null, config: fromJS(config).toJS(), loading: false }) this.props.modifyCustomMenu(config) } else { this.jointComponents(config, indeComs, true) } }) } jointComponents = (config, indeComs, isCreate) => { let deffers = indeComs.map(item => { return new Promise(resolve => { Api.getSystemConfig({ func: 'sPC_Get_LongParam', TypeCharOne: sessionStorage.getItem('kei_no'), typename: 'mob', MenuID: item.uuid }).then(res => { res.uuid = item.uuid if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) } resolve(res) }) }) }) Promise.all(deffers).then(result => { let _conf = {} result.forEach(res => { let _config = null try { _config = res.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(res.LongParam))) : null } catch (e) { console.warn('Parse Failure') _config = null } if (_config) { _config.open_edition = res.open_edition || '' _conf[res.uuid] = _config window.GLOB.CacheIndependent.set(res.uuid, fromJS(_config).toJS()) } }) let _length = config.components.length config.components = config.components.map(item => { if (item.type === 'navbar') { if (_conf[item.uuid]) { item = _conf[item.uuid] } else { item = null } } return item }) config.components = config.components.filter(Boolean) if (_length > config.components.length) { notification.warning({ top: 92, message: '部分组件已删除!', duration: 5 }) } this.setState({ oriConfig: isCreate ? null : fromJS(config).toJS(), config: config, loading: false }) this.props.modifyCustomMenu(config) }) } getMenuMessage = () => { const { config } = this.state let buttons = [] let _sort = 1 let traversal = (components) => { components.forEach(item => { if (item.type === 'tabs') { item.subtabs.forEach(tab => { traversal(tab.components) }) } else if (item.type === 'group') { traversal(item.components) } else if (item.type === 'card' || (item.type === 'table' && item.subtype === 'tablecard')) { item.action && item.action.forEach(btn => { this.checkBtn(btn) buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`) _sort++ }) 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++ }) card.backElements && card.backElements.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) buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`) _sort++ }) } else if (item.type === 'table' && item.subtype === 'normaltable') { item.action && item.action.forEach(btn => { this.checkBtn(btn) buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`) _sort++ }) item.cols && item.cols.forEach(col => { if (col.type !== 'action') return col.elements.forEach(btn => { this.checkBtn(btn) buttons.push(`select '${btn.uuid}' as menuid, '${item.name + '-' + btn.label}' as menuname, '${_sort * 10}' as Sort`) _sort++ }) }) } }) } traversal(config.components) return buttons } checkBtn = (btn) => { if (['prompt', 'exec', 'pop'].includes(btn.OpenType) && btn.Ot === 'required' && btn.verify && btn.verify.scripts && btn.verify.scripts.length > 0) { let hascheck = false btn.verify.scripts.forEach(item => { if (item.status === 'false') return if (/\$check@|@check\$/ig.test(item.sql)) { hascheck = true } }) if (hascheck) { notification.warning({ top: 92, message: `可选择多行的按钮《${btn.label}》中 $check@ 或 @check$ 将不会生效!`, duration: 5 }) } } } filterConfig = (components) => { return components.map(item => { if (item.type === 'tabs') { item.subtabs.forEach(tab => { tab.components = this.filterConfig(tab.components) }) } else if (item.type === 'group') { item.components = this.filterConfig(item.components) } else if (item.type === 'table' && item.subtype === 'normaltable') { item.search = item.search.filter(a => !a.origin) item.action = item.action.filter(a => !a.origin) item.cols = item.cols.filter(a => !a.origin) } return item }) } submitConfig = () => { const { delButtons, copyButtons, thawButtons } = this.state let config = fromJS(this.state.config).toJS() confirm({ title: '确定删除元素吗?', content: '', okText: this.state.dict['mob.confirm'], cancelText: this.state.dict['mob.cancel'], onOk() { config.components = config.components.filter(item => item.uuid !== id) if (!config.MenuName || !config.MenuNo || (config.cacheUseful === 'true' && !config.cacheTime)) { notification.warning({ top: 92, message: '请完善菜单基本信息!', duration: 5 }) this.setState({ activeKey: 'basedata' }) return } _this.setState({ this.setState({ menuloading: true }) setTimeout(() => { config.components = this.filterConfig(config.components) if (config.enabled && this.verifyConfig()) { config.enabled = false } let parMenuId = sessionStorage.getItem('kei_no') + 'pc' + sessionStorage.getItem('lang') let param = { func: 'sPC_TrdMenu_AddUpt', FstID: parMenuId, SndID: parMenuId, ParentID: parMenuId, MenuID: config.uuid, MenuNo: config.MenuNo || '', EasyCode: '', Template: 'webPage', TypeCharOne: sessionStorage.getItem('kei_no'), Typename: 'pc', MenuName: config.MenuName || '', PageParam: JSON.stringify({Template: 'webPage'}), open_edition: config.open_edition, LText: '', LTexttb: '' } param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') param.secretkey = Utils.encrypt('', param.timestamp) let btnParam = { // 添加菜单按钮 func: 'sPC_Button_AddUpt', Type: 40, // 添加菜单下的按钮type为40,按钮下的按钮type为60 ParentID: config.uuid, MenuNo: config.MenuNo, Template: 'webPage', PageParam: '', LongParam: '', LText: [] } btnParam.LText = this.getMenuMessage() btnParam.LText = btnParam.LText.join(' union all ') let btnIds = btnParam.LText // 用于复制按钮的过滤 btnParam.LText = Utils.formatOptions(btnParam.LText) btnParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') btnParam.secretkey = Utils.encrypt(btnParam.LText, btnParam.timestamp) new Promise(resolve => { let _config = fromJS(config).toJS() let indeComs = [] _config.components = _config.components.map(item => { if (item.type === 'navbar') { indeComs.push(item) return { type: 'navbar', uuid: item.uuid } } return item }) param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(_config))) if (indeComs.length === 0) { resolve(true) } else { let new_open_edition = {} let deffers = indeComs.map(item => { return new Promise(resolve => { let _item = window.GLOB.CacheIndependent.get(item.uuid) if (_item && is(fromJS(_item), fromJS(item))) { new_open_edition[item.uuid] = item.open_edition || '' resolve() return } let _param = { func: 'sPC_TrdMenu_AddUpt', FstID: parMenuId, SndID: parMenuId, ParentID: parMenuId, MenuID: item.uuid, MenuNo: item.wrap.MenuNo || '', EasyCode: '', Template: item.type, TypeCharOne: sessionStorage.getItem('kei_no'), Typename: 'pc', MenuName: item.name || '', PageParam: JSON.stringify({Template: item.type}), open_edition: item.open_edition || '', LText: '', LTexttb: '' } _param.LongParam = window.btoa(window.encodeURIComponent(JSON.stringify(item))) _param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') _param.secretkey = Utils.encrypt('', _param.timestamp) let appMenuParam = null if (item.type === 'navbar') { appMenuParam = { func: 's_appmenus_addupt', exec_type: 'y' } appMenuParam.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') appMenuParam.secretkey = Utils.encrypt('', _param.timestamp) let LText = [] let app_param = [] let kei_no = sessionStorage.getItem('kei_no') let userid = sessionStorage.getItem('CloudUserID') || '' item.menus.forEach((fst, findex) => { // LText.push(`select '${fst.MenuID}','${fst.name}','','0','${sessionStorage.getItem('appId')}','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`) LText.push(`select '${fst.MenuID}','${fst.name}','','0','0','0','${(findex + 1) * 10}','10','','${userid}','${window.GLOB.appkey}','${fst.MenuNo || ''}','${kei_no}','pc'`) app_param.push(`select '${window.GLOB.appkey}','${fst.MenuID}','${userid}','${(findex + 1) * 10}','','${fst.name}','${fst.MenuNo || ''}','0','10','${kei_no}','pc'`) if (fst.property === 'classify' && fst.sublist.length > 0) { fst.sublist.forEach(scd => { LText.push(`select '${scd.MenuID}','${scd.name}','','0','${fst.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${scd.MenuNo || ''}','${kei_no}','pc'`) app_param.push(`select '${window.GLOB.appkey}','${scd.MenuID}','${userid}','${(findex + 1) * 10}','','${scd.name}','${scd.MenuNo || ''}','${fst.MenuID}','20','${kei_no}','pc'`) if (scd.property === 'classify' && scd.sublist.length > 0) { scd.sublist.forEach(thd => { LText.push(`select '${thd.MenuID}','${thd.name}','','0','${scd.MenuID}','0','${(findex + 1) * 10}','20','','${userid}','${window.GLOB.appkey}','${thd.MenuNo || ''}','${kei_no}','pc'`) app_param.push(`select '${window.GLOB.appkey}','${thd.MenuID}','${userid}','${(findex + 1) * 10}','','${thd.name}','${thd.MenuNo || ''}','${scd.MenuID}','20','${kei_no}','pc'`) }) } }) } }) appMenuParam.LText = Utils.formatOptions(LText.join(' union ')) appMenuParam.LText1 = Utils.formatOptions(app_param.join(' union ')) } if (appMenuParam) { Api.getSystemConfig(appMenuParam).then(_res => { if (!_res.status) { notification.warning({ top: 92, message: _res.message, duration: 5 }) this.setState({ menuloading: false }) return } Api.getSystemConfig(_param).then(res => { if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) this.setState({ menuloading: false }) return } new_open_edition[item.uuid] = res.open_edition || '' resolve() }) }) } else { Api.getSystemConfig(_param).then(res => { if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) this.setState({ menuloading: false }) return } new_open_edition[item.uuid] = res.open_edition || '' resolve() }) } }) }) Promise.all(deffers).then(() => { let appViewList = sessionStorage.getItem('appViewList') appViewList = JSON.parse(appViewList) let _length = appViewList.length let appIndeList = appViewList.map(item => item.keys_id).join(',') config.components = config.components.map(item => { if (item.type === 'navbar') { item.open_edition = new_open_edition[item.uuid] || '' window.GLOB.CacheIndependent.set(item.uuid, fromJS(item).toJS()) if (appIndeList.indexOf(item.uuid) === -1) { appViewList.unshift({ appkey: window.GLOB.appkey || '', bid: sessionStorage.getItem('appId') || '', kei_no: sessionStorage.getItem('kei_no') || '', keys_id: item.uuid, keys_type: 'navbar', remark: item.name }) } } return item }) if (appViewList.length > _length) { let param = { func: 's_kei_link_keyids_addupt', BID: sessionStorage.getItem('appId'), exec_type: 'y', LText: '' } param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`) param.LText = param.LText.join(' union all ') param.LText = Utils.formatOptions(param.LText) param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') param.secretkey = Utils.encrypt('', param.timestamp) Api.getSystemConfig(param).then(result => { if (!result.status) { notification.warning({ top: 92, message: result.message, duration: 5 }) this.setState({ menuloading: false }) } else { sessionStorage.setItem('appViewList', JSON.stringify(appViewList)) resolve(true) } }) } else { resolve(true) } }) } }).then(res => { // 按钮或菜单删除 if (!res) return if (delButtons.length === 0) { return { status: true, nonexec: true } } else { let appHomeId = sessionStorage.getItem('appHomeId') let _param = { func: 'sPC_MainMenu_Del', MenuID: delButtons.filter(id => id !== appHomeId).join(',') } return Api.getSystemConfig(_param) } }).then(res => { // 按钮解除冻结 if (!res) return if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) return false } else if (!res.nonexec) { // 执行删除后刷新菜单列表 this.getAppMenus() } let ids = thawButtons.filter(item => btnIds.indexOf(item) !== -1) if (ids.length === 0) { return { status: true } } else { return Api.getSystemConfig({ func: 'sPC_MainMenu_ReDel', MenuID: ids.join(',') }) } }).then(res => { // 页面保存 if (!res) return if (res.status) { return Api.getSystemConfig(param) } else { notification.warning({ top: 92, message: res.message, duration: 5 }) return false } }).then(res => { // 页面按钮关系保存 if (!res) return if (res.status) { config.open_edition = res.open_edition || '' this.setState({ oriConfig: fromJS(config).toJS(), }) if (btnParam.LText) { return Api.getSystemConfig(btnParam) } else { return { status: true } } } else { notification.warning({ top: 92, message: res.message, duration: 5 }) return false } }).then(res => { // 按钮复制 if (!res) return if (!res.status) { notification.warning({ top: 92, message: res.message, duration: 5 }) return false } if (copyButtons.length === 0) { return { status: true } } else { return new Promise(resolve => { let deffers = copyButtons.map(item => { return new Promise(resolve => { if (btnIds.indexOf(item.uuid) === -1) { // 复制的按钮已删除 resolve({ status: true }) return } Api.getSystemConfig({ func: 'sPC_Get_LongParam', MenuID: item.$originUuid }).then(result => { if (result.status) { let _conf = '' try { _conf = result.LongParam ? JSON.parse(window.decodeURIComponent(window.atob(result.LongParam))) : '' } catch (e) { console.warn('Parse Failure') _conf = '' } if (_conf) { _conf.components = MenuUtils.resetConfig(_conf.components) _conf.uuid = item.uuid _conf.MenuID = item.uuid _conf.Template = 'webPage' } else { resolve({ status: true }) return } let _param = { func: 'sPC_ButtonParam_AddUpt', ParentID: config.uuid, MenuID: item.uuid, MenuNo: '', Template: 'webPage', MenuName: item.label, PageParam: JSON.stringify({Template: 'webPage'}), LongParam: window.btoa(window.encodeURIComponent(JSON.stringify(_conf))) } Api.getSystemConfig(_param).then(response => { resolve(response) }) } }) }) }) Promise.all(deffers).then(result => { let error = null result.forEach(response => { if (!response.status) { error = response } }) if (error) { notification.warning({ top: 92, message: error.message, duration: 5 }) resolve(false) } else { resolve({ status: true }) } }) }) } }).then(res => { if (res && res.status) { this.setState({ delButtons: [], copyButtons: [], thawButtons: [], menuloading: false, config: {...config, components: []} }, () => { this.setState({ config: {...this.state.config, components: this.state.oriConfig.components} }) }) notification.success({ top: 92, message: '保存成功', duration: 2 }) } else { this.setState({ menuloading: false }) } }) }, 300) } getRoleFields = () => { if (sessionStorage.getItem('sysRoles') || sessionStorage.getItem('permFuncField')) return Api.getSystemConfig({func: 'sPC_Get_Roles_sModular'}).then(res => { if (res.status) { let _permFuncField = [] let _sysRoles = [] if (res.Roles && res.Roles.length > 0) { _sysRoles = res.Roles.map(role => { return { uuid: Utils.getuuid(), value: role.RoleID, text: role.RoleName } }) } if (res.sModular && res.sModular.length > 0) { res.sModular.forEach(field => { if (field.ModularNo) { _permFuncField.push(field.ModularNo) } }) _permFuncField = _permFuncField.sort() } sessionStorage.setItem('sysRoles', JSON.stringify(_sysRoles)) sessionStorage.setItem('permFuncField', JSON.stringify(_permFuncField)) } }) } onEnabledChange = () => { const { config } = this.state if (!config || (!config.enabled && this.verifyConfig(true))) { return } this.setState({ config: {...config, enabled: !config.enabled} }) } verifyConfig = (show) => { const { config } = this.state let error = '' config.components.forEach(item => { if (error) return if (['propcard', 'brafteditor', 'sandbox'].includes(item.subtype) && item.wrap.datatype === 'static') return if (item.setting) { if (item.setting.interType === 'system' && item.setting.execute !== 'false' && !item.setting.dataresource) { error = `组件《${item.name}》未设置数据源!` } else if (item.setting.interType === 'system' && item.setting.execute === 'false' && item.scripts.length === 0) { error = `组件《${item.name}》未设置数据源!` } else if (item.setting.interType && !item.setting.primaryKey) { error = `组件《${item.name}》未设置主键!` } } if (item.type === 'bar' || item.type === 'line' || item.type === 'pie') { if (!item.plot.Xaxis) { error = `组件《${item.name}》图表字段尚未设置!` } } }) if (show && error) { notification.warning({ top: 92, message: error, duration: 5 }) } return error } // 更新配置信息 updateConfig = (config) => { this.setState({ config: config }) this.props.modifyCustomMenu(config) } insert = (item) => { let config = fromJS(this.state.config).toJS() config.components.push(item) this.setState({config}) this.props.modifyCustomMenu(config) } refreshView = () => { const { oriConfig, config } = this.state if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) { notification.warning({ top: 92, message: '配置信息未保存!', duration: 5 }) return } // Api.getSystemConfig({ // func: 'sPC_MainMenu_Del', // MenuID: '1614740497468ku800sbg853vupf65v4' // }) sessionStorage.removeItem('sysRoles') sessionStorage.removeItem('permFuncField') sessionStorage.removeItem('app_videos') sessionStorage.removeItem('app_pictures') window.location.reload() } setHomeView = () => { const { oriConfig, config } = this.state if (!oriConfig || !is(fromJS(oriConfig), fromJS(config))) { notification.warning({ top: 92, message: '配置信息未保存!', duration: 5 }) return } let param = { func: 's_kei_link_keyids_addupt', BID: sessionStorage.getItem('appId'), exec_type: 'y', LText: '' } let appViewList = sessionStorage.getItem('appViewList') appViewList = appViewList ? JSON.parse(appViewList) : [] appViewList = appViewList.filter(item => item.keys_type !== 'index') appViewList.unshift({ appkey: window.GLOB.appkey || '', bid: sessionStorage.getItem('appId') || '', kei_no: sessionStorage.getItem('kei_no') || '', keys_id: config.MenuID, keys_type: 'index', remark: config.MenuName }) param.LText = appViewList.map(item => `select '${item.keys_id}','${item.keys_type}','${item.kei_no}','${item.appkey}','${item.bid}','${sessionStorage.getItem('CloudUserID')}','${item.remark}'`) param.LText = param.LText.join(' union all ') param.LText = Utils.formatOptions(param.LText) param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss') param.secretkey = Utils.encrypt('', param.timestamp) confirm({ title: '确定设置本页面为首页吗?', content: '', onOk() { Api.getSystemConfig(param).then(result => { if (!result.status) { notification.warning({ top: 92, message: result.message, duration: 5 }) } else { sessionStorage.setItem('appHomeId', config.MenuID) sessionStorage.setItem('appViewList', JSON.stringify(appViewList)) } }) }, onCancel() {} }) } editCard = (element) => { this.setState({ editElem: element }) } updateStyle = (proper) => { const { config } = this.state config.components = config.components.map(component => { if (component.uuid === proper.componentId) { Object.keys(component).forEach(key => { let _uuid = component[key].uuid if (_uuid && (_uuid === proper.uuid || _uuid === proper.classId)) { if (component[key].substyle) { } else { component[key].style = {...component[key].style, ...proper.style} // eslint-disable-next-line for (let index in component[key].style) { if (component[key].style[index] === '') { delete component[key].style[index] } } } } }) } return component }) this.setState({config}) } updateConfig = (config) => { this.setState({ config: config }) } render () { const { appType, config, editElem } = this.state const { localedict, loading, activeKey, dict, MenuId, config, menuloading, customComponents } = this.state return ( <div className="mobile-view"> <ConfigProvider locale={localedict}> <div className="mk-mob-view" id="mk-mob-design-view"> <Header /> {loading ? <Spin className="view-spin" size="large" /> : null} <DndProvider backend={HTML5Backend}> <div className="mob-body"> <div className="mob-tool"> <div className="mob-tool-content"> <div className="plus-content"> <Icon type="plus-circle" />添 加 组 件 </div> <div className="useable-component"> <SourceWrap appType={appType} /> </div> </div> <div className="mob-tool-other"></div> </div> {appType === 'mob' && config ? <div className="mob-shell"> <MobShell <div className="menu-setting"> <div className="pc-setting-tools"> <Collapse accordion activeKey={activeKey} bordered={false} onChange={(key) => this.setState({activeKey: key})}> {/* 基本信息 */} <Panel header={dict['mob.basemsg']} key="basedata"> {/* 菜单信息 */} {config ? <MenuForm dict={dict} config={config} deleteCard={this.deleteCard} editCard={this.editCard} editId={editElem ? editElem.uuid : ''} handleList={this.updateConfig} /> </div> : null } <div className="mob-setting"> {config ? <Tabs defaultActiveKey="1" animated={false} size="small"> <TabPane tab="配置" key="1"> <Controller editElem={editElem} updateStyle={this.updateStyle} /> </TabPane> <TabPane tab="数据源" key="2"> <DataSource config={config} updateConfig={this.updateConfig} /> </TabPane> </Tabs> : null} MenuId={MenuId} updateConfig={this.updateConfig} /> : null} {config ? <UrlFieldComponent config={config} updateConfig={this.updateConfig}/> : null} {/* 表名添加 */} {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null} </Panel> {/* 组件添加 */} <Panel header={dict['mob.component']} key="component"> <SourceWrap /> </Panel> {customComponents && customComponents.length ? <Panel header="自定义组件" key="cuscomponent"> <SourceWrap components={customComponents} /> </Panel> : null} <Panel header={'页面样式'} key="background"> {config ? <BgController config={config} updateConfig={this.updateConfig} /> : null} </Panel> </Collapse> </div> </div> <div className="menu-control"> <Button type="primary" onClick={this.submitConfig} loading={menuloading}>{dict['mob.save']}</Button> <Switch className="big" checkedChildren={dict['mob.enable']} unCheckedChildren={dict['mob.disable']} checked={config && config.enabled} onChange={this.onEnabledChange} /> <PasteController type="menu" Tab={null} insert={this.insert} /> <StyleCombControlButton menu={config} /> <SysInterface config={config} updateConfig={this.updateConfig}/> <PictureController/> <Quotecomponent config={config} updateConfig={this.updateConfig}/> <Button className="mk-border-green" icon="home" onClick={this.setHomeView}>设为首页</Button> <Button className="mk-border-danger" icon="redo" onClick={this.refreshView}>强制刷新</Button> <Button type="default" onClick={this.closeView}>{dict['mob.return']}</Button> </div> <div className={'menu-body' + (menuloading ? 'saving' : '')}> <div className="mob-shell"> {config ? <MobShell menu={config} handleList={this.updateConfig} /> : null} </div> </div> </DndProvider> <StyleController /> <StyleCombController /> <ModalController /> </div> </ConfigProvider> ) } } const mapStateToProps = () => { return {} const mapStateToProps = (state) => { return { memberLevel: state.memberLevel } } const mapDispatchToProps = () => { return {} const mapDispatchToProps = (dispatch) => { return { modifyCustomMenu: (customMenu) => dispatch(modifyCustomMenu(customMenu)) } } export default connect(mapStateToProps, mapDispatchToProps)(Mobile) export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MobDesign)) src/views/mobdesign/index.scss
@@ -1,77 +1,76 @@ .mobile-view { background: #000; .mk-mob-view { min-height: 100vh; .mob-body { width: 100vw; height: 100vh; overflow-x: hidden; position: relative; background: #262626; padding: 50px 300px 0px 40px; .mob-tool { >.view-spin { position: absolute; z-index: 3; left: calc(50% - 16px); top: calc(50vh - 70px); } .modal-form-board { padding-top: 0; } .menu-setting { position: fixed; left: 0; top: 48px; height: 100%; width: 40px; background: #262626; box-shadow: 2px 0px 2px #000; .mob-tool-content { width: 100%; .plus-content { position: relative; color: #ffffff; width: 100%; display: flex; align-items: center; writing-mode: tb-rl; padding: 16px 0; border-bottom: 1px solid #000; cursor: pointer; z-index: 10; background: #202735; i { margin-bottom: 5px; margin-left: 2px; } } transition: left 0.3s; .useable-component { position: absolute; width: 305px; top: 0; bottom: 0; left: -340px; background: #fff; opacity: 0; transition: left 0.3s linear 0.1s, opacity 0.3s linear 0.1s; overflow-y: auto; } } .mob-tool-content:hover { .useable-component { opacity: 1; left: 40px; } } .mob-tool-other { position: relative; z-index: 10; height: 1000px; background: #202735; } } .mob-setting { position: fixed; right: 0; top: 0; z-index: 10; height: 100%; .pc-setting-tools { height: calc(100vh - 48px); width: 300px; background: #202735; box-shadow: 0px 2px 2px #000; background: #ffffff; overflow-y: auto; overflow-x: hidden; > .ant-collapse { background-color: #ffffff; .ant-collapse-item.ant-collapse-item-active { border-bottom: 1px solid #d9d9d9; } .ant-collapse-header { padding: 11px 16px 10px 40px; border-bottom: 1px solid #d9d9d9; background: #1890ff; color: #ffffff; } .ant-collapse-content-box { .ant-form-item { margin-bottom: 10px; } .model-table-tablemanage-view { >.ant-list { margin-top: 20px; .ant-list-item { display: -webkit-box; padding-right: 20px; position: relative; padding-left: 5px; overflow: hidden; text-overflow: ellipsis; -webkit-line-clamp: 2; -webkit-box-orient: vertical; min-height: 55px; width: 100%; .anticon { position: absolute; top: 0px; right: 0px; padding: 3px 3px 10px 10px; cursor: pointer; } } } >.tables { width: 66.66666667%!important; } >.ant-form-item-label { width: 33.33333333%; } } } } >.ant-tabs { >.ant-tabs-bar { @@ -88,12 +87,26 @@ } } } .pc-setting-tools::-webkit-scrollbar { width: 4px; } .pc-setting-tools::-webkit-scrollbar-thumb { border-radius: 5px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08); background: rgba(0, 0, 0, 0.08); } .pc-setting-tools::-webkit-scrollbar-track { box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); border-radius: 3px; border: 1px solid rgba(0, 0, 0, 0.07); background: rgba(0, 0, 0, 0); } } .mob-shell { width: 375px; height: 680px; margin: 0 auto; background: #ffffff; background: #000000; background-size: 100% 100%; padding: 25px 13px 40px; border-radius: 30px; @@ -103,6 +116,7 @@ height: 100%; overflow-y: auto; overflow-x: hidden; background: #ffffff; box-shadow: 0px 0px 2px #000000; } .mob-shell-inner::-webkit-scrollbar { @@ -120,30 +134,66 @@ border-radius: 3px; } } .menu-control { position: fixed; right: 0; top: 48px; height: 100vh; padding: 20px 10px; background: #ffffff; z-index: 10; transition: right 0.3s; div:not(.draw), button:not(.ant-switch) { display: block!important; margin-bottom: 15px; width: 100%; } .ant-switch.big { min-width: 60px; height: 24px; line-height: 24px; margin-bottom: 15px; .ant-switch-inner { font-size: 14px; } } .ant-switch.big:after { width: 22px; height: 22px; } } .flex-container { margin: 0 15px; .menu-body { width: 100vw; height: 100vh; overflow-x: hidden; position: relative; background: #959595; padding: 50px 0px 0px; overflow-y: auto; .menu-shell-inner { min-height: 100vh; margin: 0 auto; } .flex-container .inline { width: 80px!important; margin: 9px 9px 9px 0; } .flex-container .small { height: 20px!important; line-height: 20px!important; .menu-body.saving { .anticon-tool { display: none; } .sub-title { color: #888; font-size: 14px; padding: 30px 0 18px 0; } .placeholder { background-color: #ebebef; color: #bbb; text-align: center; height: 30px; line-height: 30px; width: 100%; .menu-body::-webkit-scrollbar { width: 7px; } .menu-body::-webkit-scrollbar-thumb { border-radius: 5px; box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.08); background: rgba(0, 0, 0, 0.08); } .menu-body::-webkit-scrollbar-track { box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.05); border-radius: 3px; border: 1px solid rgba(0, 0, 0, 0.07); background: rgba(0, 0, 0, 0); } } src/views/mobdesign/menuform/index.jsx
New file @@ -0,0 +1,138 @@ import React, {Component} from 'react' import PropTypes from 'prop-types' import { Form, Row, Col, Input, Radio, Icon, Tooltip, InputNumber } from 'antd' import './index.scss' class CustomMenuForm extends Component { static propTpyes = { dict: PropTypes.object, // 字典项 config: PropTypes.object, MenuId: PropTypes.string, updateConfig: PropTypes.func } state = {} // 一二级菜单切换 selectChange = (key, value) => { const { config } = this.props if (key === 'cacheUseful') { this.props.updateConfig({...config, cacheUseful: value}) } else if (key === 'timeUnit') { this.props.updateConfig({...config, timeUnit: value}) } } // 菜单名称 changeName = (e) => { this.props.updateConfig({...this.props.config, MenuName: e.target.value}) } // 菜单参数 changeNo = (e) => { this.props.updateConfig({...this.props.config, MenuNo: e.target.value}) } changeCacheDay = (val) => { if (typeof(val) !== 'number') { val = '' } this.props.updateConfig({...this.props.config, cacheTime: val}) } render() { const { dict, config } = this.props const { getFieldDecorator } = this.props.form const formItemLayout = { labelCol: { xs: { span: 24 }, sm: { span: 8 } }, wrapperCol: { xs: { span: 24 }, sm: { span: 16 } } } return ( <Form {...formItemLayout} className="custom-menu-form"> <Row> <Col span={24}> <Form.Item label={dict['mob.menu'] + dict['mob.name']}> {getFieldDecorator('MenuName', { initialValue: config.MenuName, rules: [ { required: true, message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.name'] + '!' } ] })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeName}/>)} </Form.Item> </Col> <Col span={24}> <Form.Item label={dict['mob.menu'] + dict['mob.param']}> {getFieldDecorator('MenuNo', { initialValue: config.MenuNo, rules: [ { required: true, message: dict['mob.required.input'] + dict['mob.menu'] + dict['mob.param'] + '!' } ] })(<Input placeholder="" disabled={!!(config.fixed && config.MenuName)} autoComplete="off" onChange={this.changeNo}/>)} </Form.Item> </Col> <Col span={24}> <Form.Item label={ <Tooltip placement="topLeft" title="对于不经常性变动的信息,缓存数据有助于提高查询效率。"> <Icon type="question-circle" /> 缓存数据 </Tooltip> }> {getFieldDecorator('cacheUseful', { initialValue: config.cacheUseful || 'false' })( <Radio.Group onChange={(e) => {this.selectChange('cacheUseful', e.target.value)}}> <Radio value="true">使用</Radio> <Radio value="false">不使用</Radio> </Radio.Group> )} </Form.Item> </Col> {config.cacheUseful === 'true' ? <Col span={24}> <Form.Item label="单位"> {getFieldDecorator('timeUnit', { initialValue: config.timeUnit || 'day' })( <Radio.Group onChange={(e) => {this.selectChange('timeUnit', e.target.value)}}> <Radio value="day">天</Radio> <Radio value="hour">小时</Radio> </Radio.Group> )} </Form.Item> </Col> : null} {config.cacheUseful === 'true' ? <Col span={24}> <Form.Item label="时长"> {getFieldDecorator('cacheTime', { initialValue: config.cacheTime, rules: [ { required: true, message: dict['mob.required.input'] + '时长!' } ] })( <InputNumber min={1} max={config.timeUnit !== 'hour' ? 7 : 23} precision={0} onChange={this.changeCacheDay}/> )} </Form.Item> </Col> : null} </Row> </Form> ) } } export default Form.create()(CustomMenuForm) src/views/mobdesign/menuform/index.scss
New file @@ -0,0 +1,10 @@ .custom-menu-form { .anticon-question-circle { color: #c49f47; position: relative; left: -3px; } .ant-input-number { width: 100%; } } src/views/pcdesign/index.jsx
@@ -31,6 +31,7 @@ const PasteController = asyncComponent(() => import('@/menu/pastecontroller')) const StyleController = asyncComponent(() => import('@/menu/stylecontroller')) const SysInterface = asyncComponent(() => import('@/menu/sysinterface')) const UrlFieldComponent = asyncComponent(() => import('@/menu/urlfieldcomponent')) const PictureController = asyncComponent(() => import('@/menu/picturecontroller')) const ModalController = asyncComponent(() => import('@/menu/modalconfig/controller')) const StyleCombController = asyncComponent(() => import('@/menu/stylecombcontroller')) @@ -43,6 +44,7 @@ document.body.className = '' window.GLOB.UserComponentMap = new Map() // 缓存用户自定义组件 window.GLOB.CacheIndependent = new Map() window.GLOB.urlFields = [] // url变量 class MenuDesign extends Component { state = { @@ -446,6 +448,7 @@ config.uuid = MenuId config.MenuID = MenuId config.open_edition = result.open_edition || '' window.GLOB.urlFields = config.urlFields || [] if (urlParam.fixed) { config.fixed = true @@ -1424,6 +1427,7 @@ MenuId={MenuId} updateConfig={this.updateConfig} /> : null} {config ? <UrlFieldComponent config={config} updateConfig={this.updateConfig}/> : null} {/* 表名添加 */} {config ? <TableComponent config={config} updatetable={this.updateConfig}/> : null} </Panel>