/**
* 沪深港通资金流向监控JS
*/
document.addEventListener('DOMContentLoaded', function() {
// 初始化图表
let northChart = null;
let southChart = null;
let rzrqChart = null; // 融资融券图表实例
// 当前显示的融资融券数据系列
let currentMetric = 'total_rzrq_balance';
// 融资融券数据
let rzrqData = null;
// 融资融券图表相关功能
let rzrqIndexSelector = null;
let rzrqChartData = null; // 用于存储融资融券图表的原始数据
// 初始化图表函数,确保DOM元素存在
function initCharts() {
try {
const northChartDom = document.getElementById('northChart');
const southChartDom = document.getElementById('southChart');
const rzrqChartDom = document.getElementById('rzrqChart');
if (northChartDom && !northChart) {
try {
northChart = echarts.init(northChartDom);
console.log('北向资金图表初始化成功');
} catch (e) {
console.error('北向资金图表初始化失败:', e);
}
}
if (southChartDom && !southChart) {
try {
southChart = echarts.init(southChartDom);
console.log('南向资金图表初始化成功');
} catch (e) {
console.error('南向资金图表初始化失败:', e);
}
}
if (rzrqChartDom && !rzrqChart) {
try {
rzrqChart = echarts.init(rzrqChartDom);
console.log('融资融券图表初始化成功');
} catch (e) {
console.error('融资融券图表初始化失败:', e);
}
}
return northChart && southChart && rzrqChart;
} catch (e) {
console.error('图表初始化过程中发生错误:', e);
return false;
}
}
// 确保DOM加载完毕后初始化图表
// 使用setTimeout确保DOM元素完全渲染
setTimeout(function() {
if (!initCharts()) {
console.log('首次初始化图表不成功,将在数据加载时再次尝试');
}
// 开始加载数据
loadData();
// 加载融资融券数据
initRzrqChart();
// 检查是否在交易时段,只有在交易时段才设置自动刷新
if (isWithinTradingHours()) {
console.log('当前处于交易时段,启用自动刷新');
// 设置自动刷新 (每分钟刷新一次)
window.refreshInterval = setInterval(loadData, 60000);
} else {
console.log('当前不在交易时段,不启用自动刷新');
}
}, 100);
/**
* 判断当前时间是否在交易时段内 (9:20-16:00)
*/
function isWithinTradingHours() {
const now = new Date();
const hours = now.getHours();
const minutes = now.getMinutes();
const dayOfWeek = now.getDay(); // 0是周日,6是周六
// 如果是周末,不在交易时段
if (dayOfWeek === 0 || dayOfWeek === 6) {
return false;
}
// 计算当前时间的分钟数
const totalMinutes = hours * 60 + minutes;
// 交易时段开始时间:9:20 (9*60 + 20 = 560分钟)
const tradingStartMinutes = 9 * 60 + 20;
// 交易时段结束时间:16:00 (16*60 = 960分钟)
const tradingEndMinutes = 16 * 60;
// 判断当前时间是否在交易时段内
return totalMinutes >= tradingStartMinutes && totalMinutes <= tradingEndMinutes;
}
// 设置图表自适应
window.addEventListener('resize', function() {
if (northChart) {
try {
northChart.resize();
} catch (e) {
console.error('北向资金图表调整大小失败:', e);
}
}
if (southChart) {
try {
southChart.resize();
} catch (e) {
console.error('南向资金图表调整大小失败:', e);
}
}
if (rzrqChart) {
try {
rzrqChart.resize();
} catch (e) {
console.error('融资融券图表调整大小失败:', e);
}
}
});
// 刷新按钮事件
const refreshBtn = document.getElementById('refreshBtn');
if (refreshBtn) {
refreshBtn.addEventListener('click', function() {
loadData();
// 如果当前不在交易时段但点击了刷新按钮,显示提示信息
if (!isWithinTradingHours()) {
showMessage('当前不在交易时段(9:20-16:00),数据可能不会更新');
}
});
}
// 融资融券刷新按钮事件
const rzrqRefreshBtn = document.getElementById('rzrqRefreshBtn');
if (rzrqRefreshBtn) {
rzrqRefreshBtn.addEventListener('click', function() {
if (rzrqChart) {
rzrqChart.showLoading();
loadRzrqData();
}
});
}
// 融资融券指标切换按钮点击事件
const metricButtons = document.querySelectorAll('.btn-group button[data-metric]');
if (metricButtons && metricButtons.length > 0) {
metricButtons.forEach(button => {
button.addEventListener('click', function() {
metricButtons.forEach(btn => btn.classList.remove('active'));
this.classList.add('active');
currentMetric = this.getAttribute('data-metric');
updateRzrqChart();
});
});
}
/**
* 显示消息提示
*/
function showMessage(message) {
console.log(message);
// 可以在这里添加Toast或其他UI提示
// 例如:
const updateTimeElem = document.getElementById('updateTime');
if (updateTimeElem) {
const originalText = updateTimeElem.textContent;
updateTimeElem.textContent = message;
setTimeout(() => {
updateTimeElem.textContent = originalText;
}, 3000);
}
}
/**
* 加载北向和南向资金数据
*/
function loadData() {
// 确保图表已经初始化
initCharts();
// 显示加载中状态
showLoading(true);
console.log('开始加载北向资金数据...');
// 获取北向资金数据 (从香港流入A股的资金)
fetch('/api/hsgt/northbound')
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.message || '获取北向资金数据失败');
});
}
return response.json();
})
.then(data => {
console.log('北向资金数据获取成功:', data.status);
if (data.status === 'success' && data.data && data.data.success) {
// 检查数据结构
console.log('北向资金数据结构:', {
hasTimeArray: Array.isArray(data.data.times),
timeLength: data.data.times ? data.data.times.length : 0,
hasDataObj: !!data.data.data,
totalLength: data.data.data && data.data.data.total ? data.data.data.total.length : 0,
hasCurrent: !!data.data.current
});
// 渲染北向资金数据
renderNorthboundData(data.data);
} else {
const errorMessage = data.data && data.data.message
? data.data.message
: (data.message || '北向资金数据格式错误');
showError('北向资金数据获取失败: ' + errorMessage);
// 显示空数据状态
renderEmptyNorthboundChart();
}
})
.catch(error => {
showError('请求北向资金数据错误: ' + error.message);
console.error('北向资金数据请求异常:', error);
// 显示空数据状态
renderEmptyNorthboundChart();
})
.finally(() => {
// 无论成功失败,都开始请求南向资金数据
loadSouthboundData();
});
}
/**
* 渲染空的北向资金图表
*/
function renderEmptyNorthboundChart() {
if (!northChart) return;
// 更新统计卡片为暂无数据
updateStatCard('northTotal', null, '暂无数据');
updateStatCard('northSH', null, '暂无数据');
updateStatCard('northSZ', null, '暂无数据');
// 初始化一个简单的图表提示暂无数据
northChart.setOption({
title: {
text: '陆股通资金流向(北向)',
left: 'center',
top: 0
},
graphic: {
elements: [{
type: 'text',
left: 'center',
top: 'middle',
style: {
text: '暂无数据',
fontSize: 20,
fill: '#999'
}
}]
}
}, true);
}
/**
* 加载南向资金数据
*/
function loadSouthboundData() {
console.log('开始加载南向资金数据...');
fetch('/api/hsgt/southbound')
.then(response => {
if (!response.ok) {
return response.json().then(data => {
throw new Error(data.message || '获取南向资金数据失败');
});
}
return response.json();
})
.then(data => {
console.log('南向资金数据获取成功:', data.status);
if (data.status === 'success' && data.data && data.data.success) {
// 检查数据结构
console.log('南向资金数据结构:', {
hasTimeArray: Array.isArray(data.data.times),
timeLength: data.data.times ? data.data.times.length : 0,
hasDataObj: !!data.data.data,
totalLength: data.data.data && data.data.data.total ? data.data.data.total.length : 0,
hasCurrent: !!data.data.current
});
// 渲染南向资金数据
renderSouthboundData(data.data);
} else {
const errorMessage = data.data && data.data.message
? data.data.message
: (data.message || '南向资金数据格式错误');
showError('南向资金数据获取失败: ' + errorMessage);
// 显示空数据状态
renderEmptySouthboundChart();
}
})
.catch(error => {
showError('请求南向资金数据错误: ' + error.message);
console.error('南向资金数据请求异常:', error);
// 显示空数据状态
renderEmptySouthboundChart();
})
.finally(() => {
// 隐藏加载中状态
showLoading(false);
});
}
/**
* 渲染空的南向资金图表
*/
function renderEmptySouthboundChart() {
if (!southChart) return;
// 更新统计卡片为暂无数据
updateStatCard('southTotal', null, '暂无数据');
updateStatCard('southHKSH', null, '暂无数据');
updateStatCard('southHKSZ', null, '暂无数据');
// 初始化一个简单的图表提示暂无数据
southChart.setOption({
title: {
text: '港股通资金流向(南向)',
left: 'center',
top: 0
},
graphic: {
elements: [{
type: 'text',
left: 'center',
top: 'middle',
style: {
text: '暂无数据',
fontSize: 20,
fill: '#999'
}
}]
}
}, true);
}
/**
* 渲染北向资金数据 (从香港流入A股的资金)
*/
function renderNorthboundData(data) {
if (!northChart) return;
try {
// 验证数据有效性
if (!data || !data.data || !data.times || !data.current) {
renderEmptyNorthboundChart();
return;
}
// 准备简化的图表数据
const times = data.times;
const seriesData = [];
// 处理北向资金总量
if (data.data.total && Array.isArray(data.data.total) && data.data.total.length > 0) {
seriesData.push({
name: '北向资金',
type: 'line',
data: data.data.total,
lineStyle: {width: 3}
});
}
// 处理沪股通
if (data.data.sh && Array.isArray(data.data.sh) && data.data.sh.length > 0) {
seriesData.push({
name: '沪股通',
type: 'line',
data: data.data.sh
});
}
// 处理深股通
if (data.data.sz && Array.isArray(data.data.sz) && data.data.sz.length > 0) {
seriesData.push({
name: '深股通',
type: 'line',
data: data.data.sz
});
}
// 如果没有有效的系列数据,显示空图表
if (seriesData.length === 0) {
renderEmptyNorthboundChart();
return;
}
// 更新统计卡片
updateStatCard('northTotal', data.current.total);
updateStatCard('northSH', data.current.sh);
updateStatCard('northSZ', data.current.sz);
// 更新时间
const updateTimeElem = document.getElementById('updateTime');
if (updateTimeElem) {
let timeText = '最后更新时间: ' + data.update_time;
// 如果不在交易时段,添加提示
if (!isWithinTradingHours()) {
timeText += ' (非交易时段)';
}
updateTimeElem.textContent = timeText;
}
// 创建简单的图表配置
const option = {
title: {
text: '陆股通资金流向(北向)',
left: 'center',
top: 0
},
tooltip: {
trigger: 'axis',
formatter: function(params) {
if (!params || params.length === 0) return '';
const time = params[0].axisValue;
let result = `${time}
`;
params.forEach(param => {
if (param && param.value !== undefined) {
const value = param.value;
const color = param.color;
const marker = ``;
let valueText = value !== null ? value.toFixed(2) : 'N/A';
if (value > 0) valueText = '+' + valueText;
result += `${marker}${param.seriesName}: ${valueText} 亿
`;
}
});
return result;
}
},
legend: {
data: seriesData.map(item => item.name),
top: 30
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: 80,
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: times,
axisLabel: {
rotate: 45
}
},
yAxis: {
type: 'value',
name: '净流入金额(亿元)',
axisLabel: {
formatter: function(value) {
return value.toFixed(1);
}
}
},
series: seriesData,
color: ['#ec0000', '#1e88e5', '#ff9800']
};
// 安全地设置图表
if (northChart && northChart.setOption) {
northChart.setOption(option, true);
} else {
console.error('北向资金图表实例无效');
const northChartDom = document.getElementById('northChart');
if (northChartDom) {
northChart = echarts.init(northChartDom);
northChart.setOption(option, true);
}
}
} catch (error) {
console.error('设置北向资金图表选项时出错:', error);
renderEmptyNorthboundChart();
}
}
/**
* 渲染南向资金数据 (从内地流入港股的资金)
*/
function renderSouthboundData(data) {
if (!southChart) return;
try {
// 验证数据有效性
if (!data || !data.data || !data.times || !data.current) {
renderEmptySouthboundChart();
return;
}
// 准备简化的图表数据
const times = data.times;
const seriesData = [];
// 处理南向资金总量
if (data.data.total && Array.isArray(data.data.total) && data.data.total.length > 0) {
seriesData.push({
name: '南向资金',
type: 'line',
data: data.data.total,
lineStyle: {width: 3}
});
}
// 处理沪市港股通
if (data.data.hk_sh && Array.isArray(data.data.hk_sh) && data.data.hk_sh.length > 0) {
seriesData.push({
name: '沪市港股通',
type: 'line',
data: data.data.hk_sh
});
}
// 处理深市港股通
if (data.data.hk_sz && Array.isArray(data.data.hk_sz) && data.data.hk_sz.length > 0) {
seriesData.push({
name: '深市港股通',
type: 'line',
data: data.data.hk_sz
});
}
// 如果没有有效的系列数据,显示空图表
if (seriesData.length === 0) {
renderEmptySouthboundChart();
return;
}
// 更新统计卡片
updateStatCard('southTotal', data.current.total);
updateStatCard('southHKSH', data.current.hk_sh);
updateStatCard('southHKSZ', data.current.hk_sz);
// 创建简单的图表配置
const option = {
title: {
text: '港股通资金流向(南向)',
left: 'center',
top: 0
},
tooltip: {
trigger: 'axis',
formatter: function(params) {
if (!params || params.length === 0) return '';
const time = params[0].axisValue;
let result = `${time}
`;
params.forEach(param => {
if (param && param.value !== undefined) {
const value = param.value;
const color = param.color;
const marker = ``;
let valueText = value !== null ? value.toFixed(2) : 'N/A';
if (value > 0) valueText = '+' + valueText;
result += `${marker}${param.seriesName}: ${valueText} 亿
`;
}
});
return result;
}
},
legend: {
data: seriesData.map(item => item.name),
top: 30
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: 80,
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: times,
axisLabel: {
rotate: 45
}
},
yAxis: {
type: 'value',
name: '净流入金额(亿元)',
axisLabel: {
formatter: function(value) {
return value.toFixed(1);
}
}
},
series: seriesData,
color: ['#ec0000', '#1e88e5', '#ff9800']
};
// 安全地设置图表
if (southChart && southChart.setOption) {
southChart.setOption(option, true);
} else {
console.error('南向资金图表实例无效');
const southChartDom = document.getElementById('southChart');
if (southChartDom) {
southChart = echarts.init(southChartDom);
southChart.setOption(option, true);
}
}
} catch (error) {
console.error('设置南向资金图表选项时出错:', error);
renderEmptySouthboundChart();
}
}
/**
* 更新统计卡片
*/
function updateStatCard(id, value, customText) {
const statCard = document.getElementById(id);
if (!statCard) return;
const statValue = statCard.querySelector('.stat-value');
if (!statValue) return;
if (customText) {
statValue.textContent = customText;
statValue.classList.remove('money-inflow', 'money-outflow');
return;
}
if (value === null || value === undefined) {
statValue.textContent = '--';
statValue.classList.remove('money-inflow', 'money-outflow');
return;
}
// 格式化显示,保留两位小数
const formattedValue = value.toFixed(2);
// 根据正负值设置样式
if (value > 0) {
statValue.textContent = '+' + formattedValue;
statValue.classList.add('money-inflow');
statValue.classList.remove('money-outflow');
} else if (value < 0) {
statValue.textContent = formattedValue;
statValue.classList.add('money-outflow');
statValue.classList.remove('money-inflow');
} else {
statValue.textContent = formattedValue;
statValue.classList.remove('money-inflow', 'money-outflow');
}
}
/**
* 显示错误信息
*/
function showError(message) {
console.error(message);
// 可以添加Toast或其他UI提示
}
/**
* 显示/隐藏加载状态
*/
function showLoading(isLoading) {
if (!northChart || !southChart) return;
// 实现加载中状态显示
if (isLoading) {
northChart.showLoading({text: '加载中...'});
southChart.showLoading({text: '加载中...'});
} else {
northChart.hideLoading();
southChart.hideLoading();
}
}
// ============ 融资融券图表相关功能 ============
/**
* 初始化融资融券图表
*/
function initRzrqChart() {
if (rzrqChart) {
rzrqChart.dispose();
}
rzrqChart = echarts.init(document.getElementById('rzrqChart'));
// 设置图表加载中状态
if (rzrqChart) {
rzrqChart.showLoading();
// 加载数据
loadRzrqData();
}
}
/**
* 加载融资融券数据
*/
function loadRzrqData() {
$.ajax({
url: '/api/rzrq/chart_data',
type: 'GET',
data: {
days: 90 // 默认加载90天数据
},
dataType: 'json',
success: function(response) {
if (response.status === 'success') {
rzrqData = response.data;
rzrqChartData = response.data; // 用于存储融资融券图表的原始数据
updateRzrqChart();
$('#rzrqUpdateTime').text('数据更新时间: ' + rzrqData.last_update);
// 初始化融资融券图表的索引选择器
if (!rzrqIndexSelector) {
initRzrqIndexSelector();
}
} else {
rzrqChart.hideLoading();
rzrqChart.setOption({
title: {
text: '数据加载失败',
textStyle: {
color: '#999',
fontSize: 14
},
left: 'center',
top: 'center'
}
});
}
},
error: function(xhr, status, error) {
rzrqChart.hideLoading();
rzrqChart.setOption({
title: {
text: '数据加载失败: ' + error,
textStyle: {
color: '#999',
fontSize: 14
},
left: 'center',
top: 'center'
}
});
}
});
}
/**
* 初始化融资融券图表的索引选择器
*/
function initRzrqIndexSelector() {
rzrqIndexSelector = new IndexSelector('rzrqChart', {
// 获取图表当前显示的日期范围
getDateRange: function() {
// 如果有rzrq图表的日期数据,返回第一个和最后一个日期
if (rzrqChartData && rzrqChartData.dates && rzrqChartData.dates.length) {
return {
startDate: rzrqChartData.dates[0],
endDate: rzrqChartData.dates[rzrqChartData.dates.length - 1]
};
}
return { startDate: null, endDate: null };
},
// 指数数据更新时的回调
onChange: function(selectedIndices) {
updateRzrqChartWithIndices(selectedIndices);
}
});
}
/**
* 将数据对齐到日期范围
*/
function alignDataToDateRange(sourceDates, sourceValues, targetDates) {
const result = new Array(targetDates.length).fill(null);
const dateMap = {};
// 创建源数据日期到值的映射
sourceDates.forEach((date, index) => {
dateMap[date] = sourceValues[index];
});
// 映射到目标日期
targetDates.forEach((date, index) => {
if (dateMap[date] !== undefined) {
result[index] = dateMap[date];
}
});
return result;
}
/**
* 更新融资融券图表,添加指数数据
*/
function updateRzrqChartWithIndices(indices) {
if (!rzrqChart) return;
// 获取当前图表配置
const option = rzrqChart.getOption();
// 保留原始系列数据(融资融券数据)
const originalSeries = option.series.filter(s => s.name.indexOf('指数') === -1);
// 清除所有指数系列
option.series = [...originalSeries];
// 如果没有选择指数,则移除右侧Y轴
if (indices.length === 0) {
option.yAxis = option.yAxis.filter(axis => axis.name !== '指数值');
rzrqChart.setOption(option, true);
return;
}
// 计算所有指数数据的最小值和最大值
let allValues = [];
indices.forEach(index => {
if (index.data && index.data.values) {
// 过滤掉null和undefined值
const validValues = index.data.values.filter(v => v !== null && v !== undefined);
allValues = allValues.concat(validValues);
}
});
// 计算数据范围
let minValue = Math.min(...allValues);
let maxValue = Math.max(...allValues);
// 增加一定的边距,使图表更美观
const range = maxValue - minValue;
const padding = range * 0.1; // 上下各留10%的边距
minValue = minValue - padding;
maxValue = maxValue + padding;
minValue = Math.round(minValue * 10) / 10;
maxValue = Math.round(maxValue * 10) / 10;
// 添加指数系列
indices.forEach(index => {
if (!index.data || !index.data.dates) return;
// 将指数数据对齐到融资融券数据的日期范围
const alignedData = alignDataToDateRange(index.data.dates, index.data.values, option.xAxis[0].data);
// 创建新的Y轴用于指数
if (!option.yAxis.some(axis => axis.name === '指数值')) {
option.yAxis.push({
name: '指数值',
type: 'value',
position: 'right',
min: minValue, // 使用计算出的最小值
max: maxValue, // 使用计算出的最大值
splitLine: {
show: false
},
axisLabel: {
formatter: '{value}'
}
});
} else {
// 如果已存在指数Y轴,更新其范围
const indexAxis = option.yAxis.find(axis => axis.name === '指数值');
if (indexAxis) {
indexAxis.min = minValue;
indexAxis.max = maxValue;
}
}
// 添加指数系列
option.series.push({
name: `${index.name}`, // 移除"指数"后缀,避免在tooltip中显示为"上证指数指数"
type: 'line',
yAxisIndex: 1, // 使用第二个Y轴
data: alignedData,
symbol: 'none',
smooth: true,
lineStyle: {
width: 2,
color: index.color
},
itemStyle: {
color: index.color
},
// 标记这是指数数据
isIndex: true
});
});
// 更新图例
option.legend = {
data: [
...originalSeries.map(s => s.name),
...indices.map(i => i.name) // 使用原始指数名称
],
selected: {
...option.legend?.selected || {},
...indices.reduce((acc, index) => {
acc[index.name] = true; // 使用原始指数名称
return acc;
}, {})
},
top: 40 // 将图例下移,避免与标题重叠
};
// 应用更新
rzrqChart.setOption(option, true);
}
/**
* 更新融资融券图表
*/
function updateRzrqChart() {
if (!rzrqData || !rzrqData.success) {
return;
}
// 查找当前指标的数据
let currentSeries = rzrqData.series.find(s => s.name === getMetricName(currentMetric));
// 如果未找到,使用第一个系列
if (!currentSeries && rzrqData.series.length > 0) {
currentSeries = rzrqData.series[0];
currentMetric = getMetricKey(currentSeries.name);
}
if (!currentSeries) {
rzrqChart.hideLoading();
return;
}
// 计算数据的最小值和最大值,用于设置Y轴范围
const validData = currentSeries.data.filter(value => value !== null && value !== undefined);
let min = Math.min(...validData);
let max = Math.max(...validData);
// 为了图表美观,给最小值和最大值增加一些间距
const range = max - min;
min = min - range * 0.05; // 下方留5%的间距
max = max + range * 0.05; // 上方留5%的间距
// 设置图表选项
const option = {
title: {
text: currentSeries.name + '走势',
left: 'center',
top: 10 // 固定标题位置在顶部
},
tooltip: {
trigger: 'axis',
formatter: function(params) {
let tooltip = params[0].axisValue + '
';
params.forEach(param => {
// 判断是否为指数系列
const isIndexSeries = param.seriesIndex > 0 && param.seriesName.indexOf('融资') === -1 && param.seriesName.indexOf('融券') === -1;
// 对于指数系列,不添加单位;对于融资融券系列,添加相应单位
tooltip += param.marker + ' ' + param.seriesName + ': ' +
param.value + (isIndexSeries ? '' : (' ' + currentSeries.unit)) + '
';
});
return tooltip;
}
},
xAxis: {
type: 'category',
data: rzrqData.dates,
axisLabel: {
rotate: 45
},
axisLine: {
lineStyle: {
color: '#999'
}
}
},
yAxis: {
type: 'value',
name: currentSeries.unit,
min: min, // 设置Y轴最小值为数据的最小值
max: max, // 设置Y轴最大值为数据的最大值
nameTextStyle: {
padding: [0, 30, 0, 0]
},
axisLine: {
show: true,
lineStyle: {
color: '#999'
}
},
splitLine: {
lineStyle: {
color: '#eee'
}
}
},
dataZoom: [
{
type: 'inside',
start: 0,
end: 100
},
{
start: 0,
end: 100
}
],
series: [
{
name: currentSeries.name,
type: 'line',
data: currentSeries.data,
lineStyle: {
width: 3
},
itemStyle: {
color: '#1890ff'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(24, 144, 255, 0.3)'
},
{
offset: 1,
color: 'rgba(24, 144, 255, 0.1)'
}
]
}
},
connectNulls: true
}
],
grid: {
left: '3%',
right: '4%',
bottom: '15%',
top: '70px', // 增加顶部空间,给标题和图例留出足够位置
containLabel: true
},
legend: {
top: 40, // 将图例放在标题下方
left: 'center'
},
toolbox: {
feature: {
saveAsImage: {}
}
}
};
rzrqChart.hideLoading();
rzrqChart.setOption(option);
// 更新风险指标显示
updateRiskIndicators();
}
/**
* 更新风险指标显示
*/
function updateRiskIndicators() {
// 检查是否有风险指标数据
if (!rzrqData || !rzrqData.risk_indicators) {
// 隐藏或显示无数据状态
console.log('无风险指标数据');
// 清理可能存在的旧数据
$('#summaryBalanceChangeDesc').text('--');
$('#summarySecuritiesChangeDesc').text('--');
$('#overallRiskLevel').text('N/A');
$('#overallRiskDesc').text('无法加载风险数据。');
$('#overallRiskAlert').removeClass('alert-danger alert-warning alert-success alert-info');
return;
}
const indicators = rzrqData.risk_indicators;
// 辅助函数:格式化描述文本并设置
function formatAndSetDescription(targetSelector, descriptionText, defaultText) {
const descElement = $(targetSelector);
if (!descriptionText) {
descElement.text(defaultText || '--');
return;
}
// 正则表达式匹配数字(包括正负号和小数点)和百分号
const percentageRegex = /([-+]?\d*\.?\d+)%/;
const match = descriptionText.match(percentageRegex);
if (match && match[1]) {
const percentageValueStr = match[0]; // 例如 "+0.15%" 或 "-3.14%"
const numericValue = parseFloat(match[1]); // 例如 0.15 或 -3.14
let colorClass = 'neutral';
if (numericValue > 0) {
colorClass = 'positive';
} else if (numericValue < 0) {
colorClass = 'negative';
}
const styledDescription = descriptionText.replace(
percentageRegex,
`${percentageValueStr}`
);
descElement.html(styledDescription);
} else {
descElement.text(descriptionText); // 没有百分比则直接显示
}
}
// 更新综合风险评估
if (indicators.overall_risk) {
const overallRisk = indicators.overall_risk;
const riskLevel = overallRisk.level;
// 设置风险等级和描述
$('#overallRiskLevel').text(riskLevel);
$('#overallRiskDesc').text(overallRisk.description);
// 根据风险等级设置颜色
const alertElem = $('#overallRiskAlert');
alertElem.removeClass('alert-danger alert-warning alert-success alert-info');
if (riskLevel === '高') {
alertElem.addClass('alert-danger');
} else if (riskLevel === '中') {
alertElem.addClass('alert-warning');
} else if (riskLevel === '低') {
alertElem.addClass('alert-success');
} else {
alertElem.addClass('alert-info');
}
} else {
$('#overallRiskLevel').text('N/A');
$('#overallRiskDesc').text('综合风险数据缺失。');
$('#overallRiskAlert').removeClass('alert-danger alert-warning alert-success').addClass('alert-info');
}
// 更新融资融券余额变化 - 新的汇总位置
if (indicators.balance_risk && indicators.balance_risk.description) {
formatAndSetDescription('#summaryBalanceChangeDesc', indicators.balance_risk.description);
} else {
$('#summaryBalanceChangeDesc').text('融资融券余额变化数据: --');
}
// 更新卡片内的详细信息(不含移动的描述)
if (indicators.recent_balance_change && indicators.balance_risk) {
const balanceChange = indicators.recent_balance_change;
const balanceRisk = indicators.balance_risk;
let rateText = balanceChange.rate > 0 ? '+' : '';
rateText += balanceChange.rate + '%';
$('#balanceChangeRate').text(rateText).removeClass('text-success text-danger').addClass(balanceChange.rate > 0 ? 'text-danger' : 'text-success');
$('#balanceRiskLevel').text(balanceRisk.level);
setRiskLevelColor('#balanceRiskLevel', balanceRisk.level);
// $('#balanceRiskDesc').text(balanceRisk.description); // 这行被移动了
} else {
$('#balanceChangeRate').text('--');
$('#balanceRiskLevel').text('--');
}
// 更新融券余额变化 - 新的汇总位置
if (indicators.securities_risk && indicators.securities_risk.description) {
formatAndSetDescription('#summarySecuritiesChangeDesc', indicators.securities_risk.description);
} else {
$('#summarySecuritiesChangeDesc').text('融券余额变化数据: --');
}
// 更新卡片内的详细信息(不含移动的描述)
if (indicators.securities_balance_change && indicators.securities_risk) {
const securitiesChange = indicators.securities_balance_change;
const securitiesRisk = indicators.securities_risk;
let rateText = securitiesChange.rate > 0 ? '+' : '';
rateText += securitiesChange.rate + '%';
$('#securitiesChangeRate').text(rateText).removeClass('text-success text-danger').addClass(securitiesChange.rate > 0 ? 'text-danger' : 'text-success');
$('#securitiesRiskLevel').text(securitiesRisk.level);
setRiskLevelColor('#securitiesRiskLevel', securitiesRisk.level);
// $('#securitiesRiskDesc').text(securitiesRisk.description); // 这行被移动了
} else {
$('#securitiesChangeRate').text('--');
$('#securitiesRiskLevel').text('--');
}
// 更新融资偿还比率 (这部分逻辑不变,仅为上下文)
if (indicators.repay_buy_ratio && indicators.repay_risk) {
const repayRatio = indicators.repay_buy_ratio;
const repayRisk = indicators.repay_risk;
$('#repayBuyRatio').text(repayRatio.value);
if (repayRatio.value > 1.1) {
$('#repayBuyRatio').removeClass('text-success').addClass('text-danger');
} else if (repayRatio.value < 0.9) {
$('#repayBuyRatio').removeClass('text-danger').addClass('text-success');
} else {
$('#repayBuyRatio').removeClass('text-danger text-success');
}
$('#repayRiskLevel').text(repayRisk.level);
setRiskLevelColor('#repayRiskLevel', repayRisk.level);
$('#repayRiskDesc').text(repayRisk.description); // 这个描述保留在原位
} else {
$('#repayBuyRatio').text('--');
$('#repayRiskLevel').text('--');
$('#repayRiskDesc').text('--');
}
// 更新融资占比 (这部分逻辑不变,仅为上下文)
if (indicators.financing_ratio) {
$('#financingRatio').text(indicators.financing_ratio + '%');
if (indicators.financing_ratio_percentile !== undefined) {
$('#financingRatioPercentile').text(indicators.financing_ratio_percentile + '%');
if (indicators.financing_ratio_percentile > 80) {
$('#financingRatioPercentile').removeClass('text-success text-warning').addClass('text-danger');
} else if (indicators.financing_ratio_percentile > 50) {
$('#financingRatioPercentile').removeClass('text-success text-danger').addClass('text-warning');
} else {
$('#financingRatioPercentile').removeClass('text-danger text-warning').addClass('text-success');
}
} else {
$('#financingRatioPercentile').text('数据不足');
}
} else {
$('#financingRatio').text('--');
$('#financingRatioPercentile').text('--');
}
}
/**
* 根据风险等级设置文本颜色
*/
function setRiskLevelColor(selector, level) {
const elem = $(selector);
elem.removeClass('text-danger text-warning text-success text-info');
if (level === '高') {
elem.addClass('text-danger');
} else if (level === '中') {
elem.addClass('text-warning');
} else if (level === '低') {
elem.addClass('text-success');
} else {
elem.addClass('text-info');
}
}
/**
* 根据数据系列键名获取显示名称
*/
function getMetricName(metricKey) {
const metricMap = {
'total_rzrq_balance': '融资融券余额合计',
'total_financing_buy': '融资买入额合计',
'total_financing_balance': '融资余额合计',
'financing_repayment': '融资偿还',
'securities_balance': '融券余额'
};
return metricMap[metricKey] || metricKey;
}
/**
* 根据显示名称获取数据系列键名
*/
function getMetricKey(metricName) {
const metricMap = {
'融资融券余额合计': 'total_rzrq_balance',
'融资买入额合计': 'total_financing_buy',
'融资余额合计': 'total_financing_balance',
'融资偿还': 'financing_repayment',
'融券余额': 'securities_balance'
};
return metricMap[metricName] || metricName;
}
});