// RiskControl.js - 风险管控页面组件
import React from 'react';
import { Table } from 'antd';
import styles from './../fullinter.less';
import echarts from 'echarts';
class RiskControl extends React.Component {
constructor(props) {
super(props);
this.echartsInstances = {
stackBarChart: null, // 堆叠柱状图
typeBarChart: null, // 风险类别柱状图
};
this.chartResizeHandlers = {};
this.isUnmounted = false;
}
waitForElement = (elementId, maxRetries = 10) => {
return new Promise((resolve) => {
let retries = 0;
const checkInterval = setInterval(() => {
const element = document.getElementById(elementId);
if (element || retries >= maxRetries) {
clearInterval(checkInterval);
resolve(!!element);
}
retries++;
}, 50);
});
};
// 堆叠柱状图: 各公司风险统计(与 trainingContent 样式一致)
renderStackBarChart = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('stackBarChart');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.stackBarChart) {
this.echartsInstances.stackBarChart.dispose();
this.echartsInstances.stackBarChart = null;
}
const chartDom = document.getElementById('stackBarChart');
if (!chartDom) return;
this.echartsInstances.stackBarChart = echarts.init(chartDom);
const { riskSubData } = this.props;
const riskList = riskSubData?.riskList || [];
if (riskList.length === 0) {
this.echartsInstances.stackBarChart.setOption({
title: {
text: '各家公司的风险统计情况',
x: 'center',
y: '25%',
textStyle: { fontSize: 16, color: '#999' },
},
graphic: {
type: 'text',
left: 'center',
top: 'middle',
style: {
text: '暂无数据',
fill: '#999',
fontSize: 14,
},
},
});
return;
}
const companyNames = riskList.map((item) => item.companyName);
const majorCounts = riskList.map((item) => item.majorCount);
const largerCounts = riskList.map((item) => item.largerCount);
const generalCounts = riskList.map((item) => item.generalCount);
const lowCounts = riskList.map((item) => item.lowCount);
const option = {
title: {
text: '各家公司的风险统计情况',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' },
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function (params) {
let result = `${params[0].axisValue}
`;
params.forEach((param) => {
result += `${param.marker}${param.seriesName}: ${param.value}
`;
});
return result;
},
},
legend: {
data: ['重大风险', '较大风险', '一般风险', '低风险'],
orient: 'vertical',
right: '3%',
top: '5%',
itemGap: 16,
itemWidth: 18,
itemHeight: 12,
textStyle: { color: '#000', fontSize: 14 },
},
grid: {
left: '8%',
right: '5%',
top: '18%',
bottom: '8%',
containLabel: true,
},
xAxis: [
{
type: 'category',
data: companyNames,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
textStyle: { color: '#000' },
rotate: companyNames.length > 4 ? 15 : 0,
interval: 0,
fontSize: 12,
},
},
],
yAxis: [
{
type: 'value',
show: true,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
show: true,
textStyle: { color: '#000' },
},
splitLine: { show: false },
name: '风险数量',
nameTextStyle: { fontSize: 12 },
},
],
series: [
{
name: '重大风险',
type: 'bar',
stack: 'total',
data: majorCounts,
itemStyle: { normal: { color: '#c92a2a' } },
label: {
show: true,
position: 'inside',
textStyle: { color: '#fff', fontSize: 11 },
formatter: (params) => (params.value > 0 ? params.value : ''),
},
barWidth: '35%',
},
{
name: '较大风险',
type: 'bar',
stack: 'total',
data: largerCounts,
itemStyle: { normal: { color: '#ffa94d' } },
label: {
show: true,
position: 'inside',
textStyle: { color: '#fff', fontSize: 11 },
formatter: (params) => (params.value > 0 ? params.value : ''),
},
barWidth: '35%',
},
{
name: '一般风险',
type: 'bar',
stack: 'total',
data: generalCounts,
itemStyle: { normal: { color: '#ffe066' } },
label: {
show: true,
position: 'inside',
textStyle: { color: '#fff', fontSize: 11 },
formatter: (params) => (params.value > 0 ? params.value : ''),
},
barWidth: '35%',
},
{
name: '低风险',
type: 'bar',
stack: 'total',
data: lowCounts,
itemStyle: { normal: { color: '#4285F4' } },
label: {
show: true,
position: 'inside',
textStyle: { color: '#fff', fontSize: 11 },
formatter: (params) => (params.value > 0 ? params.value : ''),
},
barWidth: '35%',
},
],
};
this.echartsInstances.stackBarChart.setOption(option);
this.setupResizeHandler('stackBarChart', this.renderStackBarChart);
};
// 风险类别柱状图
renderTypeBarChart = async () => {
if (this.isUnmounted) return;
const elementExists = await this.waitForElement('typeBarChart');
if (!elementExists || this.isUnmounted) return;
if (this.echartsInstances.typeBarChart) {
this.echartsInstances.typeBarChart.dispose();
this.echartsInstances.typeBarChart = null;
}
const chartDom = document.getElementById('typeBarChart');
if (!chartDom) return;
this.echartsInstances.typeBarChart = echarts.init(chartDom);
const { riskSubData } = this.props;
const riskTypeList = riskSubData?.riskTypeList || [];
if (riskTypeList.length === 0) {
this.echartsInstances.typeBarChart.setOption({
title: {
text: '风险类别统计情况',
x: 'center',
y: '25%',
textStyle: { fontSize: 16, color: '#999' },
},
graphic: {
type: 'text',
left: 'center',
top: 'middle',
style: {
text: '暂无数据',
fill: '#999',
fontSize: 14,
},
},
});
return;
}
const typeNames = riskTypeList.map((item) => item.typeName);
const quantities = riskTypeList.map((item) => item.qty);
const option = {
title: {
text: '风险类别统计情况',
x: 'center',
y: '5%',
textStyle: { fontSize: 16, color: '#000', fontWeight: 'bold' },
},
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' },
formatter: function (params) {
let result = `${params[0].axisValue}
`;
params.forEach((param) => {
result += `${param.marker}${param.seriesName}: ${param.value}
`;
});
return result;
},
},
grid: {
left: '8%',
right: '5%',
top: '18%',
bottom: '8%',
containLabel: true,
},
xAxis: [
{
type: 'category',
data: typeNames,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
textStyle: { color: '#000' },
// rotate: typeNames.length > 4 ? 15 : 0,
interval: 0,
fontSize: 12,
},
},
],
yAxis: [
{
type: 'value',
show: true,
axisLine: { show: false },
axisTick: { show: false },
axisLabel: {
show: true,
textStyle: { color: '#000' },
},
splitLine: { show: false },
},
],
series: [
{
name: '风险数量',
type: 'bar',
data: quantities,
itemStyle: {
normal: {
color: '#4285F4', // 与 trainingContent 一致的蓝色
},
},
label: {
show: true,
position: 'top',
textStyle: { color: '#4285F4', fontSize: 12 },
formatter: (params) => `${params.value}`,
},
barWidth: '50%',
},
],
};
this.echartsInstances.typeBarChart.setOption(option);
this.setupResizeHandler('typeBarChart', this.renderTypeBarChart);
};
// 表格: 各公司风险统计明细表
renderRiskTable = () => {
const { riskSubData } = this.props;
const riskList = riskSubData?.riskList || [];
if (riskList.length === 0) {
return