king
2020-10-11 5902ba5c3ff85efc78c95364196cd6ab5d2d1601
2020-10-11
20个文件已修改
8个文件已添加
1063 ■■■■ 已修改文件
src/assets/css/action.scss 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/actionform/index.jsx 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/dragaction/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/actioncomponent/formconfig.jsx 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/action.jsx 78 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/card.jsx 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/dragaction/index.jsx 57 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/elementform/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/formconfig.jsx 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.jsx 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcellcomponent/index.scss 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/cardcomponent/index.jsx 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.jsx 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/components/card/data-card/index.scss 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/index.jsx 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/datasource/verifycard/index.jsx 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/menu/stylecontroller/index.jsx 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardItem/index.jsx 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardItem/index.scss 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.jsx 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/cardcellList/index.scss 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/asyncButtonComponent.jsx 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.jsx 118 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/card/data-card/index.scss 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/components/chart/antv-bar-line/index.jsx 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.jsx 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/tabviews/custom/index.scss 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/option.js 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/assets/css/action.scss
@@ -16,6 +16,13 @@
    border-color: #1890ff;
  }
  // 青色
  .mk-cyan, .mk-cyan:hover, .mk-cyan:active, .mk-cyan:focus {
    color: #fff;
    background-color: #13c2c2;
    border-color: #13c2c2;
  }
  // 默认与虚线
  .mk-default, .mk-default:hover, .mk-default:active, .mk-default:focus {
    color: rgba(0, 0, 0, 0.65);
@@ -137,6 +144,9 @@
  .mk-icon.mk-primary, .mk-icon.mk-border-primary {
    color: #1890ff;
  }
  .mk-icon.mk-cyan {
    color: #13c2c2;
  }
  .mk-icon.mk-default, .mk-icon.mk-dashed {
    color: rgba(0, 0, 0, 0.65);
  }
@@ -162,7 +172,13 @@
  // 链接颜色
  .mk-link, .mk-link:hover, .mk-link:active, .mk-link:focus {
    background: transparent;
    border-color: transparent;
    line-height: 1.5;
    .anticon {
      margin-left: 0px;
      line-height: inherit;
    }
    span + .anticon {
      margin-left: 5px;
    }
  }
@@ -172,6 +188,9 @@
  .mk-link.mk-primary, .mk-link.mk-border-primary {
    color: #1890ff;
  }
  .mk-link.mk-cyan {
    color: #13c2c2;
  }
  .mk-link.mk-default, .mk-link.mk-dashed {
    color: rgba(0, 0, 0, 0.65);
  }
src/menu/actioncomponent/actionform/index.jsx
@@ -2,7 +2,7 @@
import PropTypes from 'prop-types'
import { fromJS } from 'immutable'
import { Form, Row, Col, Input, Select, Icon, Radio, notification, Tooltip, InputNumber, Cascader } from 'antd'
import { btnIcons, btnClasses, formRule } from '@/utils/option.js'
import { btnIcons, btnCustomClasses, formRule } from '@/utils/option.js'
import Api from '@/api'
import options from '@/store/options.js'
@@ -10,15 +10,15 @@
const { TextArea } = Input
const actionTypeOptions = {
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'sheet', 'execSuccess', 'execError', 'syncComponent'],
  excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'popClose'],
  tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'linkmenu'],
  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'icon', 'class'],
  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'icon', 'class']
  pop: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent', 'width'],
  prompt: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent', 'width'],
  exec: ['label', 'OpenType', 'intertype', 'Ot', 'show', 'icon', 'class', 'execSuccess', 'execError', 'syncComponent', 'width'],
  excelIn: ['label', 'Ot', 'OpenType', 'intertype', 'show', 'icon', 'class', 'sheet', 'execSuccess', 'execError', 'syncComponent', 'width'],
  excelOut: ['label', 'OpenType', 'intertype', 'show', 'icon', 'class', 'execSuccess', 'execError', 'pagination', 'search', 'width'],
  popview: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'popClose', 'width'],
  tab: ['label', 'Ot', 'OpenType', 'show', 'icon', 'class', 'linkmenu', 'width'],
  innerpage: ['label', 'Ot', 'OpenType', 'pageTemplate', 'show', 'icon', 'class', 'width'],
  funcbutton: ['label', 'OpenType', 'funcType', 'show', 'icon', 'class', 'width']
}
class MainSearch extends Component {
@@ -98,7 +98,7 @@
      funcType: _funcType,
      formlist: this.props.formlist.map(item => {
        if (item.key === 'class') {
          item.options = btnClasses
          item.options = btnCustomClasses
        } else if (item.key === 'icon') {
          item.options = btnIcons
        } else if (item.key === 'Ot') {
@@ -385,7 +385,7 @@
    const fields = []
    this.state.formlist.forEach((item, index) => {
      if (item.hidden) return
      if (item.hidden || item.forbid) return
      if (item.type === 'text') { // 文本搜索
        let _rules = []
src/menu/actioncomponent/dragaction/index.jsx
@@ -102,7 +102,7 @@
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'prompt'
    newcard.icon = ''
    newcard.class = 'default'
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
src/menu/actioncomponent/formconfig.jsx
@@ -292,6 +292,18 @@
      }]
    },
    {
      type: 'number',
      key: 'width',
      min: 1,
      max: 24,
      precision: 0,
      label: '宽度',
      initVal: card.width || 12,
      tooltip: '每行等分为24份。',
      forbid: type !== 'card',
      required: true
    },
    {
      type: 'select',
      key: 'show',
      label: "显示为",
src/menu/components/card/cardcellcomponent/dragaction/action.jsx
New file
@@ -0,0 +1,78 @@
import React from 'react'
import { useDrag, useDrop } from 'react-dnd'
import { Icon, Popover, Button } from 'antd'
import './index.scss'
const Card = ({ id, cardIds, card, moveCard, findCard, editCard, delCard, profileCard, changeStyle }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'action', id, originalIndex },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
  })
  const [, drop] = useDrop({
    accept: 'action',
    canDrop: () => true,
    drop({ id: draggedId }) {
      if (!draggedId) return
      if (!cardIds.includes(draggedId)) return
      if (draggedId !== id) {
        const { index: overIndex } = findCard(id)
        moveCard(draggedId, overIndex)
      }
    },
  })
  let _style = {opacity: isDragging ? 0 : 1}
  if (card.style) {
    _style = {...card.style, opacity: isDragging ? 0 : 1}
  }
  let hasProfile = false
  if (['pop', 'prompt', 'exec'].includes(card.OpenType)) {
    hasProfile = true
  } else if (card.OpenType === 'excelIn' || card.OpenType === 'excelOut') {
    hasProfile = true
  } else if (card.funcType === 'print') {
    hasProfile = true
  }
  let btnElement = null
  if (card.show === 'icon') {
    btnElement = (card.icon ? <Button className={'mk-link mk-' + card.class} style={card.btnstyle} type="link"><Icon type={card.icon}/></Button> : null)
  } else if (card.show === 'link') {
    btnElement = (
      <Button className={'mk-link mk-' + card.class} style={card.btnstyle} type="link">{card.label}{card.icon ? <Icon type={card.icon}/> : null}</Button>
    )
  } else {
    btnElement = (
      <Button
        className={'mk-btn mk-' + card.class}
        icon={card.icon}
        style={card.btnstyle}
        // onDoubleClick={() => doubleClickCard(id)}
      >
        {card.label}
      </Button>
    )
  }
  return (
    <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
      <div className="mk-popover-control">
        <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
        <Icon className="close" title="close" type="close" onClick={() => delCard(id)} />
        <Icon className="style" title="调整样式" onClick={() => changeStyle(id)} type="font-colors" />
        {hasProfile ? <Icon className="profile" title="setting" type="profile" onClick={() => profileCard(id)} /> : null}
      </div>
    } trigger="hover">
      <div ref={node => drag(drop(node))} className={'ant-col card-button-cell ant-col-' + card.width} style={_style}>
        {btnElement}
      </div>
    </Popover>
  )
}
export default Card
src/menu/components/card/cardcellcomponent/dragaction/card.jsx
@@ -9,7 +9,7 @@
import demo4 from '@/assets/img/demo4.jpg'
import demo5 from '@/assets/img/demo5.jpg'
const Card = ({ id, cardIds, card, moveCard, findCard, editCard, delCard }) => {
const Card = ({ id, cardIds, card, moveCard, findCard, editCard, delCard, changeStyle }) => {
  const originalIndex = findCard(id).index
  const [{ isDragging }, drag] = useDrag({
    item: { type: 'action', id, originalIndex },
@@ -32,18 +32,9 @@
  })
  let _style = {opacity: isDragging ? 0 : 1}
  _style.textAlign = card.align
  _style.color = card.color
  
  if (card.padding) {
    _style.padding = card.padding
  }
  if (card.fontSize) {
    _style.fontSize = card.fontSize + 'px'
  }
  if (card.fontWeight) {
    _style.fontWeight = card.fontWeight
  if (card.style) {
    _style = {...card.style, opacity: isDragging ? 0 : 1}
  }
  const getContent = () => {
@@ -102,7 +93,7 @@
      <div className="mk-popover-control">
        <Icon className="edit" title="edit" type="edit" onClick={() => editCard(id)} />
        <Icon className="close" title="close" type="close" onClick={() => delCard(id)} />
        {/* <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" /> */}
        <Icon className="style" title="调整样式" onClick={() => changeStyle(id)} type="font-colors" />
      </div>
    } trigger="hover">
      <div ref={node => drag(drop(node))} className={'ant-col card-cell ant-col-' + card.width} style={_style}>
src/menu/components/card/cardcellcomponent/dragaction/index.jsx
@@ -4,9 +4,10 @@
import update from 'immutability-helper'
import Card from './card'
import Action from './action'
import './index.scss'
const Container = ({list, handleList, handleMenu, deleteMenu }) => {
const Container = ({list, handleList, handleMenu, deleteMenu, profileAction, handleStyle }) => {
  const [cards, setCards] = useState(list)
  const moveCard = (id, atIndex) => {
    const { card, index } = findCard(id)
@@ -31,6 +32,16 @@
    handleMenu(card)
  }
  const changeStyle = id => {
    const { card } = findCard(id)
    handleStyle(card)
  }
  const profileCard = id => {
    const { card } = findCard(id)
    profileAction(card)
  }
  const delCard = id => {
    const { card } = findCard(id)
    deleteMenu(card)
@@ -45,18 +56,38 @@
  return (
    <div ref={drop} className="ant-row card-detail-row">
      {cards.map(card => (
        <Card
          id={card.uuid}
          key={card.uuid}
          cardIds={cardIds}
          card={card}
          moveCard={moveCard}
          editCard={editCard}
          delCard={delCard}
          findCard={findCard}
        />
      ))}
      {cards.map(card => {
        if (card.eleType === 'button') {
          return (
            <Action
              id={card.uuid}
              key={card.uuid}
              cardIds={cardIds}
              card={card}
              moveCard={moveCard}
              editCard={editCard}
              changeStyle={changeStyle}
              profileCard={profileCard}
              delCard={delCard}
              findCard={findCard}
            />
          )
        } else {
          return (
            <Card
              id={card.uuid}
              key={card.uuid}
              cardIds={cardIds}
              card={card}
              moveCard={moveCard}
              editCard={editCard}
              changeStyle={changeStyle}
              delCard={delCard}
              findCard={findCard}
            />
          )
        }
      })}
    </div>
  )
}
src/menu/components/card/cardcellcomponent/elementform/index.jsx
@@ -9,11 +9,11 @@
import './index.scss'
const cardTypeOptions = {
  text: ['eleType', 'datatype', 'value', 'format', 'fontSize', 'fontWeight', 'width', 'height', 'color', 'align', 'padding', 'prefix', 'postfix'],
  number: ['eleType', 'datatype', 'value', 'format', 'fontSize', 'fontWeight', 'width', 'height', 'color', 'align', 'padding', 'prefix', 'postfix'],
  text: ['eleType', 'datatype', 'value', 'format', 'fontSize', 'fontWeight', 'width', 'height', 'align', 'padding', 'prefix', 'postfix'],
  number: ['eleType', 'datatype', 'value', 'format', 'fontSize', 'fontWeight', 'width', 'height', 'align', 'padding', 'prefix', 'postfix'],
  picture: ['eleType', 'datatype', 'width', 'lenWidRadio', 'radius', 'padding', 'url'],
  icon: ['eleType', 'icon', 'fontSize', 'width', 'height', 'color', 'align', 'padding', 'tooltip'],
  link: ['eleType', 'datatype', 'value', 'labelfield', 'fontSize', 'width', 'height', 'color', 'align', 'padding', 'prefix'],
  icon: ['eleType', 'icon', 'fontSize', 'width', 'height', 'align', 'padding', 'tooltip'],
  link: ['eleType', 'datatype', 'value', 'labelfield', 'fontSize', 'width', 'height', 'align', 'padding', 'prefix'],
  slider: ['eleType', 'field', 'width', 'color', 'padding', 'maxValue'],
  splitline: ['eleType', 'color', 'width', 'padding'],
}
src/menu/components/card/cardcellcomponent/formconfig.jsx
@@ -148,54 +148,11 @@
      ]
    },
    {
      type: 'radio',
      key: 'align',
      label: '对齐方式',
      initVal: card.align || 'left',
      required: true,
      options: [
        { value: 'left', text: '左对齐' },
        { value: 'center', text: '居中' },
        { value: 'right', text: '右对齐' },
      ]
    },
    {
      type: 'number',
      key: 'fontSize',
      min: 12,
      max: 50,
      label: '字体大小',
      initVal: card.fontSize || 14,
      required: true,
    },
    {
      type: 'select',
      key: 'fontWeight',
      label: '字体粗细',
      initVal: card.fontWeight || 'normal',
      required: true,
      options: [
        { value: 'normal', text: '正常' },
        { value: 'bold', text: 'bold' },
        { value: 'bolder', text: 'bolder' },
        { value: 'lighter', text: 'lighter' },
        { value: '100', text: '100' },
        { value: '200', text: '200' },
        { value: '300', text: '300' },
        { value: '400', text: '400' },
        { value: '500', text: '500' },
        { value: '600', text: '600' },
        { value: '700', text: '700' },
        { value: '800', text: '800' },
        { value: '900', text: '900' }
      ]
    },
    {
      type: 'color',
      key: 'color',
      label: '颜色',
      initVal: card.color,
      required: false
      required: true
    },
    {
      type: 'number',
@@ -249,14 +206,6 @@
        { value: 'true', text: '有' },
        { value: 'false', text: '无' }
      ]
    },
    {
      type: 'text',
      key: 'padding',
      label: '内边距',
      initVal: card.padding,
      tooltip: '内边距需要按照固定格式填写,例:5px(上下左右均为5像素),5px 10px(上下5像素,左右10像素),5px 10px 15px(上5像素,左右10像素,下15像素),5px 10px 5px 10px(上5像素,右10像素,下5像素,左10像素)',
      required: false
    },
  ]
src/menu/components/card/cardcellcomponent/index.jsx
@@ -16,6 +16,10 @@
import DragElement from './dragaction'
import ActionForm from '@/menu/actioncomponent/actionform'
import CreateFunc from '@/templates/zshare/createfunc'
import VerifyCard from '@/templates/zshare/verifycard'
import VerifyPrint from '@/menu/actioncomponent/verifyprint'
import VerifyExcelIn from '@/menu/actioncomponent/verifyexcelin'
import VerifyExcelOut from '@/menu/actioncomponent/verifyexcelout'
import './index.scss'
const { confirm } = Modal
@@ -23,7 +27,8 @@
class CardCellComponent extends Component {
  static propTpyes = {
    cards: PropTypes.object,         // 菜单配置信息
    card: PropTypes.object,
    cardCell: PropTypes.object,
    side: PropTypes.string,
    elements: PropTypes.array,       // 元素集
    updateElement: PropTypes.func    // 菜单配置更新
  }
@@ -34,7 +39,8 @@
    formlist: null,      // 表单信息
    elements: null,      // 按钮组
    visible: false,      // 模态框控制
    actvisible: false    // 按钮编辑模态框
    actvisible: false,   // 按钮编辑模态框
    profVisible: false
  }
  /**
@@ -50,10 +56,19 @@
  componentDidMount () {
    MKEmitter.addListener('cardAddElement', this.cardAddElement)
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.props.cards), fromJS(nextProps.cards)) || !is(fromJS(this.state), fromJS(nextState))
  }
  UNSAFE_componentWillReceiveProps(nextProps) {
    if (this.props.side !== nextProps.side) {
      this.setState({
        elements: fromJS(nextProps.elements).toJS()
      })
    }
  }
  /**
@@ -67,17 +82,107 @@
  }
  cardAddElement = (ids, element) => {
    if (!ids || ids.length !== 2 || ids[0] !== this.props.cards.uuid || ids[1] !== this.props.card.uuid) return
    const { cards, cardCell } = this.props
    if (!ids || ids.length !== 2 || ids[0] !== cards.uuid || ids[1] !== cardCell.uuid) return
    const { elements } = this.state
    this.setState({elements: [...elements, element]})
    this.handleElement(element)
  }
  handleStyle = (element) => {
    const { cards, cardCell } = this.props
    let _style = element.style ? fromJS(element.style).toJS() : {}
    let options = ['font', 'border', 'padding', 'margin']
    if (element.eleType === 'button') {
      this.handleAction(element)
    } else {
      this.handleElement(element)
      options.push('background')
      if (element.btnstyle) {
        _style = {..._style, ...element.btnstyle}
      }
    } else if (element.eleType === 'picture') {
      options = ['border', 'margin']
    } else if (element.eleType === 'slider') {
      options = ['padding', 'margin']
    } else if (element.eleType === 'splitline') {
      options = ['padding', 'margin']
    }
    this.setState({
      card: element
    })
    MKEmitter.emit('changeStyle', [cards.uuid, cardCell.uuid, element.uuid], options, _style)
  }
  getStyle = (comIds, style) => {
    const { cards, cardCell } = this.props
    const { card, elements } = this.state
    if (comIds.length !== 3 || comIds[0] !== cards.uuid || comIds[1] !== cardCell.uuid) return
    let _card = fromJS(card).toJS()
    if (card.eleType === 'button') { // 拆分style
      let _style = fromJS(style).toJS()
      _card.style = {}
      if (_style.marginTop) {
        _card.style.marginTop = _style.marginTop
        delete _style.marginTop
      }
      if (_style.marginBottom) {
        _card.style.marginBottom = _style.marginBottom
        delete _style.marginBottom
      }
      if (_style.marginLeft) {
        _card.style.marginLeft = _style.marginLeft
        delete _style.marginLeft
      }
      if (_style.marginRight) {
        _card.style.marginRight = _style.marginRight
        delete _style.marginRight
      }
      if (_style.paddingTop) {
        _card.style.paddingTop = _style.paddingTop
        delete _style.paddingTop
      }
      if (_style.paddingBottom) {
        _card.style.paddingBottom = _style.paddingBottom
        delete _style.paddingBottom
      }
      if (_style.paddingLeft) {
        _card.style.paddingLeft = _style.paddingLeft
        delete _style.paddingLeft
      }
      if (_style.paddingRight) {
        _card.style.paddingRight = _style.paddingRight
        delete _style.paddingRight
      }
      if (_style.textAlign) {
        _card.style.textAlign = _style.textAlign
        delete _style.textAlign
      }
      _card.btnstyle = _style
    } else {
      _card.style = style
    }
    let _elements = elements.map(cell => {
      if (cell.uuid === _card.uuid) return _card
      return cell
    })
    this.setState({
      elements: _elements
    }, () => {
      this.props.updateElement(_elements)
    })
  }
  /**
@@ -93,11 +198,15 @@
   * @description 元素编辑,获取元素表单信息
   */
  handleElement = (card) => {
    this.setState({
      visible: true,
      card: card,
      formlist: getCardCellForm(card)
    })
    if (card.eleType === 'button') {
      this.handleAction(card)
    } else {
      this.setState({
        visible: true,
        card: card,
        formlist: getCardCellForm(card)
      })
    }
  }
  /**
@@ -172,14 +281,14 @@
        this.setState({
          actvisible: true,
          card: card,
          formlist: getActionForm(card, functip, cards.setting, menu.permFuncField, '', menulist, modules)
          formlist: getActionForm(card, functip, cards.setting, menu.permFuncField, 'card', menulist, modules)
        })
      })
    } else {
      this.setState({
        actvisible: true,
        card: card,
        formlist: getActionForm(card, functip, cards.setting, menu.permFuncField, '', menulist, modules)
        formlist: getActionForm(card, functip, cards.setting, menu.permFuncField, 'card', menulist, modules)
      })
    }
  }
@@ -264,7 +373,11 @@
    this.elementFormRef.handleConfirm().then(ele => {
      let _elements = elements.map(cell => {
        if (cell.uuid === ele.uuid) return ele
        if (cell.uuid === ele.uuid) {
          ele.style = cell.style || {}
          ele.btnstyle = cell.btnstyle || {}
          return ele
        }
        return cell
      })
@@ -285,7 +398,12 @@
    this.actionFormRef.handleConfirm().then(ele => {
      let _elements = elements.map(cell => {
        if (cell.uuid === ele.uuid) return ele
        if (cell.uuid === ele.uuid) {
          ele.eleType = 'button'
          ele.style = cell.style || {}
          return ele
        }
        return cell
      })
@@ -320,9 +438,46 @@
    })
  }
  /**
   * @description 验证信息配置
   */
  profileAction = (element) => {
    this.setState({
      profVisible: true,
      card: element
    })
  }
  /**
   * @description 验证信息保存
   */
  verifySubmit = () => {
    const { elements } = this.state
    this.verifyRef.handleConfirm().then(res => {
      console.log(res)
      let _elements = elements.map(cell => {
        if (cell.uuid === res.uuid) {
          res.eleType = 'button'
          res.style = cell.style || {}
          return res
        }
        return cell
      })
      this.setState({
        elements: _elements,
        actvisible: false
      }, () => {
        this.props.updateElement(_elements)
      })
    })
  }
  render() {
    const { cards } = this.props
    const { elements, visible, actvisible, card, dict } = this.state
    const { elements, visible, actvisible, profVisible, card, dict } = this.state
    return (
      <div className="model-menu-card-cell-list">
@@ -330,6 +485,8 @@
          list={elements}
          handleList={this.handleList}
          handleMenu={this.handleElement}
          handleStyle={this.handleStyle}
          profileAction={this.profileAction}
          deleteMenu={this.deleteElement}
        />
        {/* 编辑按钮:复制、编辑 */}
@@ -374,6 +531,54 @@
            wrappedComponentRef={(inst) => this.actionFormRef = inst}
          />
        </Modal>
        {/* 按钮使用系统存储过程时,验证信息模态框 */}
        <Modal
          wrapClassName="model-table-action-verify-modal"
          title={'验证信息'}
          visible={profVisible}
          width={'75vw'}
          maskClosable={false}
          style={{minWidth: '900px', maxWidth: '1200px'}}
          okText={dict['model.submit']}
          onOk={this.verifySubmit}
          onCancel={() => { this.setState({ profVisible: false }) }}
          destroyOnClose
        >
          {card && !card.execMode && card.OpenType !== 'excelIn' && card.OpenType !== 'excelOut' ?
            <VerifyCard
              // floor={this.props.type}
              card={card}
              dict={dict}
              config={cards}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.execMode ?
            <VerifyPrint
              card={card}
              dict={dict}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.OpenType === 'excelIn' ?
            <VerifyExcelIn
              card={card}
              dict={dict}
              columns={cards.columns}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
          {card && card.OpenType === 'excelOut' ?
            <VerifyExcelOut
              card={card}
              dict={dict}
              config={cards}
              wrappedComponentRef={(inst) => this.verifyRef = inst}
            /> : null
          }
        </Modal>
      </div>
    )
  }
src/menu/components/card/cardcellcomponent/index.scss
@@ -16,6 +16,21 @@
    cursor: pointer;
  }
  .card-cell {
    border-style: solid;
    border-width: 0;
  }
  .card-button-cell {
    float: left;
    button {
      background-size: cover;
      background-position: center center;
      span {
        font-style: inherit;
        text-decoration: inherit;
      }
    }
  }
  .card-cell:hover {
    box-shadow: 0px 0px 1px #d8d8d8;
  }
src/menu/components/card/cardcomponent/index.jsx
@@ -153,7 +153,7 @@
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'prompt'
    newcard.icon = ''
    newcard.class = 'default'
    newcard.class = 'primary'
    newcard.intertype = 'system'
    newcard.method = 'POST'
    newcard.execSuccess = 'grid'
@@ -177,7 +177,7 @@
      _style = card.style ? fromJS(card.style).toJS() : {}
    } else if (side === 'back') {
      _style = card.backStyle ? fromJS(card.backStyle).toJS() : {}
      options = ['background', 'border', 'padding', 'margin']
      options = ['background', 'padding']
    }
    MKEmitter.emit('changeStyle', [cards.uuid, card.uuid], options, _style)
@@ -214,7 +214,7 @@
    return (
      <div className={'ant-col card-item ant-col-' + (card.setting.width || 6)} style={_style}>
        <CardCellComponent cards={cards} card={card} elements={elements} updateElement={this.updateCard}/>
        <CardCellComponent cards={cards} cardCell={card} side={side} 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">
@@ -222,8 +222,8 @@
              <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
              <Icon className="edit" type="edit" onClick={() => this.setState({settingVisible: true})} />
              <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
              {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
              <Icon className="close" title="删除卡片" type="delete" onClick={() => this.props.deleteElement(card)} />
              {card.setting.type === 'multi' ? <Switch size="small" onClick={this.changeSide} defaultChecked /> : null}
            </div>
          } trigger="hover">
            <Icon type="tool" />
src/menu/components/card/data-card/index.jsx
@@ -68,7 +68,7 @@
        subcards: [{
          uuid: Utils.getuuid(),
          setting: { width: 6, type: 'simple'},
          style: {borderWidth: '1px', borderColor: '#e8e8e8'},
          style: {borderWidth: '1px', borderColor: '#e8e8e8', paddingTop: '15px', paddingBottom: '15px', paddingLeft: '15px', paddingRight: '15px'},
          backStyle: {},
          elements: [],
          backElements: []
src/menu/components/card/data-card/index.scss
@@ -7,7 +7,7 @@
  background-size: cover;
  border-style: solid;
  border-width: 0;
  min-height: 50px;
  min-height: 100px;
  
  .card-control {
    position: absolute;
@@ -16,6 +16,7 @@
    .anticon-tool {
      right: auto;
      left: 1px;
      padding: 1px;
    }
  }
  .anticon-tool {
src/menu/datasource/index.jsx
@@ -18,6 +18,7 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    sourcelist: [],
    mainSearch: [],
    visible: false,
    loading: false,
    setting: null
@@ -35,7 +36,8 @@
  editDataSource = () => {
    this.setState({
      visible: true
      visible: true,
      mainSearch: []
    })
  }
@@ -54,7 +56,7 @@
  render () {
    const { config, menu } = this.props
    const { visible, dict, loading } = this.state
    const { visible, dict, loading, mainSearch } = this.state
    return (
      <div className="model-datasource">
@@ -75,6 +77,7 @@
          <VerifyCard
            dict={dict}
            menu={menu}
            mainSearch={mainSearch}
            config={config}
            wrappedComponentRef={(inst) => this.verifyRef = inst}
          />
src/menu/datasource/verifycard/index.jsx
@@ -122,12 +122,16 @@
  }
  UNSAFE_componentWillMount() {
    const { config } = this.props
    const { config, mainSearch } = this.props
    let search = config.search || []
    search = [...search, ...mainSearch]
    this.setState({
      columns: fromJS(config.columns).toJS(),
      setting: fromJS(config.setting).toJS(),
      scripts: fromJS(config.scripts).toJS()
      scripts: fromJS(config.scripts).toJS(),
      searches: search
    })
    this.getsysScript()
@@ -410,8 +414,7 @@
  }
  sqlverify = (resolve, reject, change = false, testScripts) => {
    const { config } = this.props
    const { columns, setting, scripts } = this.state
    const { columns, setting, scripts, searches } = this.state
    let _scripts = scripts.filter(item => item.status !== 'false')
@@ -431,7 +434,7 @@
    if ((setting.interType === 'system' && setting.execute !== 'false') || _scripts.length > 0) {
      let param = {
        func: 's_debug_sql',
        LText: SettingUtils.getDebugSql(setting, _scripts, columns, config.search)
        LText: SettingUtils.getDebugSql(setting, _scripts, columns, searches)
      }
      param.LText = Utils.formatOptions(param.LText)
      param.timestamp = moment().format('YYYY-MM-DD HH:mm:ss')
@@ -469,7 +472,7 @@
  render() {
    const { menu, config } = this.props
    const { columns, setting, scripts, colColumns, scriptsColumns, activeKey, loading } = this.state
    const { columns, setting, scripts, colColumns, scriptsColumns, activeKey, loading, searches } = this.state
    return (
      <div id="model-verify-card-box-tab">
@@ -510,7 +513,7 @@
          <TabPane tab="自定义脚本" key="scripts">
            <CustomScriptsForm
              setting={setting}
              searches={config.search}
              searches={searches}
              initsql={this.state.initsql}
              dict={this.props.dict}
              customScripts={scripts}
src/menu/stylecontroller/index.jsx
@@ -260,11 +260,7 @@
    this.updateStyle({height: _val})
  }
  changeBorderRadius = (val) => {
    this.updateStyle({borderRadius: val})
  }
  changeMarginOrPadding = (val, type) => {
  changeNormalStyle = (val, type) => {
    this.updateStyle({[type]: val})
  }
@@ -502,7 +498,7 @@
                    label={<Icon title="圆角" type="radius-setting" />}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <StyleInput defaultValue={card.borderRadius || ''} options={['px', '%']} onChange={this.changeBorderRadius}/>
                    <StyleInput defaultValue={card.borderRadius || ''} options={['px', '%']} onChange={(val) => this.changeNormalStyle(val, 'borderRadius')}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
@@ -512,7 +508,7 @@
                    colon={false}
                    label={<Icon title="上边距" type="arrow-up"/>}
                  >
                    <StyleInput defaultValue={card.marginTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'marginTop')}/>
                    <StyleInput defaultValue={card.marginTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginTop')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -520,7 +516,7 @@
                    colon={false}
                    label={<Icon title="下边距" type="arrow-down"/>}
                  >
                    <StyleInput defaultValue={card.marginBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'marginBottom')}/>
                    <StyleInput defaultValue={card.marginBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginBottom')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -528,7 +524,7 @@
                    colon={false}
                    label={<Icon title="左边距" type="arrow-left"/>}
                  >
                    <StyleInput defaultValue={card.marginLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'marginLeft')}/>
                    <StyleInput defaultValue={card.marginLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginLeft')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -536,7 +532,7 @@
                    colon={false}
                    label={<Icon title="右边距" type="arrow-right"/>}
                  >
                    <StyleInput defaultValue={card.marginRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'marginRight')}/>
                    <StyleInput defaultValue={card.marginRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'marginRight')}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
@@ -546,7 +542,7 @@
                    colon={false}
                    label={<Icon title="上边距" type="arrow-up"/>}
                  >
                    <StyleInput defaultValue={card.paddingTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'paddingTop')}/>
                    <StyleInput defaultValue={card.paddingTop} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingTop')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -554,7 +550,7 @@
                    colon={false}
                    label={<Icon title="下边距" type="arrow-down"/>}
                  >
                    <StyleInput defaultValue={card.paddingBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'paddingBottom')}/>
                    <StyleInput defaultValue={card.paddingBottom} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingBottom')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -562,7 +558,7 @@
                    colon={false}
                    label={<Icon title="左边距" type="arrow-left"/>}
                  >
                    <StyleInput defaultValue={card.paddingLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'paddingLeft')}/>
                    <StyleInput defaultValue={card.paddingLeft} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingLeft')}/>
                  </Form.Item>
                </Col>
                <Col span={12}>
@@ -570,7 +566,22 @@
                    colon={false}
                    label={<Icon title="右边距" type="arrow-right"/>}
                  >
                    <StyleInput defaultValue={card.paddingRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeMarginOrPadding(val, 'paddingRight')}/>
                    <StyleInput defaultValue={card.paddingRight} options={['px', 'vh', 'vw']} onChange={(val) => this.changeNormalStyle(val, 'paddingRight')}/>
                  </Form.Item>
                </Col>
              </Panel> : null}
              {options.includes('float') ? <Panel header="浮动" key="float">
                <Col span={24}>
                  <Form.Item
                    colon={false}
                    label={<Icon title="浮动" type="swap" />}
                    labelCol={{xs: { span: 24 }, sm: { span: 4 }}} wrapperCol={ {xs: { span: 24 }, sm: { span: 20 }} }
                  >
                    <Radio.Group defaultValue={card.float || 'left'} onChange={(e) => this.changeNormalStyle(e.target.value, 'float')}>
                      <Radio value="left">左浮动</Radio>
                      <Radio value="right">右浮动</Radio>
                      <Radio value="none">不浮动</Radio>
                    </Radio.Group>
                  </Form.Item>
                </Col>
              </Panel> : null}
src/tabviews/custom/components/card/cardItem/index.jsx
New file
@@ -0,0 +1,59 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Col } from 'antd'
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('../cardcellList'))
class CardBoxComponent extends Component {
  static propTpyes = {
    cards: PropTypes.object,         // 卡片行配置信息
    card: PropTypes.object,          // 卡片配置信息
    data: PropTypes.object
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    card: null,            // 卡片信息,包括正反面
  }
  /**
   * @description 搜索条件初始化
   */
  UNSAFE_componentWillMount () {
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  render() {
    const { card } = this.props
    return (
      <Col span={card.setting.width || 6}>
        <div className={'card-item'} style={card.style}>
          <CardCellComponent elements={card.elements} updateElement={this.updateCard}/>
        </div>
      </Col>
    )
  }
}
export default CardBoxComponent
src/tabviews/custom/components/card/cardItem/index.scss
src/tabviews/custom/components/card/cardcellList/index.jsx
New file
@@ -0,0 +1,125 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Button, Icon } from 'antd'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
class CardCellComponent extends Component {
  static propTpyes = {
    cards: PropTypes.object,         // 菜单配置信息
    cardCell: PropTypes.object,
    elements: PropTypes.array,       // 元素集
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS,
    card: null,          // 编辑中元素
    elements: null,      // 按钮组
  }
  /**
   * @description 搜索条件初始化
   */
  UNSAFE_componentWillMount () {
    const { elements } = this.props
    this.setState({
      elements: fromJS(elements).toJS()
    })
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  /**
   * @description 组件销毁,清除state更新,清除快捷键设置
   */
  componentWillUnmount () {
    this.setState = () => {
      return
    }
  }
  getContent = (card) => {
    if (card.eleType === 'text' || card.eleType === 'number') {
      let val = `${card.prefix || ''}${card.value || ''}${card.postfix || ''}`
      return <span key={card.uuid}>{val}</span>
    } else if (card.eleType === 'icon') {
      return (<Icon key={card.uuid} type={card.icon}/>)
    } else if (card.eleType === 'slider') {
      return (
        <div className="ant-mk-slider" key={card.uuid}>
          <div className="ant-mk-slider-rail"></div>
          <div className="ant-mk-slider-track" style={{width: '30%', backgroundColor: card.color}}></div>
          <div className="ant-mk-slider-handle" style={{left: '30%', borderColor: card.color}}></div>
        </div>
      )
    } else if (card.eleType === 'picture') {
      let _imagestyle = {}
      if (card.url) {
        _imagestyle = {backgroundImage: `url('${card.url}')`}
      } else {
        _imagestyle = {backgroundImage: `url('')`}
      }
      if (card.radius === 'true') {
        _imagestyle.borderRadius = '50%'
      }
      if (card.lenWidRadio === '16:9') {
        _imagestyle.paddingTop = '56.25%'
      } else if (card.lenWidRadio === '3:2') {
        _imagestyle.paddingTop = '66.67%'
      } else if (card.lenWidRadio === '4:3') {
        _imagestyle.paddingTop = '75%'
      } else {
        _imagestyle.paddingTop = '100%'
      }
      return (
        <div className="ant-mk-picture" key={card.uuid} style={_imagestyle}></div>
      )
    } else if (card.eleType === 'splitline') {
      return (
        <div className="ant-mk-splitline" key={card.uuid} style={{backgroundColor: card.color}}></div>
      )
    } else if (card.eleType === 'button') {
      if (card.show === 'icon') {
        return (card.icon ? <Button key={card.uuid} className={'mk-link mk-' + card.class} style={card.btnstyle} type="link"><Icon type={card.icon}/></Button> : null)
      } else if (card.show === 'link') {
        return (
          <Button key={card.uuid} className={'mk-link mk-' + card.class} style={card.btnstyle} type="link">{card.label}{card.icon ? <Icon type={card.icon}/> : null}</Button>
        )
      } else {
        return (
          <Button
            key={card.uuid}
            className={'mk-btn mk-' + card.class}
            icon={card.icon}
            style={card.btnstyle}
          >
            {card.label}
          </Button>
        )
      }
    }
  }
  render() {
    const { elements } = this.state
    return (
      <div className="model-menu-card-cell-list">
        {elements.map(item => this.getContent(item))}
      </div>
    )
  }
}
export default CardCellComponent
src/tabviews/custom/components/card/cardcellList/index.scss
New file
@@ -0,0 +1,40 @@
.model-menu-card-cell-list {
  position: relative;
  .ant-form-item-label {
    .anticon-question-circle {
      color: #c49f47;
      position: absolute;
      left: 5px;
      top: 5px;
    }
  }
  .card-detail-row > .anticon-plus {
    color: #26C281;
    font-size: 16px;
    padding: 5px;
    cursor: pointer;
  }
  .card-cell {
    border-style: solid;
    border-width: 0;
  }
  .card-button-cell {
    float: left;
    button {
      background-size: cover;
      background-position: center center;
      span {
        font-style: inherit;
        text-decoration: inherit;
      }
    }
  }
  .card-cell:hover {
    box-shadow: 0px 0px 1px #d8d8d8;
  }
  .ant-slider {
    margin: 0px;
  }
}
src/tabviews/custom/components/card/data-card/asyncButtonComponent.jsx
New file
@@ -0,0 +1,34 @@
import React, {Component} from 'react'
import { Button } from 'antd'
/**
 * @description 异步加载模块
 * @param {*} importComponent
 */
export default function asyncComponent(importComponent) {
  return class extends Component {
    constructor(props) {
      super(props)
      this.state = {
        component: null
      }
    }
    async componentDidMount() {
      const {default: component} = await importComponent()
      this.setState({component})
    }
    // <Button className="loading-skeleton" disabled={true}></Button> // 骨架按钮
    render() {
      const C = this.state.component
      const btn = this.props.btn || {}
      return C ?
        <C {...this.props} /> :
        <Button icon={btn.OpenType === 'excelOut' ? 'download' : 'upload'} disabled={true} title={btn.label} style={{border: 0, background: 'transparent'}}></Button>
    }
  }
}
src/tabviews/custom/components/card/data-card/index.jsx
New file
@@ -0,0 +1,118 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import { is, fromJS } from 'immutable'
import { Spin, Empty, notification } from 'antd'
import asyncComponent from '@/utils/asyncComponent'
import Api from '@/api'
// import Utils from '@/utils/utils.js'
import UtilsDM from '@/utils/utils-datamanage.js'
import zhCN from '@/locales/zh-CN/main.js'
import enUS from '@/locales/en-US/main.js'
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,         // 菜单类型
    dataManager: PropTypes.any,      // 数据权限
  }
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 字典
    config: null,              // 图表配置信息
    empty: false,
    loading: false,            // 数据加载状态
    data: null                 // 数据
  }
  UNSAFE_componentWillMount () {
    let _config = fromJS(this.props.config).toJS()
    console.log(_config)
    this.setState({
      config: _config,
      arr_field: _config.columns.map(col => col.field).join(','),
    }, () => {
      this.loadData()
    })
  }
  /**
   * @description 校验图表的按钮组,如果为统计图表,计算图表字段
   */
  componentDidMount () {
  }
  /**
   * @description 图表数据更新,刷新内容
   */
  UNSAFE_componentWillReceiveProps (nextProps) {
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
  }
  async loadData () {
    const { mainSearch, BID, menuType, dataManager } = this.props
    const { config, arr_field } = this.state
    let searches = []
    if (mainSearch && mainSearch.length > 0) { // 主表搜索条件
      searches = [...mainSearch, ...searches]
    }
    this.setState({
      loading: true
    })
    let _orderBy = config.setting.order || ''
    let param = UtilsDM.getQueryDataParams(config.setting, arr_field, searches, _orderBy, 1, config.setting.pageSize, BID, menuType, dataManager)
    let result = await Api.genericInterface(param)
    if (result.status) {
      this.setState({
        data: result.data,
        loading: false
      })
    } else {
      this.setState({
        loading: false
      })
      notification.error({
        top: 92,
        message: result.message,
        duration: 10
      })
    }
  }
  render() {
    const { config, empty, loading, data } = this.state
    return (
      <div className="custom-card-box" style={config.style}>
        {loading ?
          <div className="loading-mask">
            <div className="ant-spin-blur"></div>
            <Spin />
          </div> : null
        }
        {data && data.length > 0 ? data.map((item, index) => (
          <CardItem key={index} card={config.subcards[0]} cards={config} data={item} />
        )) : null}
        {empty ? <Empty description={false}/> : null}
      </div>
    )
  }
}
export default DataCard
src/tabviews/custom/components/card/data-card/index.scss
New file
@@ -0,0 +1,38 @@
.custom-card-box {
  background: #ffffff;
  min-height: 100px;
  .card-item {
    border-style: solid;
  }
  .ant-empty {
    position: absolute;
    top: calc(50% - 34px);
    left: calc(50% - 92px);
    .ant-empty-image {
      height: 60px;
    }
  }
  .loading-mask {
    position: absolute;
    left: 20px;
    top: 0;
    right: 20px;
    bottom: 30px;
    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;
    }
  }
}
src/tabviews/custom/components/chart/antv-bar-line/index.jsx
@@ -29,7 +29,7 @@
  state = {
    dict: localStorage.getItem('lang') !== 'en-US' ? zhCN : enUS, // 字典
    config: true,              // 图表配置信息
    config: null,              // 图表配置信息
    empty: true,               // 图表数据为空
    loading: false,            // 数据加载状态
    chartId: Utils.getuuid(),  // 图表Id
@@ -1026,7 +1026,7 @@
    const { showHeader, config, loading, title, plot, empty, chartFields, selectFields } = this.state
    return (
      <div className="custom-line-chart-plot-box">
      <div className="custom-line-chart-plot-box" style={config.style}>
        {loading ?
          <div className="loading-mask">
            <div className="ant-spin-blur"></div>
src/tabviews/custom/index.jsx
@@ -19,6 +19,7 @@
// 通用组件
const AntvBarAndLine = asyncSpinComponent(() => import('./components/chart/antv-bar-line'))
const AntvTabs = asyncSpinComponent(() => import('./components/tabs/antv-tabs'))
const DataCard = asyncSpinComponent(() => import('./components/card/data-card'))
class NormalTable extends Component {
  static propTpyes = {
@@ -450,6 +451,16 @@
            <AntvTabs config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
          </Col>
        )
      } else if (item.type === 'card') {
        if (item.subtype === 'datacard') {
          return (
            <Col span={item.width} key={item.uuid}>
              <DataCard config={item} BID={BID} mainSearch={mainSearch} menuType={menuType} dataManager={dataManager} />
            </Col>
          )
        } else {
          return null
        }
      } else {
        return null
      }
@@ -463,7 +474,7 @@
    return (
      <div className="custom-page-wrap" id={this.state.ContainerId} style={config ? config.style : null}>
        {loadingview && <Spin size="large" />}
        <Row gutter={8}>{this.getComponents()}</Row>
        <Row>{this.getComponents()}</Row>
        {options.sysType !== 'cloud' ? <Button
          icon="copy"
          shape="circle"
src/tabviews/custom/index.scss
@@ -12,10 +12,6 @@
    padding-top: 30px;
  }
  .ant-col {
    padding-bottom: 16px;
  }
  .ant-modal-mask {
    position: absolute;
  }
src/utils/option.js
@@ -329,6 +329,36 @@
  text: '白底紫框'
}]
// 按钮颜色集
export const btnCustomClasses = [{
  value: 'primary',
  text: '蓝色'
}, {
  value: 'yellow',
  text: '黄色'
}, {
  value: 'orange',
  text: '橙色'
}, {
  value: 'danger',
  text: '红色'
}, {
  value: 'green',
  text: '绿色'
}, {
  value: 'dgreen',
  text: '深绿色'
}, {
  value: 'purple',
  text: '紫色'
}, {
  value: 'cyan',
  text: '青色'
}, {
  value: 'gray',
  text: '灰色'
}]
export const calendarColors = [
  {name: 'red', value: '#d0021b'},
  {name: 'orange', value: '#f5a623'},