stock / templates /risk_monitor.html
gitdeem's picture
Upload 32 files
f5d52f6 verified
{% extends "layout.html" %}
{% block title %}风险监控 - 智能分析系统{% endblock %}
{% block content %}
<div class="container-fluid py-3">
<div id="alerts-container"></div>
<div class="row mb-3">
<div class="col-12">
<div class="card">
<div class="card-header py-2">
<h5 class="mb-0">风险监控</h5>
</div>
<div class="card-body py-2">
<ul class="nav nav-tabs" id="risk-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="stock-risk-tab" data-bs-toggle="tab" data-bs-target="#stock-risk" type="button" role="tab" aria-controls="stock-risk" aria-selected="true">个股风险</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="portfolio-risk-tab" data-bs-toggle="tab" data-bs-target="#portfolio-risk" type="button" role="tab" aria-controls="portfolio-risk" aria-selected="false">组合风险</button>
</li>
</ul>
<div class="tab-content mt-3" id="risk-tabs-content">
<div class="tab-pane fade show active" id="stock-risk" role="tabpanel" aria-labelledby="stock-risk-tab">
<form id="stock-risk-form" class="row g-2">
<div class="col-md-4">
<div class="input-group input-group-sm">
<span class="input-group-text">股票代码</span>
<input type="text" class="form-control" id="stock-code" placeholder="例如: 600519" required>
</div>
</div>
<div class="col-md-3">
<div class="input-group input-group-sm">
<span class="input-group-text">市场</span>
<select class="form-select" id="market-type">
<option value="A" selected>A股</option>
<option value="HK">港股</option>
<option value="US">美股</option>
</select>
</div>
</div>
<div class="col-md-3">
<button type="submit" class="btn btn-primary btn-sm w-100">
<i class="fas fa-search"></i> 分析风险
</button>
</div>
</form>
</div>
<div class="tab-pane fade" id="portfolio-risk" role="tabpanel" aria-labelledby="portfolio-risk-tab">
<div class="alert alert-info">
<i class="fas fa-info-circle"></i> 分析投资组合的整体风险,识别高风险股票和风险集中度。
</div>
<button id="analyze-portfolio-btn" class="btn btn-primary btn-sm">
<i class="fas fa-briefcase"></i> 分析我的投资组合
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="loading-panel" class="text-center py-5" style="display: none;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3 mb-0">正在分析风险,请稍候...</p>
</div>
<!-- 个股风险分析结果 -->
<div id="stock-risk-result" style="display: none;">
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2 d-flex justify-content-between align-items-center">
<h5 class="mb-0">风险概览</h5>
<span id="risk-level-badge" class="badge"></span>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-7">
<h3 id="stock-name" class="mb-0 fs-4"></h3>
<p id="stock-info" class="text-muted mb-0 small"></p>
</div>
<div class="col-md-5 text-end">
<div id="risk-gauge-chart" style="height: 120px;"></div>
</div>
</div>
<div class="row">
<div class="col-12">
<h6>风险预警</h6>
<div id="risk-alerts" class="mt-2">
<!-- 风险预警内容将在JS中动态填充 -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">风险构成</h5>
</div>
<div class="card-body">
<div id="risk-radar-chart" style="height: 220px;"></div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">波动率风险</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6>波动率指标</h6>
<p><span class="text-muted">当前波动率:</span> <span id="current-volatility" class="fw-bold"></span></p>
<p><span class="text-muted">变化率:</span> <span id="volatility-change" class="fw-bold"></span></p>
<p><span class="text-muted">风险等级:</span> <span id="volatility-risk-level" class="fw-bold"></span></p>
<p class="small text-muted" id="volatility-comment"></p>
</div>
<div class="col-md-6">
<div id="volatility-chart" style="height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">趋势风险</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6>趋势指标</h6>
<p><span class="text-muted">当前趋势:</span> <span id="current-trend" class="fw-bold"></span></p>
<p><span class="text-muted">均线关系:</span> <span id="ma-relationship" class="fw-bold"></span></p>
<p><span class="text-muted">风险等级:</span> <span id="trend-risk-level" class="fw-bold"></span></p>
<p class="small text-muted" id="trend-comment"></p>
</div>
<div class="col-md-6">
<div id="trend-chart" style="height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">反转风险</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6>反转信号</h6>
<p><span class="text-muted">反转信号数:</span> <span id="reversal-signals" class="fw-bold"></span></p>
<p><span class="text-muted">可能方向:</span> <span id="reversal-direction" class="fw-bold"></span></p>
<p><span class="text-muted">风险等级:</span> <span id="reversal-risk-level" class="fw-bold"></span></p>
<p class="small text-muted" id="reversal-comment"></p>
</div>
<div class="col-md-6">
<div id="reversal-chart" style="height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">成交量风险</h5>
</div>
<div class="card-body">
<div class="row">
<div class="col-md-6">
<h6>成交量指标</h6>
<p><span class="text-muted">成交量比率:</span> <span id="volume-ratio" class="fw-bold"></span></p>
<p><span class="text-muted">成交量模式:</span> <span id="volume-pattern" class="fw-bold"></span></p>
<p><span class="text-muted">风险等级:</span> <span id="volume-risk-level" class="fw-bold"></span></p>
<p class="small text-muted" id="volume-comment"></p>
</div>
<div class="col-md-6">
<div id="volume-chart" style="height: 150px;"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- 投资组合风险分析结果 -->
<div id="portfolio-risk-result" style="display: none;">
<div class="row g-3 mb-3">
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2 d-flex justify-content-between align-items-center">
<h5 class="mb-0">组合风险概览</h5>
<span id="portfolio-risk-level-badge" class="badge"></span>
</div>
<div class="card-body">
<div class="row mb-3">
<div class="col-md-7">
<h3 class="mb-0 fs-4">我的投资组合</h3>
<p class="text-muted mb-0 small">包含 <span id="portfolio-stock-count">0</span> 只股票</p>
</div>
<div class="col-md-5 text-end">
<div id="portfolio-risk-gauge-chart" style="height: 120px;"></div>
</div>
</div>
<div class="row">
<div class="col-12">
<h6>风险集中度</h6>
<p><span class="text-muted">行业集中度:</span> <span id="industry-concentration" class="fw-bold"></span></p>
<p><span class="text-muted">高风险股票占比:</span> <span id="high-risk-concentration" class="fw-bold"></span></p>
<div id="portfolio-risk-alerts" class="mt-2">
<!-- 风险预警内容将在JS中动态填充 -->
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card h-100">
<div class="card-header py-2">
<h5 class="mb-0">行业分布</h5>
</div>
<div class="card-body">
<div id="industry-distribution-chart" style="height: 220px;"></div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-12">
<div class="card">
<div class="card-header py-2">
<h5 class="mb-0">高风险股票</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-sm table-striped table-hover mb-0">
<thead>
<tr>
<th>代码</th>
<th>名称</th>
<th>风险评分</th>
<th>风险等级</th>
<th>权重</th>
<th>主要风险</th>
<th>操作</th>
</tr>
</thead>
<tbody id="high-risk-stocks-table">
<!-- 高风险股票列表将在JS中动态填充 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
<div class="row g-3 mb-3">
<div class="col-12">
<div class="card">
<div class="card-header py-2">
<h5 class="mb-0">风险预警列表</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-sm table-striped table-hover mb-0">
<thead>
<tr>
<th>代码</th>
<th>名称</th>
<th>预警类型</th>
<th>风险等级</th>
<th>预警信息</th>
</tr>
</thead>
<tbody id="risk-alerts-table">
<!-- 风险预警列表将在JS中动态填充 -->
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<script>
$(document).ready(function() {
// 个股风险分析表单提交
$('#stock-risk-form').submit(function(e) {
e.preventDefault();
const stockCode = $('#stock-code').val().trim();
const marketType = $('#market-type').val();
if (!stockCode) {
showError('请输入股票代码!');
return;
}
analyzeStockRisk(stockCode, marketType);
});
// 分析投资组合风险按钮点击
$('#analyze-portfolio-btn').click(function() {
analyzePortfolioRisk();
});
});
function analyzeStockRisk(stockCode, marketType) {
$('#loading-panel').show();
$('#stock-risk-result').hide();
$('#portfolio-risk-result').hide();
$.ajax({
url: '/api/risk_analysis',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
stock_code: stockCode,
market_type: marketType
}),
success: function(response) {
$('#loading-panel').hide();
renderStockRiskAnalysis(response, stockCode);
$('#stock-risk-result').show();
},
error: function(xhr, status, error) {
$('#loading-panel').hide();
let errorMsg = '获取风险分析数据失败';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg += ': ' + xhr.responseJSON.error;
} else if (error) {
errorMsg += ': ' + error;
}
showError(errorMsg);
}
});
}
function analyzePortfolioRisk() {
// 尝试从本地存储获取投资组合数据
const savedPortfolio = localStorage.getItem('portfolio');
if (!savedPortfolio) {
showError('您的投资组合为空,请先添加股票到投资组合');
return;
}
const portfolio = JSON.parse(savedPortfolio);
if (portfolio.length === 0) {
showError('您的投资组合为空,请先添加股票到投资组合');
return;
}
$('#loading-panel').show();
$('#stock-risk-result').hide();
$('#portfolio-risk-result').hide();
$.ajax({
url: '/api/portfolio_risk',
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
portfolio: portfolio
}),
success: function(response) {
$('#loading-panel').hide();
renderPortfolioRiskAnalysis(response, portfolio);
$('#portfolio-risk-result').show();
},
error: function(xhr, status, error) {
$('#loading-panel').hide();
let errorMsg = '获取投资组合风险分析数据失败';
if (xhr.responseJSON && xhr.responseJSON.error) {
errorMsg += ': ' + xhr.responseJSON.error;
} else if (error) {
errorMsg += ': ' + error;
}
showError(errorMsg);
}
});
}
function renderStockRiskAnalysis(data, stockCode) {
// 设置基本信息
$('#stock-name').text(data.stock_name || stockCode);
$('#stock-info').text(data.industry || '未知行业');
// 设置风险等级
const riskScore = data.total_risk_score || 0;
const riskLevel = data.risk_level || '未知';
const riskLevelBadgeClass = getRiskLevelBadgeClass(riskLevel);
$('#risk-level-badge').text(riskLevel).removeClass().addClass(`badge ${riskLevelBadgeClass}`);
// 设置风险预警
renderRiskAlerts(data.alerts || []);
// 渲染风险仪表图
renderRiskGaugeChart(riskScore);
// 渲染风险雷达图
renderRiskRadarChart(data);
// 设置波动率风险
const volatilityRisk = data.volatility_risk || {};
$('#current-volatility').text(formatPercent(volatilityRisk.value || 0, 2));
const volatilityChange = volatilityRisk.change || 0;
const volatilityChangeClass = volatilityChange >= 0 ? 'trend-up' : 'trend-down';
$('#volatility-change').text(formatPercent(volatilityChange, 2)).addClass(volatilityChangeClass);
$('#volatility-risk-level').text(volatilityRisk.risk_level || '未知');
$('#volatility-comment').text('波动率反映价格波动的剧烈程度,高波动率意味着高风险');
// 设置趋势风险
const trendRisk = data.trend_risk || {};
$('#current-trend').text(trendRisk.trend || '未知');
$('#ma-relationship').text(trendRisk.ma_relationship || '未知');
$('#trend-risk-level').text(trendRisk.risk_level || '未知');
$('#trend-comment').text('下降趋势中的股票有更高的风险,特别是在空头排列时');
// 设置反转风险
const reversalRisk = data.reversal_risk || {};
$('#reversal-signals').text(reversalRisk.reversal_signals || 0);
$('#reversal-direction').text(reversalRisk.direction || '未知');
$('#reversal-risk-level').text(reversalRisk.risk_level || '未知');
$('#reversal-comment').text('多个技术指标同时出现反转信号,意味着趋势可能即将改变');
// 设置成交量风险
const volumeRisk = data.volume_risk || {};
$('#volume-ratio').text(formatNumber(volumeRisk.volume_ratio || 0, 2));
$('#volume-pattern').text(volumeRisk.pattern || '未知');
$('#volume-risk-level').text(volumeRisk.risk_level || '未知');
$('#volume-comment').text('成交量异常变化常常预示价格波动,尤其是量价背离时');
// 渲染各个风险维度的图表
renderVolatilityChart([5.2, 3.8, 4.5, 7.2, 6.3]);
renderTrendChart([110, 108, 106, 102, 98]);
renderReversalChart([55, 60, 65, 72, 68]);
renderVolumeChart([1.2, 0.8, 1.5, 2.8, 2.1]);
}
function renderPortfolioRiskAnalysis(data, portfolio) {
// 设置基本信息
$('#portfolio-stock-count').text(portfolio.length);
// 设置风险等级
const riskScore = data.portfolio_risk_score || 0;
const riskLevel = data.risk_level || '未知';
const riskLevelBadgeClass = getRiskLevelBadgeClass(riskLevel);
$('#portfolio-risk-level-badge').text(riskLevel).removeClass().addClass(`badge ${riskLevelBadgeClass}`);
// 设置风险集中度
const riskConcentration = data.risk_concentration || {};
$('#industry-concentration').text(`${riskConcentration.max_industry || '未知'} (${formatPercent(riskConcentration.max_industry_weight || 0, 1)})`);
$('#high-risk-concentration').text(formatPercent(riskConcentration.high_risk_weight || 0, 1));
// 设置风险预警
renderPortfolioRiskAlerts(data.alerts || []);
// 渲染投资组合风险仪表图
renderPortfolioRiskGaugeChart(riskScore);
// 渲染行业分布图
renderIndustryDistributionChart(portfolio);
// 渲染高风险股票列表
renderHighRiskStocksTable(data.high_risk_stocks || []);
// 渲染风险预警列表
renderRiskAlertsTable(data.alerts || []);
}
function renderRiskAlerts(alerts) {
let html = '';
if (alerts.length === 0) {
html = '<div class="alert alert-success">未发现显著风险因素</div>';
} else {
alerts.forEach(alert => {
const alertClass = getRiskAlertClass(alert.level);
html += `
<div class="alert ${alertClass} mb-2">
<strong>${alert.type}风险:</strong> ${alert.message}
</div>
`;
});
}
$('#risk-alerts').html(html);
}
function renderPortfolioRiskAlerts(alerts) {
let html = '';
if (alerts.length === 0) {
html = '<div class="alert alert-success">投资组合风险均衡,未发现显著风险集中</div>';
} else {
let alertCount = 0;
alerts.forEach(alert => {
if (alertCount < 3) { // 只显示前3条
const alertClass = getRiskAlertClass(alert.level);
html += `
<div class="alert ${alertClass} mb-2">
<strong>${alert.stock_code}:</strong> ${alert.message}
</div>
`;
alertCount++;
}
});
if (alerts.length > 3) {
html += `<p class="text-muted small">还有 ${alerts.length - 3} 条风险预警,请查看下方详情表格</p>`;
}
}
$('#portfolio-risk-alerts').html(html);
}
function renderRiskGaugeChart(score) {
const options = {
series: [score],
chart: {
height: 120,
type: 'radialBar',
},
plotOptions: {
radialBar: {
hollow: {
size: '70%',
},
dataLabels: {
show: true,
name: {
show: false
},
value: {
fontSize: '16px',
fontWeight: 'bold',
offsetY: 5
}
},
track: {
background: '#f2f2f2'
}
}
},
fill: {
colors: [getRiskColor(score)]
},
labels: ['风险分数']
};
const chart = new ApexCharts(document.querySelector("#risk-gauge-chart"), options);
chart.render();
}
function renderPortfolioRiskGaugeChart(score) {
const options = {
series: [score],
chart: {
height: 120,
type: 'radialBar',
},
plotOptions: {
radialBar: {
hollow: {
size: '70%',
},
dataLabels: {
show: true,
name: {
show: false
},
value: {
fontSize: '16px',
fontWeight: 'bold',
offsetY: 5
}
},
track: {
background: '#f2f2f2'
}
}
},
fill: {
colors: [getRiskColor(score)]
},
labels: ['风险分数']
};
const chart = new ApexCharts(document.querySelector("#portfolio-risk-gauge-chart"), options);
chart.render();
}
function renderRiskRadarChart(data) {
const volatilityRisk = data.volatility_risk?.score || 0;
const trendRisk = data.trend_risk?.score || 0;
const reversalRisk = data.reversal_risk?.score || 0;
const volumeRisk = data.volume_risk?.score || 0;
const options = {
series: [{
name: '风险评分',
data: [volatilityRisk, trendRisk, reversalRisk, volumeRisk]
}],
chart: {
height: 220,
type: 'radar',
toolbar: {
show: false
}
},
xaxis: {
categories: ['波动率风险', '趋势风险', '反转风险', '成交量风险']
},
fill: {
opacity: 0.7,
colors: ['#dc3545']
},
markers: {
size: 4
},
title: {
text: '风险雷达图',
align: 'center',
style: {
fontSize: '14px'
}
}
};
const chart = new ApexCharts(document.querySelector("#risk-radar-chart"), options);
chart.render();
}
function renderIndustryDistributionChart(portfolio) {
// 根据投资组合计算行业分布
const industries = {};
let totalWeight = 0;
portfolio.forEach(stock => {
const industry = stock.industry || '未知';
const weight = stock.weight || 1;
if (industries[industry]) {
industries[industry] += weight;
} else {
industries[industry] = weight;
}
totalWeight += weight;
});
const series = [];
const labels = [];
for (const industry in industries) {
if (industries.hasOwnProperty(industry)) {
series.push(industries[industry]);
labels.push(industry);
}
}
const options = {
series: series,
chart: {
height: 220,
type: 'pie',
},
labels: labels,
colors: ['#4e73df', '#1cc88a', '#36b9cc', '#f6c23e', '#e74a3b', '#858796', '#5a5c69', '#6f42c1'],
legend: {
position: 'bottom'
},
tooltip: {
y: {
formatter: function(value) {
return value + ' (' + ((value / totalWeight) * 100).toFixed(1) + '%)';
}
}
}
};
const chart = new ApexCharts(document.querySelector("#industry-distribution-chart"), options);
chart.render();
}
function renderVolatilityChart(data) {
const options = {
series: [{
name: '波动率(%)',
data: data
}],
chart: {
height: 150,
type: 'line',
toolbar: {
show: false
}
},
stroke: {
curve: 'smooth',
width: 3
},
xaxis: {
labels: {
show: false
}
},
yaxis: {
labels: {
formatter: function(val) {
return val.toFixed(1) + '%';
},
style: {
fontSize: '10px'
}
}
},
colors: ['#dc3545'],
tooltip: {
y: {
formatter: function(value) {
return value.toFixed(2) + '%';
}
}
},
markers: {
size: 3
}
};
const chart = new ApexCharts(document.querySelector("#volatility-chart"), options);
chart.render();
}
function renderTrendChart(data) {
const options = {
series: [{
name: '价格',
data: data
}, {
name: 'MA20',
data: [109, 107, 105, 103, 101]
}],
chart: {
height: 150,
type: 'line',
toolbar: {
show: false
}
},
stroke: {
curve: 'straight',
width: [3, 2]
},
xaxis: {
labels: {
show: false
}
},
yaxis: {
labels: {
formatter: function(val) {
return val.toFixed(0);
},
style: {
fontSize: '10px'
}
}
},
colors: ['#dc3545', '#007bff'],
tooltip: {
y: {
formatter: function(value) {
return value.toFixed(2);
}
}
},
markers: {
size: 3
},
legend: {
show: false
}
};
const chart = new ApexCharts(document.querySelector("#trend-chart"), options);
chart.render();
}
function renderReversalChart(data) {
const options = {
series: [{
name: 'RSI',
data: data
}],
chart: {
height: 150,
type: 'line',
toolbar: {
show: false
}
},
stroke: {
curve: 'smooth',
width: 3
},
xaxis: {
labels: {
show: false
}
},
yaxis: {
min: 0,
max: 100,
labels: {
formatter: function(val) {
return val.toFixed(0);
},
style: {
fontSize: '10px'
}
}
},
colors: ['#ffc107'],
tooltip: {
y: {
formatter: function(value) {
return value.toFixed(2);
}
}
},
markers: {
size: 3
},
annotations: {
yaxis: [{
y: 70,
borderColor: '#dc3545',
label: {
text: '超买',
style: {
color: '#fff',
background: '#dc3545'
}
}
}, {
y: 30,
borderColor: '#28a745',
label: {
text: '超卖',
style: {
color: '#fff',
background: '#28a745'
}
}
}]
}
};
const chart = new ApexCharts(document.querySelector("#reversal-chart"), options);
chart.render();
}
function renderVolumeChart(data) {
const options = {
series: [{
name: '成交量比率',
data: data
}],
chart: {
height: 150,
type: 'bar',
toolbar: {
show: false
}
},
xaxis: {
labels: {
show: false
}
},
yaxis: {
labels: {
formatter: function(val) {
return val.toFixed(1) + 'x';
},
style: {
fontSize: '10px'
}
}
},
colors: ['#4e73df'],
tooltip: {
y: {
formatter: function(value) {
return value.toFixed(2) + 'x';
}
}
},
plotOptions: {
bar: {
columnWidth: '50%'
}
},
dataLabels: {
enabled: false
}
};
const chart = new ApexCharts(document.querySelector("#volume-chart"), options);
chart.render();
}
function renderHighRiskStocksTable(highRiskStocks) {
let html = '';
if (highRiskStocks.length === 0) {
html = '<tr><td colspan="7" class="text-center">未发现高风险股票</td></tr>';
} else {
highRiskStocks.forEach(stock => {
const riskScoreClass = getRiskScoreClass(stock.risk_score);
const riskLevelBadgeClass = getRiskLevelBadgeClass(stock.risk_level);
html += `
<tr>
<td>${stock.stock_code}</td>
<td>${stock.stock_name || '未知'}</td>
<td><span class="badge ${riskScoreClass}">${stock.risk_score}</span></td>
<td><span class="badge ${riskLevelBadgeClass}">${stock.risk_level}</span></td>
<td>${formatPercent(stock.weight || 0, 1)}</td>
<td>${stock.main_risk || '未知'}</td>
<td>
<a href="/stock_detail/${stock.stock_code}" class="btn btn-sm btn-outline-info me-1">
<i class="fas fa-chart-line"></i>
</a>
<a href="/risk_monitor?stock=${stock.stock_code}" class="btn btn-sm btn-outline-danger">
<i class="fas fa-exclamation-triangle"></i>
</a>
</td>
</tr>
`;
});
}
$('#high-risk-stocks-table').html(html);
}
function renderRiskAlertsTable(alerts) {
let html = '';
if (alerts.length === 0) {
html = '<tr><td colspan="5" class="text-center">暂无风险预警</td></tr>';
} else {
alerts.forEach(alert => {
const riskLevelBadgeClass = getRiskLevelBadgeClass(alert.level);
html += `
<tr>
<td>${alert.stock_code}</td>
<td>${alert.stock_name || '未知'}</td>
<td>${alert.type}</td>
<td><span class="badge ${riskLevelBadgeClass}">${alert.level}</span></td>
<td>${alert.message}</td>
</tr>
`;
});
}
$('#risk-alerts-table').html(html);
}
function getRiskLevelBadgeClass(level) {
switch (level) {
case '极高':
return 'bg-danger';
case '高':
return 'bg-warning text-dark';
case '中等':
return 'bg-info text-dark';
case '低':
return 'bg-success';
case '极低':
return 'bg-secondary';
default:
return 'bg-secondary';
}
}
function getRiskAlertClass(level) {
switch (level) {
case '高':
return 'alert-danger';
case '中':
return 'alert-warning';
case '低':
return 'alert-info';
default:
return 'alert-secondary';
}
}
function getRiskScoreClass(score) {
if (score >= 80) return 'bg-danger';
if (score >= 60) return 'bg-warning text-dark';
if (score >= 40) return 'bg-info text-dark';
return 'bg-success';
}
function getRiskColor(score) {
if (score >= 80) return '#dc3545'; // 红色
if (score >= 60) return '#ffc107'; // 黄色
if (score >= 40) return '#17a2b8'; // 蓝色
return '#28a745'; // 绿色
}
</script>
{% endblock %}