king
2020-12-29 9f3a0655391c42dc7fb9a3cfa6d8fc4ca935bd9d
src/menu/components/chart/antv-bar/index.jsx
@@ -1,27 +1,34 @@
import React, {Component} from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { is, fromJS } from 'immutable'
import { Icon, Popover, notification } from 'antd'
import { Chart } from '@antv/g2'
import DataSet from '@antv/data-set'
import MKEmitter from '@/utils/events.js'
import asyncComponent from '@/utils/asyncComponent'
import asyncIconComponent from '@/utils/asyncIconComponent'
import Utils from '@/utils/utils.js'
import { chartColors } from '@/utils/option.js'
import zhCN from '@/locales/zh-CN/model.js'
import enUS from '@/locales/en-US/model.js'
import './index.scss'
const SettingComponent = asyncComponent(() => import('@/menu/datasource'))
const SearchComponent = asyncComponent(() => import('@/menu/searchcomponent'))
const ActionComponent = asyncComponent(() => import('@/menu/actioncomponent'))
const ChartCompileForm = asyncComponent(() => import('./chartcompile'))
const SettingComponent = asyncIconComponent(() => import('@/menu/datasource'))
const ChartCompileForm = asyncIconComponent(() => import('./chartcompile'))
const LogComponent = asyncIconComponent(() => import('@/menu/components/share/logcomponent'))
const CopyComponent = asyncIconComponent(() => import('@/menu/components/share/copycomponent'))
const PasteComponent = asyncIconComponent(() => import('@/menu/components/share/pastecomponent'))
const NormalHeader = asyncComponent(() => import('@/menu/components/share/normalheader'))
const ActionComponent = asyncComponent(() => import('@/menu/components/share/actioncomponent'))
class antvBarLineChart extends Component {
  static propTpyes = {
    menu: PropTypes.object,
    card: PropTypes.object,
    updateConfig: PropTypes.func,
    deletecomponent: PropTypes.func,
  }
  state = {
@@ -31,14 +38,18 @@
  }
  UNSAFE_componentWillMount () {
    const { card, menu } = this.props
    const { card } = this.props
    if (card.isNew) {
      let _plot = {
        chartType: card.type, // 图表类型
        enabled: 'false',     // 是否使用自定义设置
        datatype: 'query',    // 数据类型查询或统计
        customs: []
        customs: [],
        width: 24,
        height: 400,
        barSize: 35,
        name: card.name
      }
      if (card.subtype === 'bar') {
@@ -53,17 +64,6 @@
        _plot.shape = 'hv'
      }
      let dataName = ''
      if (card.floor === 1) {
        while (!dataName) {
          let _dataName = Utils.getdataName()
          if (menu.components.filter(com => com.dataName === _dataName).length === 0) {
            dataName = _dataName
          }
        }
      }
      let _card = {
        uuid: card.uuid,
        type: card.type,
@@ -73,14 +73,22 @@
        format: 'array',   // 组件属性 - 数据格式
        pageable: false,   // 组件属性 - 是否可分页
        switchable: false, // 组件属性 - 数据是否可切换
        dataName: dataName,
        dataName: card.dataName || '',
        width: _plot.width,
        name: _plot.name,
        subtype: card.subtype,
        setting: {span: card.floor === 1 ? 12 : 24, height: 400, interType: 'system', name: card.name},
        setting: { interType: 'system' },
        style: {
          borderWidth: '1px', borderColor: 'rgb(217, 217, 217)',
          marginLeft: '8px', marginRight: '8px', marginTop: '8px', marginBottom: '8px'
        },
        headerStyle: { fontSize: '16px', borderBottomWidth: '1px', borderBottomColor: '#e8e8e8' },
        columns: [],
        scripts: [],
        search: [],
        action: [],
        plot: _plot
        plot: _plot,
        btnlog: [],
      }
      this.setState({
        card: _card
@@ -96,10 +104,11 @@
  componentDidMount () {
    this.viewrender()
    MKEmitter.addListener('tabsChange', this.handleTabsChange)
    MKEmitter.addListener('submitStyle', this.getStyle)
  }
  shouldComponentUpdate (nextProps, nextState) {
    return !is(fromJS(this.state), fromJS(nextState))
    return !is(fromJS(this.state), fromJS(nextState)) || (!this.props.menu && nextProps.menu)
  }
  /**
@@ -110,6 +119,7 @@
      return
    }
    MKEmitter.removeListener('tabsChange', this.handleTabsChange)
    MKEmitter.removeListener('submitStyle', this.getStyle)
  }
  handleTabsChange = (parentId) => {
@@ -159,17 +169,13 @@
    }
  }
  /**
   * @description 折线图
   */
  linerender = () => {
    const { card } = this.state
    let plot = {...card.plot, height: card.setting.height - 70}
    let transfield = {}
    card.columns.forEach(col => {
      if (col.field) {
        transfield[col.field] = col.label
      }
    })
    let plot = {...card.plot, height: card.plot.height - 80} // 去除title所占空间
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || ['y']
@@ -178,6 +184,12 @@
    if (plot.enabled !== 'true') {
      const ds = new DataSet()
      const dv = ds.createView().source(data)
      let transfield = {}
      card.columns.forEach(col => {
        if (col.field) {
          transfield[col.field] = col.label
        }
      })
      dv.transform({
        type: 'fold',
@@ -203,6 +215,9 @@
      })
  
      chart.data(dv.rows)
      chart.axis(X_axis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
      chart.axis('value', { grid: { style: { fill: color } }, label: { style: { fill: color } } })
  
      if (plot.coordinate !== 'polar') {
        chart.scale(X_axis, {
@@ -210,14 +225,16 @@
        })
      }
      chart.scale('value', {
        nice: true
        nice: true,
        range: [0, 0.93]
      })
  
      if (!plot.legend || plot.legend === 'hidden') {
        chart.legend(false)
      } else {
        chart.legend({
          position: plot.legend
          position: plot.legend,
          itemName: { style: { fill: color } }
        })
      }
  
@@ -239,15 +256,57 @@
          radius: 0.8
        })
      }
      let colors = new Map()
      let colorIndex = 0
      if (plot.colors && plot.colors.length > 0) {
        plot.colors.forEach(item => {
          if (!colors.has(transfield[item.type])) {
            colors.set(transfield[item.type], item.color)
          }
        })
      }
  
      let _chart = chart
        .line()
        .position(`${X_axis}*value`)
        .color('key')
        .shape(plot.shape || 'smooth')
        .tooltip(`${X_axis}*value`, (name, value) => {
          if (plot.show === 'percent') {
            value = value + '%'
          }
          return {
            name: name,
            value: value
          }
        })
  
      if (plot.colors && plot.colors.length > 0) {
        let limit = chartColors.length
        _chart.color('key', (key) => {
          if (colors.get(key)) {
            return colors.get(key)
          } else {
            colors.set(key, chartColors[colorIndex % limit])
            colorIndex++
          }
        })
      } else {
        _chart.color('key')
      }
      if (plot.label === 'true') {
        _chart.label('value')
        _chart.label('value', (value) => {
          if (plot.show === 'percent') {
            value = value + '%'
          }
          return {
            content: value,
            style: {
              fill: color
            }
          }
        })
      }
      if (plot.point === 'true') {
@@ -260,34 +319,75 @@
      }
      chart.render()
    } else {
      this.customrender(data, transfield)
      this.customrender(data)
    }
  }
  customrender = (data, transfield) => {
    const { plot } = this.props
    let barfields = []
  /**
   * @description 自定义图
   */
  customrender = (data) => {
    let card = fromJS(this.state.card).toJS()
    let plot = {...card.plot, height: card.plot.height - 80} // 去除title所占空间
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let fields = []
    let legends = []
    let transfield = {}
    card.columns.forEach(col => {
      if (col.field) {
        transfield[col.field] = col.label
      }
    })
    let colors = new Map()
    let colorIndex = 0
    let limit = chartColors.length
    if (plot.colors && plot.colors.length > 0) {
      plot.colors.forEach(item => {
        if (!colors.has(item.type)) {
          colors.set(item.type, item.color)
        }
      })
    }
    let axisIndex = 0
    let hasBar = false
    plot.customs.forEach(item => {
      item.name = transfield[item.field] || item.field
      if (item.axis === 'left') {
        item.index = 0
      } else if (item.axis === 'right') {
        item.index = 1
      item.name = transfield[item.type] || item.type
      item.chartType = item.shape ? (item.shape[0] || 'bar') : 'bar'
      item.shape = item.shape ? (item.shape[1] || '') : ''
      if (colors.get(item.type)) {
        item.color = colors.get(item.type)
      } else {
        item.index = 2
        item.color = chartColors[colorIndex % limit]
        colorIndex++
      }
      if (item.chartType === 'bar') {
        barfields.push(item.field)
        fields.unshift(item)
      if (item.chartType === 'bar' && !hasBar) {
        hasBar = true
      } else if (item.chartType === 'bar') {
        item.chartType = 'line'
        item.shape = 'smooth'
      }
      if (item.axis === 'true' && axisIndex < 2) {
        if (axisIndex === 0) {
          item.axis = { grid: {style: { fill: color }}, title: { style: { fill: color } }, label: {style: { fill: color }} }
          fields.unshift(item)
        } else {
          item.axis = { grid: null, title: {style: { fill: color }}, label: {style: { fill: color }} }
          fields.splice(1, 0, item)
        }
        axisIndex++
      } else {
        item.axis = { grid: null, title: null, label: null }
        fields.push(item)
      }
      legends.push({
        value: item.name,
        name: item.name,
@@ -295,29 +395,29 @@
      })
    })
    fields.sort((a, b) => a.index - b.index)
    const ds = new DataSet()
    const dv = ds.createView().source(data)
    dv.transform({
      type: 'map',
      callback(row) {
        fields.forEach(line => {
          row[line.name] = row[line.field]
          row[line.name] = row[line.type]
        })
        return row
      }
    })
    const chart = new Chart({
      container: plot.uuid,
      container: card.uuid,
      autoFit: true,
      height: plot.height || 400
    })
    chart.data(dv.rows)
    if (plot.coordinate !== 'polar' && barfields.length === 0) {
    chart.axis(plot.Xaxis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
    if (!hasBar) {
      chart.scale(plot.Xaxis, {
        range: [0, 1]
      })
@@ -330,6 +430,7 @@
        custom: true,
        position: plot.legend,
        items: legends,
        itemName: { style: { fill: color } }
      })
    }
@@ -337,18 +438,7 @@
      chart.tooltip(false)
    } else {
      chart.tooltip({
        shared: true
      })
    }
    if (plot.transpose === 'true') {
      chart.coordinate().transpose()
    }
    if (plot.coordinate === 'polar') {
      chart.coordinate('polar', {
        innerRadius: 0.1,
        radius: 0.8
        shared: true,
      })
    }
@@ -356,36 +446,45 @@
      nice: true
    })
    fields.forEach((item, i) => {
      if (i === 0) {
        chart.axis(item.name, {
          grid: {},
          title: {},
          label: {}
        })
      } else if (i === 1 && item.axis !== 'unset') {
        chart.axis(item.name, {
          grid: null,
          title: {},
          label: {}
        })
      } else {
        chart.axis(item.name, {
          grid: null,
          title: null,
          label: null
        })
      }
    fields.forEach(item => {
      chart.axis(item.name, item.axis)
      
      chart.scale(item.name, {
        nice: true,
        range: [0, 0.93]
      })
      if (item.chartType === 'bar') {
        let _chart = chart
          .interval()
          .position(`${plot.Xaxis}*${item.name}`)
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${plot.Xaxis}*${item.name}`, (name, value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              name: name,
              value: value
            }
          })
        if (plot.barSize) {
          _chart.size(plot.barSize || 35)
        }
        if (item.label === 'true') {
          _chart.label(item.name)
          _chart.label(item.name, (value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              content: value,
              style: {
                fill: color
              }
            }
          })
        }
      } else if (item.chartType === 'line') {
        let _chart = chart
@@ -393,9 +492,28 @@
          .position(`${plot.Xaxis}*${item.name}`)
          .color(item.color)
          .shape(item.shape)
          .tooltip(`${plot.Xaxis}*${item.name}`, (name, value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              name: name,
              value: value
            }
          })
        if (item.label === 'true') {
          _chart.label(item.name)
          _chart.label(item.name, (value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              content: value,
              style: {
                fill: color
              }
            }
          })
        }
        if (plot.point === 'true') {
@@ -412,17 +530,13 @@
    chart.render()
  }
  /**
   * @description 柱形图
   */
  barrender = () => {
    const { card } = this.state
    let plot = {...card.plot, height: card.setting.height - 70}
    let transfield = {}
    card.columns.forEach(col => {
      if (col.field) {
        transfield[col.field] = col.label
      }
    })
    let plot = {...card.plot, height: card.plot.height - 80}
    let color = plot.color || 'rgba(0, 0, 0, 0.85)'
    let X_axis = plot.Xaxis || 'x'
    let Y_axis = plot.Yaxis || ['y']
@@ -431,6 +545,13 @@
    if (plot.enabled !== 'true') {
      const ds = new DataSet()
      const dv = ds.createView().source(data)
      let transfield = {}
      card.columns.forEach(col => {
        if (col.field) {
          transfield[col.field] = col.label
        }
      })
  
      dv.transform({
        type: 'fold',
@@ -448,7 +569,7 @@
          },
        })
      }
      const chart = new Chart({
        container: card.uuid,
        autoFit: true,
@@ -456,16 +577,21 @@
      })
  
      chart.data(dv.rows)
      chart.axis(X_axis, { label: { style: { fill: color } }, line: { style: { fill: color } } })
      chart.axis('value', { grid: { style: { fill: color } }, label: { style: { fill: color } } })
  
      chart.scale('value', {
        nice: true
        nice: true,
        range: [0, 0.93]
      })
  
      if (!plot.legend || plot.legend === 'hidden') {
        chart.legend(false)
      } else {
        chart.legend({
          position: plot.legend
          position: plot.legend,
          itemName: { style: { fill: color } }
        })
      }
  
@@ -487,12 +613,22 @@
          radius: 0.8
        })
      }
      let colors = new Map()
      let colorIndex = 0
      if (plot.colors && plot.colors.length > 0) {
        plot.colors.forEach(item => {
          if (!colors.has(transfield[item.type])) {
            colors.set(transfield[item.type], item.color)
          }
        })
      }
  
      if (plot.adjust !== 'stack') {
        let _chart = chart
          .interval()
          .position(`${X_axis}*value`)
          .color('key')
          .adjust([
            {
              type: 'dodge',
@@ -500,39 +636,113 @@
            }
          ])
          .shape(plot.shape || 'rect')
          .tooltip(`${X_axis}*value`, (name, value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              name: name,
              value: value
            }
          })
        if (plot.colors && plot.colors.length > 0) {
          let limit = chartColors.length
          _chart.color('key', (key) => {
            if (colors.get(key)) {
              return colors.get(key)
            } else {
              colors.set(key, chartColors[colorIndex % limit])
              colorIndex++
            }
          })
        } else {
          _chart.color('key')
        }
        if (plot.label === 'true') {
          _chart.label('value')
          _chart.label('value', (value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              content: value,
              style: {
                fill: color
              }
            }
          })
        }
        if (plot.barSize || plot.correction) {
          _chart.size(plot.barSize || 35)
        }
      } else if (plot.adjust === 'stack') {
        let _chart = chart
          .interval()
          .position(`${X_axis}*value`)
          .color('key')
          .adjust('stack')
          .shape(plot.shape || 'rect')
          .tooltip(`${X_axis}*value`, (name, value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              name: name,
              value: value
            }
          })
  
        if (plot.colors && plot.colors.length > 0) {
          let limit = chartColors.length
          _chart.color('key', (key) => {
            if (colors.get(key)) {
              return colors.get(key)
            } else {
              colors.set(key, chartColors[colorIndex % limit])
              colorIndex++
            }
          })
        } else {
          _chart.color('key')
        }
        if (plot.label === 'true') {
          _chart.label('value')
          _chart.label('value', (value) => {
            if (plot.show === 'percent') {
              value = value + '%'
            }
            return {
              content: value,
              style: {
                fill: color
              }
            }
          })
        }
        if (plot.barSize || plot.correction) {
          _chart.size(plot.barSize || 35)
        }
      }
  
      chart.render()
    } else {
      this.customrender(data, transfield)
      this.customrender(data)
    }
  }
  updateComponent = (component) => {
    const card = fromJS(this.state.card).toJS()
    let refresh = false
    if (card.setting.span !== component.setting.span || card.setting.height !== component.setting.height || !is(fromJS(component.plot), fromJS(card.plot))) {
    if (!is(fromJS(component.plot), fromJS(card.plot))) {
      let _element = document.getElementById(card.uuid)
      if (_element) {
        _element.innerHTML = ''
      }
      refresh = true
    }
    component.width = component.plot.width
    component.name = component.plot.name
    
    this.setState({
      card: component
@@ -546,44 +756,142 @@
    this.props.updateConfig(component)
  }
  addSearch = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = 'label'
    newcard.initval = ''
    newcard.type = 'select'
    newcard.resourceType = '0'
    newcard.options = []
    newcard.setAll = 'false'
    newcard.orderType = 'asc'
    newcard.display = 'dropdown'
    newcard.match = '='
    // 注册事件-添加搜索
    MKEmitter.emit('addSearch', card.uuid, newcard)
  }
  addButton = () => {
    const { card } = this.state
    let newcard = {}
    newcard.uuid = Utils.getuuid()
    newcard.focus = true
    newcard.label = '导出Excel'
    newcard.sqlType = ''
    newcard.Ot = 'requiredSgl'
    newcard.OpenType = 'excelOut'
    newcard.icon = 'download'
    newcard.class = 'dgreen'
    newcard.intertype = card.setting.interType
    newcard.innerFunc = card.setting.innerFunc || ''
    newcard.sysInterface = card.setting.sysInterface || ''
    newcard.outerFunc = card.setting.outerFunc || ''
    newcard.interface = card.setting.interface || ''
    newcard.execSuccess = 'grid'
    newcard.execError = 'never'
    newcard.popClose = 'never'
    newcard.errorTime = 10
    newcard.verify = null
    newcard.show = 'icon'
    // 注册事件-添加按钮
    MKEmitter.emit('addButton', card.uuid, newcard)
  }
  changeStyle = () => {
    const { card } = this.state
    MKEmitter.emit('changeStyle', [card.uuid], ['background', 'border', 'padding', 'margin'], card.style)
  }
  getStyle = (comIds, style) => {
    const { card } = this.state
    if (comIds[0] !== card.uuid || comIds.length > 1) return
    let _card = {...card, style}
    this.setState({
      card: _card
    })
    this.props.updateConfig(_card)
  }
  handleLog = (type, logs, item) => {
    let card = fromJS(this.state.card).toJS()
    if (type === 'revert') {
      card.action = card.action ? [...card.action, item] : [item]
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '恢复成功!',
        duration: 2
      })
    } else {
      card.btnlog = logs
      this.setState({ card })
      this.props.updateConfig(card)
      notification.success({
        top: 92,
        message: '清除成功!',
        duration: 2
      })
    }
  }
  render() {
    const { card } = this.state
    const { menu } = this.props
    return (
      <div className="menu-line-chart-edit-box" style={{height: card.setting.height || 400}}>
        <SettingComponent
          config={card}
          menu={menu}
          updateConfig={this.updateComponent}
        />
        <div className="chart-header">
          <span className="chart-title">{card.setting.title || ''}</span>
          <SearchComponent
            menu={menu}
            config={card}
            sysRoles={menu.sysRoles}
            optionLibs={null}
            updatesearch={this.updateComponent}
          />
        </div>
      <div className="menu-line-chart-edit-box" style={{...card.style, height: card.plot.height || 400}}>
        <NormalHeader config={card} updateComponent={this.updateComponent}/>
        <Popover overlayClassName="mk-popover-control-wrap" mouseLeaveDelay={0.2} mouseEnterDelay={0.2} content={
          <div className="mk-popover-control">
            <Icon className="plus" title="添加搜索" onClick={this.addSearch} type="plus-circle" />
            <Icon className="plus" title="添加按钮" onClick={this.addButton} type="plus-square" />
            <ChartCompileForm config={card} dict={this.state.dict} plotchange={this.updateComponent}/>
            <CopyComponent type="line" card={card}/>
            <PasteComponent config={card} options={['action', 'search', 'form']} updateConfig={this.updateComponent} />
            <Icon className="style" title="调整样式" onClick={this.changeStyle} type="font-colors" />
            <LogComponent btnlog={card.btnlog || []} handlelog={this.handleLog} />
            <Icon className="close" title="delete" type="delete" onClick={() => this.props.deletecomponent(card.uuid)} />
            <SettingComponent config={card} updateConfig={this.updateComponent}/>
          </div>
        } trigger="hover">
          <Icon type="tool" />
        </Popover>
        <ActionComponent
          type="chart"
          menu={menu}
          config={card}
          tabs={[]}
          // setSubConfig={(_btn) => this.setSubConfig(_btn, 'button')}
          updateaction={this.updateComponent}
        />
        <div className="canvas" id={card.uuid}></div>
        <ChartCompileForm
          config={card}
          dict={this.state.dict}
          plotchange={this.updateComponent}
        />
      </div>
    )
  }
}
export default antvBarLineChart
const mapStateToProps = (state) => {
  return {
    menu: state.customMenu
  }
}
const mapDispatchToProps = () => {
  return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(antvBarLineChart)