272 lines
9.1 KiB
JavaScript
272 lines
9.1 KiB
JavaScript
// 核心库
|
||
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 (
|
||
<Spin size='large' spinning={!!loading} wrapperClassName={styles.chartTable}>
|
||
<div className={styles.chartTableSwap}>
|
||
{/** 额外需要插入的工具集 */}
|
||
{this.props.children}
|
||
{/** 目标值设定 */}
|
||
<IFComponent IF={!toggleChart && !!chartId}>
|
||
<Popover
|
||
content={
|
||
<Input.Search
|
||
autoFocus
|
||
allowClear
|
||
value={targetVal}
|
||
loading={loadingGet || loadingSet}
|
||
placeholder='请输入设定目标值'
|
||
enterButton='保存'
|
||
onChange={this.handleTVChange}
|
||
onSearch={this.setTargetVal}
|
||
/>
|
||
}
|
||
trigger='click'
|
||
>
|
||
<Icon type='setting' title='目标值设定' style={{ marginRight: 10 }} />
|
||
</Popover>
|
||
</IFComponent>
|
||
{/** 图形列表切换按钮 */}
|
||
<span onClick={() => { this.setState({ toggleChart: !toggleChart }) }}>
|
||
<Icon type='swap' />
|
||
<span>{`切换${toggleChart ? '图表' : '列表'}`}</span>
|
||
</span>
|
||
{/** 导出按钮 */}
|
||
<IFComponent IF={toggleChart}>
|
||
<ExportToExcel
|
||
fileName='列表数据'
|
||
tableId={this.state.tableId}
|
||
render={({ onExport }) => <Icon type='download' title='导出' onClick={onExport} style={{ paddingLeft: 10 }} />}
|
||
/>
|
||
</IFComponent>
|
||
</div>
|
||
<ReactEcharts
|
||
ref={ref => 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 }}
|
||
/>
|
||
<Table
|
||
id={this.state.tableId}
|
||
bordered
|
||
rowKey='ID'
|
||
size='small'
|
||
dataSource={data}
|
||
columns={columns}
|
||
scroll={{ x: true }}
|
||
pagination={false}
|
||
className={classNames(styles.table, { [styles.show]: toggleChart, [styles.hide]: !toggleChart })}
|
||
/>
|
||
</Spin>
|
||
)
|
||
}
|
||
}
|
||
|
||
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)
|