// 核心库 import React, { Component } from 'react' import { connect } from 'dva' import PropTypes from 'prop-types' // 组件库 import ReactEcharts from "echarts-for-react" import { Popover, Table, Icon, Spin, Input, message } from 'antd' import { ExportToExcel, IFComponent } from '@woowalker/feui' // 工具库 import { isEqual } from 'lodash' import { uuid, initFilter } from '../../utils/common' // 样式 import classNames from 'classnames' import styles from './chart.css' class TableChart extends Component { constructor (props) { super(props) this.state = { data: [], columns: [], toggleChart: false, // 用于列表导出的 id tableId: uuid(), // 设定的参考目标值 targetVal: undefined } this.refOfChart = null } componentDidMount () { const { option, type, chartId } = this.props if (option) { this.getTableData(option, type) chartId && this.getTargetVal() } } UNSAFE_componentWillReceiveProps (nextProps) { if (!isEqual(this.props.option, nextProps.option)) { this.getTableData(nextProps.option, nextProps.type) } } /** 生成 table 数据 */ getTableData = (option, type) => { const data = [] const columns = [] const { radar, series = [], xAxis = [], yAxis = [] } = option switch (type) { // 饼图 case 2: if (series[0] && Array.isArray(series[0].data) && series[0].data.length) { // 从 series 取 columns let total = 0 series[0].data.forEach(({ name, value }) => { total += value columns.push({ title: name, dataIndex: name, key: name }) }) // 从 series 取 data const tempTableData = {} series[0].data.forEach(({ name, value }) => { tempTableData[name] = `${value}(${total ? (value / total * 100).toFixed(2) : 0}%)` }) data.push(tempTableData) } break // 雷达图 case 3: if (radar[0] && Array.isArray(radar[0].indicator) && radar[0].indicator.length) { columns.push({ title: '类型', dataIndex: 'name', key: 'name' }) // 从 radar 取 columns radar[0].indicator.forEach(item => columns.push({ title: `${item.text}(${item.max})`, dataIndex: item.text, key: item.text })) // 从 series 取 data series.forEach(serie => { const tempTableData = {} columns.forEach((item, index) => { const { name, data: serieData } = serie tempTableData[item.key] = item.title === '类型' ? name : serieData[0].value[index - 1] }) data.push(tempTableData) }) } break // 折线、柱状图 default: if (xAxis[0] && Array.isArray(xAxis[0].data) && xAxis[0].data.length) { columns.push({ title: '类型', dataIndex: 'name', key: 'name' }) // 从 xAxis 取 columns xAxis[0].data.forEach(item => columns.push({ title: item, dataIndex: item, key: item })) // 从 series 取 data series.forEach(serie => { const tempTableData = {} columns.forEach((item, index) => { const { name, data: serieData, yAxisIndex } = serie const yName = (yAxis[yAxisIndex || 0] || {}).name tempTableData[item.key] = item.title === '类型' ? `${name}${yName ? '(' + yName + ')' : ''}` : (serieData[index - 1]?.TooltipValue || serieData[index - 1]?.value) }) data.push(tempTableData) }) } } this.setState({ data, columns }) } /** 获取 chartId 对应的目标值 */ getTargetVal = () => { const { chartId, login, dispatch } = this.props const json = initFilter(login.OrgId, chartId) dispatch({ type: 'app/getRedisValue', payload: json }).then(res => { this.setState({ targetVal: isNaN(res) ? res : Number(res) }) }) } /** 设置 chartId 对应的目标值 */ setTargetVal = (value) => { const { chartId, login, dispatch } = this.props const json = initFilter(login.OrgId, chartId) json.Parameter1 = value dispatch({ type: 'app/setRedisValue', payload: json }).then(res => { if (res) { this.setState({ targetVal: isNaN(value) ? value : Number(value) }) message.success('操作成功') } }) } /** 处理目标值 targetVal 的修改 */ handleTVChange = (evt) => { const { value } = evt.target const targetVal = value === '' ? '' : isNaN(value) ? value : Number(value) this.setState({ targetVal }) } getChartOption = (option) => { const { targetVal } = this.state if (Array.isArray(option.series) && option.series.length && targetVal) { if (Array.isArray(option.yAxis) && option.yAxis.length) { // 标记线默认对应的Y轴就是第一条Y轴,所以这里默认取第一条Y轴进行设置 const { max, min } = option.yAxis[0] let maxSet = false let minSet = false // 监测对应 max 值是否小于 targetVal 值 if (max) { maxSet = max < targetVal } else { // 取对应默认第一条Y轴的数据,取其最大值 const targetSeries = option.series.filter(item => item.yAxisIndex === 0) const maxData = Math.max.apply(null, targetSeries.map(item => Math.max.apply(null, item.data))) maxSet = maxData < targetVal } // 监测对应 min 值是否大于 targetVal 值 minSet = min > targetVal // 设置 targetVal 对应的 max 和 min 值 maxSet && (option.yAxis[0].max = targetVal) minSet && (option.yAxis[0].min = targetVal) } return { ...option, series: [ { name: '标记线', type: 'line', markLine: { label: { position: 'insideEndTop', formatter: '{b}: {c}' }, lineStyle: { color: '#096dd9' }, data: [ { name: '目标值', yAxis: targetVal, lineStyle: { width: 2 } } ] } } ].concat(option.series) } } return option } render () { const { chartId, option, onEvents, loading, style } = this.props const { targetVal, data, columns, toggleChart } = this.state const loadingGet = this.props.dvaLoading.effects['app/getRedisValue'] const loadingSet = this.props.dvaLoading.effects['app/setRedisValue'] return (
{/** 额外需要插入的工具集 */} {this.props.children} {/** 目标值设定 */} } trigger='click' > {/** 图形列表切换按钮 */} { this.setState({ toggleChart: !toggleChart }) }}> {`切换${toggleChart ? '图表' : '列表'}`} {/** 导出按钮 */} } />
this.refOfChart = ref?.getEchartsInstance()} notMerge lazyUpdate option={this.getChartOption(option)} onEvents={onEvents} className={classNames(styles.chart, { [styles.show]: !toggleChart, [styles.hide]: toggleChart })} style={{ width: '100%', height: '100%', ...style }} /> ) } } TableChart.propTypes = { option: PropTypes.object, type: PropTypes.string, chartId: PropTypes.string, onEvents: PropTypes.object, style: PropTypes.object } export default connect(({ login, loading }) => ({ login, dvaLoading: loading }))(TableChart)