摘要
随着金融科技的快速发展,银行业对企业信用风险的实时监测需求日益迫切。本文将深入探讨如何构建一个专业的金融风控大数据可视化系统,涵盖信用评级展示、风险指标监控、实时数据更新等核心功能。通过实际案例分析和完整的代码实现,帮助开发者掌握金融领域数据可视化的关键技术和最佳实践。
关键词: 金融风控、信用风险、数据可视化、银行系统、实时监控
目录
1. 引言
在当今数字化金融时代,银行业面临着日益复杂的信用风险管理挑战。传统的风险评估方法已无法满足实时性、准确性和全面性的要求。大数据可视化技术为金融风控提供了新的解决方案,能够帮助银行实时监控企业信用状况,及时识别潜在风险,提高决策效率。
1.1 金融风控的挑战
现代银行业在信用风险管理中面临以下主要挑战:
1.2 可视化解决方案的价值
大数据可视化在金融风控中的核心价值:
- 直观展示:将复杂的财务数据转化为易理解的图表
- 实时监控:提供企业信用状况的实时监测
- 风险预警:通过可视化指标及时发现潜在风险
- 决策支持:为信贷决策提供数据支撑
- 合规管理:满足监管部门的报告要求
2. 金融风控可视化系统概述
2.1 系统功能架构
# 金融风控可视化系统功能模块
class FinancialRiskVisualizationSystem:
"""金融风控可视化系统"""
def __init__(self):
self.modules = self.define_system_modules()
self.risk_indicators = self.define_risk_indicators()
self.credit_ratings = self.define_credit_ratings()
def define_system_modules(self):
"""定义系统功能模块"""
return {
"信用评级管理": {
"描述": "企业信用等级分类和展示",
"功能": [
"信用等级分类展示",
"企业信用评级查询",
"评级变化趋势分析",
"同行业对比分析"
],
"技术要点": [
"分级数据展示",
"动态表格渲染",
"筛选和排序功能",
"数据钻取分析"
]
},
"风险指标监控": {
"描述": "关键风险指标的实时监控",
"功能": [
"盈利能力指标监控",
"流动性指标分析",
"偿债能力评估",
"风险预警机制"
],
"技术要点": [
"实时数据更新",
"阈值监控告警",
"趋势图表展示",
"多维度分析"
]
},
"企业画像分析": {
"描述": "企业综合信息可视化展示",
"功能": [
"企业基本信息展示",
"财务状况分析",
"经营风险评估",
"关联关系分析"
],
"技术要点": [
"多维数据整合",
"关系图谱展示",
"交互式分析",
"详情页面设计"
]
},
"风险报告生成": {
"描述": "自动化风险评估报告生成",
"功能": [
"风险评估报告",
"监管合规报告",
"定期分析报告",
"自定义报告模板"
],
"技术要点": [
"报告模板设计",
"数据自动填充",
"图表自动生成",
"PDF导出功能"
]
}
}
def define_risk_indicators(self):
"""定义风险指标体系"""
return {
"盈利能力指标": {
"盈利对利息覆盖能力": {
"计算公式": "息税前利润 / 利息费用",
"风险阈值": {"优秀": ">5.0", "良好": "3.0-5.0", "一般": "1.5-3.0", "风险": "<1.5"},
"权重": 0.3
},
"净资产收益率": {
"计算公式": "净利润 / 平均净资产",
"风险阈值": {"优秀": ">15%", "良好": "10%-15%", "一般": "5%-10%", "风险": "<5%"},
"权重": 0.25
}
},
"流动性指标": {
"流动性还本付息能力": {
"计算公式": "流动资产 / 流动负债",
"风险阈值": {"优秀": ">2.0", "良好": "1.5-2.0", "一般": "1.0-1.5", "风险": "<1.0"},
"权重": 0.25
},
"速动比率": {
"计算公式": "(流动资产-存货) / 流动负债",
"风险阈值": {"优秀": ">1.5", "良好": "1.0-1.5", "一般": "0.8-1.0", "风险": "<0.8"},
"权重": 0.2
}
},
"偿债能力指标": {
"清偿性还本付息能力": {
"计算公式": "总资产 / 总负债",
"风险阈值": {"优秀": ">3.0", "良好": "2.0-3.0", "一般": "1.5-2.0", "风险": "<1.5"},
"权重": 0.3
},
"资产负债率": {
"计算公式": "总负债 / 总资产",
"风险阈值": {"优秀": "<40%", "良好": "40%-60%", "一般": "60%-80%", "风险": ">80%"},
"权重": 0.25
}
}
}
def define_credit_ratings(self):
"""定义信用评级体系"""
return {
"AAA": {
"描述": "信用质量极高,违约风险极低",
"评分范围": "90-100",
"风险等级": "极低",
"颜色标识": "#00ff88",
"特征": [
"财务状况优异",
"盈利能力强",
"现金流充足",
"行业地位领先"
]
},
"AA+": {
"描述": "信用质量很高,违约风险很低",
"评分范围": "85-89",
"风险等级": "很低",
"颜色标识": "#00d4ff",
"特征": [
"财务状况良好",
"盈利稳定",
"偿债能力强",
"经营风险可控"
]
},
"AA": {
"描述": "信用质量高,违约风险低",
"评分范围": "80-84",
"风险等级": "低",
"颜色标识": "#ffd93d",
"特征": [
"财务状况稳健",
"业务发展稳定",
"风险管理完善",
"市场竞争力强"
]
},
"AA-及以下": {
"描述": "信用质量中等,存在一定违约风险",
"评分范围": "<80",
"风险等级": "中等及以上",
"颜色标识": "#ff6b6b",
"特征": [
"财务状况一般",
"盈利波动较大",
"偿债压力增加",
"需要密切关注"
]
}
}
def calculate_comprehensive_score(self, financial_data):
"""计算企业综合信用评分"""
total_score = 0
total_weight = 0
for category, indicators in self.risk_indicators.items():
for indicator_name, indicator_info in indicators.items():
if indicator_name in financial_data:
value = financial_data[indicator_name]
score = self.calculate_indicator_score(value, indicator_info)
weight = indicator_info['权重']
total_score += score * weight
total_weight += weight
if total_weight > 0:
final_score = total_score / total_weight * 100
return min(100, max(0, final_score))
return 0
def calculate_indicator_score(self, value, indicator_info):
"""计算单个指标得分"""
thresholds = indicator_info['风险阈值']
# 简化的评分逻辑,实际应用中需要更复杂的算法
if self.meets_threshold(value, thresholds['优秀']):
return 95
elif self.meets_threshold(value, thresholds['良好']):
return 80
elif self.meets_threshold(value, thresholds['一般']):
return 65
else:
return 40
def meets_threshold(self, value, threshold_str):
"""检查是否满足阈值条件"""
# 简化的阈值检查逻辑
if '>' in threshold_str:
threshold = float(threshold_str.replace('>', ''))
return value > threshold
elif '<' in threshold_str:
threshold = float(threshold_str.replace('<', '').replace('%', ''))
return value < threshold
elif '-' in threshold_str:
parts = threshold_str.split('-')
min_val = float(parts[0])
max_val = float(parts[1].replace('%', ''))
return min_val <= value <= max_val
return False
def get_credit_rating(self, score):
"""根据评分获取信用等级"""
if score >= 90:
return "AAA"
elif score >= 85:
return "AA+"
elif score >= 80:
return "AA"
else:
return "AA-及以下"
def print_system_overview(self):
"""打印系统概述"""
print("=== 金融风控可视化系统概述 ===\n")
print("📊 系统功能模块:")
for module_name, module_info in self.modules.items():
print(f"\n🔹 {module_name}")
print(f" 描述: {module_info['描述']}")
print(f" 主要功能:")
for func in module_info['功能']:
print(f" • {func}")
print(f" 技术要点:")
for tech in module_info['技术要点']:
print(f" ◦ {tech}")
print(f"\n📈 风险指标体系:")
for category, indicators in self.risk_indicators.items():
print(f"\n🔸 {category}:")
for indicator, info in indicators.items():
print(f" • {indicator}")
print(f" 计算公式: {info['计算公式']}")
print(f" 权重: {info['权重']}")
print(f"\n🏆 信用评级体系:")
for rating, info in self.credit_ratings.items():
print(f"\n⭐ {rating} - {info['描述']}")
print(f" 评分范围: {info['评分范围']}")
print(f" 风险等级: {info['风险等级']}")
# 创建系统实例并展示概述
risk_system = FinancialRiskVisualizationSystem()
risk_system.print_system_overview()
# 示例:计算企业信用评分
sample_data = {
"盈利对利息覆盖能力": 5.61,
"流动性还本付息能力": 5.76,
"清偿性还本付息能力": 1.87
}
score = risk_system.calculate_comprehensive_score(sample_data)
rating = risk_system.get_credit_rating(score)
print(f"\n📊 示例企业评估结果:")
print(f" 综合评分: {score:.2f}")
print(f" 信用等级: {rating}")
2.2 系统特点与优势
特点 | 描述 | 业务价值 |
---|---|---|
实时监控 | 7×24小时实时监控企业信用状况 | 及时发现风险变化,降低损失 |
多维分析 | 从多个维度分析企业信用风险 | 全面评估,提高决策准确性 |
智能预警 | 基于阈值的自动预警机制 | 主动风险管理,提前防范 |
可视化展示 | 直观的图表和仪表板展示 | 提高信息理解效率 |
合规支持 | 满足监管要求的报告功能 | 降低合规风险和成本 |
3. 系统架构设计
3.1 技术架构
3.2 前端技术选型
/**
* 金融风控前端技术栈配置
*/
class FinancialRiskFrontendStack {
constructor() {
this.techStack = this.defineTechStack();
this.securityRequirements = this.defineSecurityRequirements();
}
defineTechStack() {
return {
"核心框架": {
"HTML5": {
"版本": "HTML5",
"用途": "页面结构和语义化",
"特性": ["语义化标签", "表单验证", "本地存储"]
},
"CSS3": {
"版本": "CSS3",
"用途": "样式设计和动画",
"特性": ["Flexbox布局", "Grid布局", "动画效果"]
},
"JavaScript": {
"版本": "ES6+",
"用途": "交互逻辑和数据处理",
"特性": ["模块化", "异步处理", "类和继承"]
}
},
"可视化库": {
"ECharts": {
"版本": "5.4.0+",
"用途": "图表绘制和数据可视化",
"优势": ["丰富的图表类型", "良好的性能", "移动端支持"]
},
"D3.js": {
"版本": "7.0+",
"用途": "自定义可视化和复杂图表",
"优势": ["高度定制化", "强大的数据绑定", "丰富的API"]
}
},
"UI框架": {
"Bootstrap": {
"版本": "5.1+",
"用途": "响应式布局和组件",
"优势": ["快速开发", "移动优先", "丰富组件"]
},
"Element UI": {
"版本": "2.15+",
"用途": "企业级UI组件",
"优势": ["专业外观", "完整组件", "Vue生态"]
}
},
"工具库": {
"jQuery": {
"版本": "3.6+",
"用途": "DOM操作和事件处理",
"优势": ["简化开发", "兼容性好", "丰富插件"]
},
"Moment.js": {
"版本": "2.29+",
"用途": "日期时间处理",
"优势": ["强大的日期API", "国际化支持", "时区处理"]
},
"Lodash": {
"版本": "4.17+",
"用途": "实用工具函数",
"优势": ["性能优化", "函数式编程", "模块化"]
}
}
};
}
defineSecurityRequirements() {
return {
"数据安全": [
"HTTPS传输加密",
"敏感数据脱敏",
"前端数据验证",
"XSS攻击防护"
],
"访问控制": [
"用户身份认证",
"权限级别控制",
"会话管理",
"操作日志记录"
],
"合规要求": [
"数据保护法规遵循",
"金融监管要求",
"审计追踪功能",
"数据备份恢复"
]
};
}
generateProjectStructure() {
return {
"项目结构": {
"index.html": "主页面入口",
"css/": {
"index.css": "主样式文件",
"components.css": "组件样式",
"themes.css": "主题样式"
},
"js/": {
"main.js": "主要业务逻辑",
"risk-analysis.js": "风险分析模块",
"data-processor.js": "数据处理模块",
"chart-manager.js": "图表管理模块",
"security.js": "安全控制模块"
},
"libs/": {
"echarts.min.js": "ECharts图表库",
"jquery.min.js": "jQuery库",
"moment.min.js": "日期处理库"
},
"data/": {
"mock-data.json": "模拟数据",
"config.json": "配置文件"
},
"images/": "图片资源",
"fonts/": "字体文件"
}
};
}
printTechStack() {
console.log("=== 金融风控前端技术栈 ===\n");
for (const [category, technologies] of Object.entries(this.techStack)) {
console.log(`📚 ${category}:`);
for (const [tech, info] of Object.entries(technologies)) {
console.log(` 🔹 ${tech} (${info.版本})`);
console.log(` 用途: ${info.用途}`);
if (info.特性) {
console.log(` 特性: ${info.特性.join(', ')}`);
}
if (info.优势) {
console.log(` 优势: ${info.优势.join(', ')}`);
}
}
console.log();
}
console.log("🔒 安全要求:");
for (const [category, requirements] of Object.entries(this.securityRequirements)) {
console.log(` ${category}:`);
requirements.forEach(req => console.log(` • ${req}`));
}
}
}
// 创建技术栈实例
const frontendStack = new FinancialRiskFrontendStack();
frontendStack.printTechStack();
4. 核心功能模块开发
4.1 企业信用评级展示模块
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>银行企业信用风险监测平台</title>
<link rel="stylesheet" href="css/index.css">
<style>
/* 信用评级展示样式 */
.credit-rating-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
padding: 20px;
background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
min-height: 100vh;
}
.rating-panel {
background: rgba(255, 255, 255, 0.1);
border-radius: 12px;
padding: 20px;
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
transition: all 0.3s ease;
}
.rating-panel:hover {
transform: translateY(-5px);
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
}
.rating-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 2px solid rgba(255, 255, 255, 0.2);
}
.rating-title {
font-size: 24px;
font-weight: 600;
color: #ffffff;
margin: 0;
}
.rating-badge {
padding: 8px 16px;
border-radius: 20px;
font-size: 14px;
font-weight: 500;
color: #000;
}
.rating-aaa { background: linear-gradient(45deg, #00ff88, #00d4ff); }
.rating-aa-plus { background: linear-gradient(45deg, #00d4ff, #6c5ce7); }
.rating-aa { background: linear-gradient(45deg, #ffd93d, #ff9ff3); }
.rating-aa-minus { background: linear-gradient(45deg, #ff6b6b, #ffa726); }
.company-table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
.company-table th {
background: rgba(0, 0, 0, 0.3);
color: #ffffff;
padding: 12px 8px;
text-align: left;
font-size: 12px;
font-weight: 500;
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}
.company-table td {
padding: 10px 8px;
color: #e0e0e0;
font-size: 11px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
cursor: pointer;
transition: background-color 0.2s ease;
}
.company-table tr:hover {
background: rgba(255, 255, 255, 0.1);
}
.risk-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 5px;
}
.risk-low { background: #00ff88; }
.risk-medium { background: #ffd93d; }
.risk-high { background: #ff6b6b; }
/* 响应式设计 */
@media (max-width: 768px) {
.credit-rating-container {
grid-template-columns: 1fr;
gap: 15px;
padding: 15px;
}
.rating-title {
font-size: 20px;
}
.company-table th,
.company-table td {
padding: 8px 4px;
font-size: 10px;
}
}
</style>
</head>
<body>
<!-- 页面头部 -->
<header class="header">
<div class="header-content">
<div class="time-display">
<span id="currentTime">2024-07-20 17:30:00</span>
</div>
<h1 class="system-title">信用风险定位系统(银行版)</h1>
<div class="user-info">
<span>管理员 <a href="#" onclick="logout()">[退出]</a></span>
</div>
</div>
</header>
<!-- 主标题 -->
<div class="main-title">
<h2>实时监测-企业名单</h2>
<div class="title-decoration"></div>
</div>
<!-- 信用评级展示区域 -->
<div class="credit-rating-container">
<!-- AAA级企业 -->
<div class="rating-panel">
<div class="rating-header">
<h3 class="rating-title">AAA</h3>
<span class="rating-badge rating-aaa">极低风险</span>
</div>
<table class="company-table">
<thead>
<tr>
<th>企业名称</th>
<th>盈利覆盖能力</th>
<th>流动性能力</th>
<th>清偿能力</th>
</tr>
</thead>
<tbody id="aaaCompanies">
<!-- 动态生成内容 -->
</tbody>
</table>
</div>
<!-- AA+级企业 -->
<div class="rating-panel">
<div class="rating-header">
<h3 class="rating-title">AA+</h3>
<span class="rating-badge rating-aa-plus">很低风险</span>
</div>
<table class="company-table">
<thead>
<tr>
<th>企业名称</th>
<th>盈利覆盖能力</th>
<th>流动性能力</th>
<th>清偿能力</th>
</tr>
</thead>
<tbody id="aaPlusCompanies">
<!-- 动态生成内容 -->
</tbody>
</table>
</div>
<!-- AA级企业 -->
<div class="rating-panel">
<div class="rating-header">
<h3 class="rating-title">AA</h3>
<span class="rating-badge rating-aa">低风险</span>
</div>
<table class="company-table">
<thead>
<tr>
<th>企业名称</th>
<th>盈利覆盖能力</th>
<th>流动性能力</th>
<th>清偿能力</th>
</tr>
</thead>
<tbody id="aaCompanies">
<!-- 动态生成内容 -->
</tbody>
</table>
</div>
<!-- AA-及以下级企业 -->
<div class="rating-panel">
<div class="rating-header">
<h3 class="rating-title">AA-及以下</h3>
<span class="rating-badge rating-aa-minus">中等风险</span>
</div>
<table class="company-table">
<thead>
<tr>
<th>企业名称</th>
<th>盈利覆盖能力</th>
<th>流动性能力</th>
<th>清偿能力</th>
</tr>
</thead>
<tbody id="aaMinusCompanies">
<!-- 动态生成内容 -->
</tbody>
</table>
</div>
</div>
<!-- 详情弹窗 -->
<div id="companyDetailModal" class="modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h3 id="modalCompanyName">企业详情</h3>
<span class="close" onclick="closeModal()">×</span>
</div>
<div class="modal-body" id="modalBody">
<!-- 动态生成详情内容 -->
</div>
</div>
</div>
<!-- JavaScript -->
<script src="libs/jquery.min.js"></script>
<script src="js/risk-analysis.js"></script>
</body>
</html>
4.2 风险分析JavaScript模块
/**
* 金融风控数据处理和可视化模块
*/
class FinancialRiskAnalyzer {
constructor() {
this.companies = [];
this.riskThresholds = this.initRiskThresholds();
this.updateInterval = 30000; // 30秒更新间隔
this.init();
}
/**
* 初始化风险阈值
*/
initRiskThresholds() {
return {
profitability: { excellent: 5.0, good: 3.0, fair: 1.5 },
liquidity: { excellent: 5.0, good: 3.0, fair: 1.5 },
solvency: { excellent: 3.0, good: 2.0, fair: 1.5 }
};
}
/**
* 初始化系统
*/
async init() {
try {
console.log('🚀 初始化金融风控分析系统...');
// 加载企业数据
await this.loadCompanyData();
// 渲染企业列表
this.renderCompanyLists();
// 启动实时更新
this.startRealTimeUpdate();
// 绑定事件
this.bindEvents();
// 更新时间显示
this.updateTimeDisplay();
console.log('✅ 系统初始化完成');
} catch (error) {
console.error('❌ 系统初始化失败:', error);
this.showErrorMessage('系统初始化失败,请刷新页面重试');
}
}
/**
* 加载企业数据
*/
async loadCompanyData() {
try {
// 模拟API调用,实际应用中替换为真实API
const response = await this.fetchMockData();
this.companies = response.companies || [];
// 计算风险评级
this.companies.forEach(company => {
company.riskRating = this.calculateRiskRating(company);
company.riskLevel = this.getRiskLevel(company);
});
console.log(`📊 加载了 ${this.companies.length} 家企业数据`);
} catch (error) {
console.error('数据加载失败:', error);
// 使用备用数据
this.companies = this.getBackupData();
}
}
/**
* 获取模拟数据
*/
async fetchMockData() {
// 模拟网络延迟
await new Promise(resolve => setTimeout(resolve, 500));
return {
companies: [
{
name: "鲁泰纺织股份有限公司",
profitCoverage: 5.61,
liquidityCapacity: 5.76,
solvencyCapacity: 1.87,
industry: "纺织业",
establishedYear: 1993,
registeredCapital: "8.5亿元"
},
{
name: "浙江森马服饰股份有限公司",
profitCoverage: 5.54,
liquidityCapacity: 5.78,
solvencyCapacity: 2.60,
industry: "服装业",
establishedYear: 1996,
registeredCapital: "12.3亿元"
},
{
name: "安正时尚集团股份有限公司",
profitCoverage: 5.58,
liquidityCapacity: 5.63,
solvencyCapacity: 1.56,
industry: "时尚服饰",
establishedYear: 1999,
registeredCapital: "6.8亿元"
},
{
name: "广东柏堡龙股份有限公司",
profitCoverage: 5.46,
liquidityCapacity: 5.56,
solvencyCapacity: 5.32,
industry: "服装设计",
establishedYear: 2003,
registeredCapital: "4.2亿元"
},
{
name: "深圳富安娜家居用品股份有限公司",
profitCoverage: 5.48,
liquidityCapacity: 5.60,
solvencyCapacity: 2.19,
industry: "家居用品",
establishedYear: 1994,
registeredCapital: "9.1亿元"
},
{
name: "比音勒芬服饰股份有限公司",
profitCoverage: 5.37,
liquidityCapacity: 5.54,
solvencyCapacity: 6.29,
industry: "高端服饰",
establishedYear: 2003,
registeredCapital: "3.6亿元"
},
{
name: "山东齐悦科技有限公司",
profitCoverage: 5.42,
liquidityCapacity: 5.43,
solvencyCapacity: 3.59,
industry: "科技服务",
establishedYear: 2015,
registeredCapital: "2.8亿元"
},
{
name: "深圳歌力思服饰股份有限公司",
profitCoverage: 5.43,
liquidityCapacity: 5.25,
solvencyCapacity: 1.69,
industry: "女装品牌",
establishedYear: 1996,
registeredCapital: "5.4亿元"
}
]
};
}
/**
* 计算企业风险评级
*/
calculateRiskRating(company) {
const { profitCoverage, liquidityCapacity, solvencyCapacity } = company;
// 计算各项指标得分
const profitScore = this.getIndicatorScore(profitCoverage, 'profitability');
const liquidityScore = this.getIndicatorScore(liquidityCapacity, 'liquidity');
const solvencyScore = this.getIndicatorScore(solvencyCapacity, 'solvency');
// 加权平均计算综合得分
const totalScore = (profitScore * 0.4 + liquidityScore * 0.3 + solvencyScore * 0.3);
return Math.round(totalScore);
}
/**
* 获取指标得分
*/
getIndicatorScore(value, type) {
const thresholds = this.riskThresholds[type];
if (value >= thresholds.excellent) {
return 95;
} else if (value >= thresholds.good) {
return 80;
} else if (value >= thresholds.fair) {
return 65;
} else {
return 40;
}
}
/**
* 获取风险等级
*/
getRiskLevel(company) {
const score = company.riskRating;
if (score >= 90) return 'AAA';
if (score >= 85) return 'AA+';
if (score >= 80) return 'AA';
return 'AA-及以下';
}
/**
* 渲染企业列表
*/
renderCompanyLists() {
const ratingGroups = {
'AAA': [],
'AA+': [],
'AA': [],
'AA-及以下': []
};
// 按评级分组
this.companies.forEach(company => {
const rating = company.riskLevel;
if (ratingGroups[rating]) {
ratingGroups[rating].push(company);
}
});
// 渲染各个评级组
this.renderRatingGroup('aaaCompanies', ratingGroups['AAA']);
this.renderRatingGroup('aaPlusCompanies', ratingGroups['AA+']);
this.renderRatingGroup('aaCompanies', ratingGroups['AA']);
this.renderRatingGroup('aaMinusCompanies', ratingGroups['AA-及以下']);
}
/**
* 渲染评级组
*/
renderRatingGroup(containerId, companies) {
const container = document.getElementById(containerId);
if (!container) return;
container.innerHTML = '';
companies.forEach(company => {
const row = document.createElement('tr');
row.innerHTML = `
<td>
<span class="risk-indicator ${this.getRiskIndicatorClass(company)}"></span>
${company.name}
</td>
<td>${company.profitCoverage.toFixed(2)}</td>
<td>${company.liquidityCapacity.toFixed(2)}</td>
<td>${company.solvencyCapacity.toFixed(2)}</td>
`;
// 添加点击事件
row.addEventListener('click', () => {
this.showCompanyDetail(company);
});
container.appendChild(row);
});
}
/**
* 获取风险指示器样式类
*/
getRiskIndicatorClass(company) {
const rating = company.riskLevel;
switch (rating) {
case 'AAA':
case 'AA+':
return 'risk-low';
case 'AA':
return 'risk-medium';
default:
return 'risk-high';
}
}
/**
* 显示企业详情
*/
showCompanyDetail(company) {
const modal = document.getElementById('companyDetailModal');
const modalTitle = document.getElementById('modalCompanyName');
const modalBody = document.getElementById('modalBody');
modalTitle.textContent = company.name;
modalBody.innerHTML = `
<div class="company-detail">
<div class="detail-section">
<h4>基本信息</h4>
<div class="detail-grid">
<div class="detail-item">
<label>企业名称:</label>
<span>${company.name}</span>
</div>
<div class="detail-item">
<label>所属行业:</label>
<span>${company.industry}</span>
</div>
<div class="detail-item">
<label>成立年份:</label>
<span>${company.establishedYear}年</span>
</div>
<div class="detail-item">
<label>注册资本:</label>
<span>${company.registeredCapital}</span>
</div>
</div>
</div>
<div class="detail-section">
<h4>风险评估</h4>
<div class="risk-assessment">
<div class="risk-item">
<label>信用等级:</label>
<span class="rating-badge rating-${company.riskLevel.toLowerCase().replace('+', '-plus').replace('-及以下', '-minus')}">${company.riskLevel}</span>
</div>
<div class="risk-item">
<label>综合评分:</label>
<span class="score">${company.riskRating}分</span>
</div>
</div>
</div>
<div class="detail-section">
<h4>财务指标</h4>
<div class="financial-indicators">
<div class="indicator-item">
<label>盈利对利息覆盖能力:</label>
<span>${company.profitCoverage.toFixed(2)}</span>
<div class="indicator-bar">
<div class="indicator-fill" style="width: ${Math.min(company.profitCoverage * 10, 100)}%"></div>
</div>
</div>
<div class="indicator-item">
<label>流动性还本付息能力:</label>
<span>${company.liquidityCapacity.toFixed(2)}</span>
<div class="indicator-bar">
<div class="indicator-fill" style="width: ${Math.min(company.liquidityCapacity * 10, 100)}%"></div>
</div>
</div>
<div class="indicator-item">
<label>清偿性还本付息能力:</label>
<span>${company.solvencyCapacity.toFixed(2)}</span>
<div class="indicator-bar">
<div class="indicator-fill" style="width: ${Math.min(company.solvencyCapacity * 20, 100)}%"></div>
</div>
</div>
</div>
</div>
<div class="detail-section">
<h4>风险建议</h4>
<div class="risk-suggestions">
${this.generateRiskSuggestions(company)}
</div>
</div>
</div>
`;
modal.style.display = 'block';
}
/**
* 生成风险建议
*/
generateRiskSuggestions(company) {
const suggestions = [];
const { profitCoverage, liquidityCapacity, solvencyCapacity } = company;
if (profitCoverage < 3.0) {
suggestions.push('• 盈利能力偏低,建议关注企业经营状况和盈利模式');
}
if (liquidityCapacity < 3.0) {
suggestions.push('• 流动性不足,需要关注短期偿债能力');
}
if (solvencyCapacity < 2.0) {
suggestions.push('• 清偿能力较弱,建议加强资产负债结构分析');
}
if (suggestions.length === 0) {
suggestions.push('• 企业财务状况良好,风险可控');
suggestions.push('• 建议继续保持定期监控');
}
return suggestions.map(s => `<p>${s}</p>`).join('');
}
/**
* 启动实时更新
*/
startRealTimeUpdate() {
setInterval(() => {
this.updateTimeDisplay();
// 这里可以添加数据更新逻辑
// this.loadCompanyData();
}, this.updateInterval);
}
/**
* 更新时间显示
*/
updateTimeDisplay() {
const now = new Date();
const timeString = now.toLocaleString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit'
});
const timeElement = document.getElementById('currentTime');
if (timeElement) {
timeElement.textContent = timeString;
}
}
/**
* 绑定事件
*/
bindEvents() {
// 关闭模态框事件
window.closeModal = () => {
document.getElementById('companyDetailModal').style.display = 'none';
};
// 退出登录事件
window.logout = () => {
if (confirm('确定要退出系统吗?')) {
// 这里添加退出逻辑
console.log('用户退出系统');
}
};
// 点击模态框外部关闭
window.addEventListener('click', (event) => {
const modal = document.getElementById('companyDetailModal');
if (event.target === modal) {
modal.style.display = 'none';
}
});
// 键盘事件
document.addEventListener('keydown', (event) => {
if (event.key === 'Escape') {
this.closeModal();
}
});
}
/**
* 显示错误消息
*/
showErrorMessage(message) {
const errorDiv = document.createElement('div');
errorDiv.className = 'error-message';
errorDiv.innerHTML = `
<div class="error-content">
<h3>系统错误</h3>
<p>${message}</p>
<button onclick="location.reload()">重新加载</button>
</div>
`;
document.body.appendChild(errorDiv);
}
/**
* 获取备用数据
*/
getBackupData() {
return [
{
name: "示例企业A",
profitCoverage: 5.50,
liquidityCapacity: 5.60,
solvencyCapacity: 2.00,
industry: "制造业",
establishedYear: 2000,
registeredCapital: "5.0亿元"
}
];
}
}
// 页面加载完成后初始化系统
document.addEventListener('DOMContentLoaded', () => {
const riskAnalyzer = new FinancialRiskAnalyzer();
// 将实例挂载到全局,便于调试
window.riskAnalyzer = riskAnalyzer;
});
5. 信用评级可视化实现
5.1 评级分布图表
/**
* 信用评级可视化图表管理器
*/
class CreditRatingChartManager {
constructor() {
this.charts = new Map();
this.colorScheme = this.initColorScheme();
this.init();
}
/**
* 初始化颜色方案
*/
initColorScheme() {
return {
'AAA': '#00ff88',
'AA+': '#00d4ff',
'AA': '#ffd93d',
'AA-': '#ff9f43',
'A+': '#ff6b6b',
'A': '#ff4757',
'A-': '#ff3838',
'BBB及以下': '#c44569'
};
}
/**
* 初始化图表管理器
*/
init() {
console.log('📊 初始化信用评级图表管理器');
}
/**
* 创建评级分布饼图
*/
createRatingDistributionChart(containerId, data) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
const option = {
backgroundColor: 'transparent',
title: {
text: '企业信用评级分布',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 18,
fontWeight: 'bold'
}
},
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
borderWidth: 1,
textStyle: {
color: '#ffffff'
},
formatter: function(params) {
return `${params.name}<br/>
企业数量: ${params.value}家<br/>
占比: ${params.percent}%`;
}
},
legend: {
orient: 'vertical',
left: 'left',
top: 'middle',
textStyle: {
color: '#ffffff',
fontSize: 12
},
itemGap: 15
},
series: [{
name: '信用评级',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 8,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: false,
position: 'center'
},
emphasis: {
label: {
show: true,
fontSize: '16',
fontWeight: 'bold',
color: '#ffffff'
},
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
labelLine: {
show: false
},
data: data.map(item => ({
name: item.rating,
value: item.count,
itemStyle: {
color: this.colorScheme[item.rating] || '#666'
}
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
// 添加点击事件
chart.on('click', (params) => {
this.onRatingClick(params);
});
return chart;
}
/**
* 创建风险指标雷达图
*/
createRiskRadarChart(containerId, companyData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
const indicators = [
{ name: '盈利能力', max: 10 },
{ name: '流动性', max: 10 },
{ name: '偿债能力', max: 10 },
{ name: '营运能力', max: 10 },
{ name: '成长能力', max: 10 },
{ name: '市场地位', max: 10 }
];
const option = {
backgroundColor: 'transparent',
title: {
text: '企业风险指标分析',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
}
},
radar: {
indicator: indicators,
center: ['50%', '55%'],
radius: '70%',
axisName: {
color: '#ffffff',
fontSize: 12
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.2)'
}
},
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
splitArea: {
show: true,
areaStyle: {
color: [
'rgba(0, 255, 136, 0.1)',
'rgba(0, 212, 255, 0.1)',
'rgba(255, 217, 61, 0.1)',
'rgba(255, 107, 107, 0.1)'
]
}
}
},
series: [{
name: '风险指标',
type: 'radar',
data: companyData.map(company => ({
value: [
company.profitability || 0,
company.liquidity || 0,
company.solvency || 0,
company.operation || 0,
company.growth || 0,
company.market || 0
],
name: company.name,
areaStyle: {
color: this.colorScheme[company.rating] || '#666',
opacity: 0.3
},
lineStyle: {
color: this.colorScheme[company.rating] || '#666',
width: 2
},
symbol: 'circle',
symbolSize: 5
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建风险趋势图
*/
createRiskTrendChart(containerId, trendData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
const option = {
backgroundColor: 'transparent',
title: {
text: '信用风险趋势分析',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
axisPointer: {
type: 'cross',
label: {
backgroundColor: '#6a7985'
}
}
},
legend: {
data: ['高风险', '中风险', '低风险'],
top: '10%',
textStyle: {
color: '#ffffff'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: trendData.dates,
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
}
},
yAxis: {
type: 'value',
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
series: [
{
name: '高风险',
type: 'line',
stack: '总量',
smooth: true,
lineStyle: {
color: '#ff6b6b'
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 107, 107, 0.8)' },
{ offset: 1, color: 'rgba(255, 107, 107, 0.1)' }
]
}
},
data: trendData.highRisk
},
{
name: '中风险',
type: 'line',
stack: '总量',
smooth: true,
lineStyle: {
color: '#ffd93d'
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 217, 61, 0.8)' },
{ offset: 1, color: 'rgba(255, 217, 61, 0.1)' }
]
}
},
data: trendData.mediumRisk
},
{
name: '低风险',
type: 'line',
stack: '总量',
smooth: true,
lineStyle: {
color: '#00ff88'
},
areaStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(0, 255, 136, 0.8)' },
{ offset: 1, color: 'rgba(0, 255, 136, 0.1)' }
]
}
},
data: trendData.lowRisk
}
]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 创建行业风险对比图
*/
createIndustryRiskChart(containerId, industryData) {
const container = document.getElementById(containerId);
if (!container) {
console.error(`容器不存在: ${containerId}`);
return null;
}
const chart = echarts.init(container);
const option = {
backgroundColor: 'transparent',
title: {
text: '行业风险对比分析',
left: 'center',
top: '5%',
textStyle: {
color: '#ffffff',
fontSize: 16
}
},
tooltip: {
trigger: 'axis',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
borderColor: 'rgba(0, 212, 255, 0.5)',
textStyle: {
color: '#ffffff'
},
axisPointer: {
type: 'shadow'
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '15%',
containLabel: true
},
xAxis: {
type: 'category',
data: industryData.map(item => item.industry),
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff',
rotate: 45
}
},
yAxis: {
type: 'value',
name: '风险评分',
axisLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.3)'
}
},
axisLabel: {
color: '#ffffff'
},
splitLine: {
lineStyle: {
color: 'rgba(255, 255, 255, 0.1)'
}
}
},
series: [{
name: '平均风险评分',
type: 'bar',
barWidth: '60%',
data: industryData.map((item, index) => ({
value: item.riskScore,
itemStyle: {
color: {
type: 'linear',
x: 0, y: 0, x2: 0, y2: 1,
colorStops: [
{ offset: 0, color: this.getGradientColor(item.riskScore, 0.8) },
{ offset: 1, color: this.getGradientColor(item.riskScore, 0.3) }
]
},
borderRadius: [4, 4, 0, 0]
}
}))
}]
};
chart.setOption(option);
this.charts.set(containerId, chart);
return chart;
}
/**
* 根据风险评分获取渐变颜色
*/
getGradientColor(score, alpha = 1) {
if (score >= 80) {
return `rgba(0, 255, 136, ${alpha})`; // 绿色 - 低风险
} else if (score >= 60) {
return `rgba(255, 217, 61, ${alpha})`; // 黄色 - 中风险
} else {
return `rgba(255, 107, 107, ${alpha})`; // 红色 - 高风险
}
}
/**
* 评级点击事件处理
*/
onRatingClick(params) {
console.log('点击评级:', params.name);
// 这里可以添加钻取分析逻辑
if (window.riskAnalyzer && window.riskAnalyzer.filterByRating) {
window.riskAnalyzer.filterByRating(params.name);
}
}
/**
* 更新图表数据
*/
updateChart(containerId, newData) {
const chart = this.charts.get(containerId);
if (!chart) {
console.error(`图表不存在: ${containerId}`);
return;
}
const option = chart.getOption();
// 根据图表类型更新相应的数据
// 这里需要根据具体的图表类型来实现
chart.setOption(option, true);
}
/**
* 调整图表大小
*/
resize(containerId = null) {
if (containerId) {
const chart = this.charts.get(containerId);
if (chart) {
chart.resize();
}
} else {
this.charts.forEach(chart => {
chart.resize();
});
}
}
/**
* 销毁图表
*/
dispose(containerId) {
const chart = this.charts.get(containerId);
if (chart) {
chart.dispose();
this.charts.delete(containerId);
}
}
/**
* 销毁所有图表
*/
disposeAll() {
this.charts.forEach(chart => {
chart.dispose();
});
this.charts.clear();
}
}
// 创建全局图表管理器实例
const creditChartManager = new CreditRatingChartManager();
// 窗口大小变化时调整图表
window.addEventListener('resize', () => {
creditChartManager.resize();
});
// 示例:创建评级分布图表
document.addEventListener('DOMContentLoaded', () => {
// 模拟评级分布数据
const ratingDistributionData = [
{ rating: 'AAA', count: 2 },
{ rating: 'AA+', count: 3 },
{ rating: 'AA', count: 6 },
{ rating: 'AA-及以下', count: 10 }
];
// 如果页面有对应容器,创建图表
if (document.getElementById('ratingDistributionChart')) {
creditChartManager.createRatingDistributionChart('ratingDistributionChart', ratingDistributionData);
}
// 模拟趋势数据
const trendData = {
dates: ['1月', '2月', '3月', '4月', '5月', '6月'],
highRisk: [5, 8, 12, 10, 15, 18],
mediumRisk: [15, 18, 20, 22, 25, 28],
lowRisk: [30, 35, 40, 45, 50, 55]
};
if (document.getElementById('riskTrendChart')) {
creditChartManager.createRiskTrendChart('riskTrendChart', trendData);
}
// 模拟行业数据
const industryData = [
{ industry: '纺织业', riskScore: 85 },
{ industry: '服装业', riskScore: 82 },
{ industry: '家居用品', riskScore: 78 },
{ industry: '科技服务', riskScore: 75 },
{ industry: '制造业', riskScore: 70 }
];
if (document.getElementById('industryRiskChart')) {
creditChartManager.createIndustryRiskChart('industryRiskChart', industryData);
}
});
6. 风险指标监控系统
6.1 实时监控仪表板
# 风险指标监控系统设计
class RiskIndicatorMonitoringSystem:
"""风险指标监控系统"""
def __init__(self):
self.indicators = self.define_risk_indicators()
self.alert_rules = self.define_alert_rules()
self.monitoring_config = self.define_monitoring_config()
def define_risk_indicators(self):
"""定义风险监控指标"""
return {
"核心财务指标": {
"资产负债率": {
"计算公式": "总负债 / 总资产 × 100%",
"正常范围": "40%-60%",
"预警阈值": "> 80%",
"危险阈值": "> 90%",
"监控频率": "日",
"权重": 0.25
},
"流动比率": {
"计算公式": "流动资产 / 流动负债",
"正常范围": "1.5-2.5",
"预警阈值": "< 1.2",
"危险阈值": "< 1.0",
"监控频率": "日",
"权重": 0.20
},
"速动比率": {
"计算公式": "(流动资产-存货) / 流动负债",
"正常范围": "1.0-1.5",
"预警阈值": "< 0.8",
"危险阈值": "< 0.5",
"监控频率": "日",
"权重": 0.15
},
"利息保障倍数": {
"计算公式": "息税前利润 / 利息费用",
"正常范围": "> 3.0",
"预警阈值": "< 2.0",
"危险阈值": "< 1.0",
"监控频率": "月",
"权重": 0.20
}
},
"经营效率指标": {
"总资产周转率": {
"计算公式": "营业收入 / 平均总资产",
"正常范围": "> 0.8",
"预警阈值": "< 0.5",
"危险阈值": "< 0.3",
"监控频率": "季",
"权重": 0.15
},
"应收账款周转率": {
"计算公式": "营业收入 / 平均应收账款",
"正常范围": "> 6",
"预警阈值": "< 4",
"危险阈值": "< 2",
"监控频率": "月",
"权重": 0.10
},
"存货周转率": {
"计算公式": "营业成本 / 平均存货",
"正常范围": "> 4",
"预警阈值": "< 2",
"危险阈值": "< 1",
"监控频率": "月",
"权重": 0.10
}
},
"盈利能力指标": {
"净资产收益率": {
"计算公式": "净利润 / 平均净资产 × 100%",
"正常范围": "> 10%",
"预警阈值": "< 5%",
"危险阈值": "< 0%",
"监控频率": "季",
"权重": 0.20
},
"销售净利率": {
"计算公式": "净利润 / 营业收入 × 100%",
"正常范围": "> 5%",
"预警阈值": "< 2%",
"危险阈值": "< 0%",
"监控频率": "月",
"权重": 0.15
},
"毛利率": {
"计算公式": "(营业收入-营业成本) / 营业收入 × 100%",
"正常范围": "> 20%",
"预警阈值": "< 10%",
"危险阈值": "< 5%",
"监控频率": "月",
"权重": 0.10
}
},
"市场表现指标": {
"市场份额变化": {
"计算公式": "企业销售额 / 行业总销售额 × 100%",
"正常范围": "稳定或增长",
"预警阈值": "连续下降",
"危险阈值": "大幅下降",
"监控频率": "季",
"权重": 0.15
},
"客户集中度": {
"计算公式": "前五大客户销售额 / 总销售额 × 100%",
"正常范围": "< 50%",
"预警阈值": "> 70%",
"危险阈值": "> 85%",
"监控频率": "季",
"权重": 0.10
}
}
}
def define_alert_rules(self):
"""定义预警规则"""
return {
"预警级别": {
"绿色": {
"描述": "风险可控",
"触发条件": "所有指标正常",
"处理措施": "常规监控",
"通知方式": "无需通知"
},
"黄色": {
"描述": "需要关注",
"触发条件": "单项指标达到预警阈值",
"处理措施": "加强监控,分析原因",
"通知方式": "系统提醒"
},
"橙色": {
"描述": "风险较高",
"触发条件": "多项指标达到预警阈值或单项达到危险阈值",
"处理措施": "立即分析,制定应对方案",
"通知方式": "邮件+短信"
},
"红色": {
"描述": "高风险",
"触发条件": "多项指标达到危险阈值",
"处理措施": "紧急处理,风险控制",
"通知方式": "电话+邮件+短信"
}
},
"自动化处理": {
"数据收集": "自动从各系统采集数据",
"指标计算": "实时计算各项风险指标",
"阈值监控": "持续监控指标是否超过阈值",
"预警触发": "自动触发相应级别的预警",
"报告生成": "自动生成风险分析报告"
}
}
def define_monitoring_config(self):
"""定义监控配置"""
return {
"数据源配置": {
"财务系统": {
"连接方式": "API接口",
"更新频率": "实时",
"数据类型": "财务报表数据"
},
"业务系统": {
"连接方式": "数据库连接",
"更新频率": "每小时",
"数据类型": "经营数据"
},
"外部数据": {
"连接方式": "第三方API",
"更新频率": "每日",
"数据类型": "市场数据、行业数据"
}
},
"监控策略": {
"实时监控": ["资产负债率", "流动比率", "速动比率"],
"日度监控": ["利息保障倍数", "应收账款周转率"],
"周度监控": ["存货周转率", "销售净利率"],
"月度监控": ["净资产收益率", "总资产周转率"],
"季度监控": ["市场份额变化", "客户集中度"]
},
"报告配置": {
"日报": {
"生成时间": "每日9:00",
"包含内容": ["核心指标概览", "异常预警", "趋势分析"],
"发送对象": ["风控经理", "业务经理"]
},
"周报": {
"生成时间": "每周一9:00",
"包含内容": ["周度指标分析", "风险评估", "建议措施"],
"发送对象": ["部门总监", "风控委员会"]
},
"月报": {
"生成时间": "每月1日9:00",
"包含内容": ["月度风险评估", "行业对比", "预测分析"],
"发送对象": ["高级管理层", "董事会"]
}
}
}
def calculate_risk_score(self, company_data):
"""计算企业风险评分"""
total_score = 0
total_weight = 0
for category, indicators in self.indicators.items():
for indicator_name, indicator_info in indicators.items():
if indicator_name in company_data:
value = company_data[indicator_name]
score = self.evaluate_indicator(value, indicator_info)
weight = indicator_info['权重']
total_score += score * weight
total_weight += weight
if total_weight > 0:
final_score = total_score / total_weight * 100
return min(100, max(0, final_score))
return 0
def evaluate_indicator(self, value, indicator_info):
"""评估单个指标"""
# 简化的评估逻辑
normal_range = indicator_info['正常范围']
warning_threshold = indicator_info['预警阈值']
danger_threshold = indicator_info['危险阈值']
# 这里需要根据具体的阈值类型进行判断
# 返回0-100的评分
if self.is_in_normal_range(value, normal_range):
return 90
elif self.exceeds_threshold(value, warning_threshold):
return 60
elif self.exceeds_threshold(value, danger_threshold):
return 30
else:
return 80
def is_in_normal_range(self, value, range_str):
"""判断是否在正常范围内"""
# 简化实现,实际需要解析各种格式的范围表达式
return True
def exceeds_threshold(self, value, threshold_str):
"""判断是否超过阈值"""
# 简化实现,实际需要解析各种格式的阈值表达式
return False
def generate_risk_alert(self, company_data, risk_score):
"""生成风险预警"""
alert_level = self.determine_alert_level(risk_score)
return {
"企业名称": company_data.get("name", "未知"),
"风险评分": risk_score,
"预警级别": alert_level,
"预警时间": "2024-07-20 17:30:00",
"风险描述": self.get_risk_description(alert_level),
"建议措施": self.get_recommended_actions(alert_level),
"详细分析": self.analyze_risk_factors(company_data)
}
def determine_alert_level(self, risk_score):
"""确定预警级别"""
if risk_score >= 80:
return "绿色"
elif risk_score >= 60:
return "黄色"
elif risk_score >= 40:
return "橙色"
else:
return "红色"
def get_risk_description(self, alert_level):
"""获取风险描述"""
descriptions = {
"绿色": "企业财务状况良好,风险可控",
"黄色": "企业存在一定风险,需要关注",
"橙色": "企业风险较高,需要采取措施",
"红色": "企业风险很高,需要紧急处理"
}
return descriptions.get(alert_level, "未知风险级别")
def get_recommended_actions(self, alert_level):
"""获取建议措施"""
actions = {
"绿色": ["继续保持良好的财务管理", "定期监控关键指标"],
"黄色": ["加强财务监控", "分析风险原因", "制定改进计划"],
"橙色": ["立即进行风险评估", "制定风险控制方案", "加强资金管理"],
"红色": ["紧急风险控制", "暂停新增授信", "要求提供担保", "考虑提前收回贷款"]
}
return actions.get(alert_level, ["联系风控专家"])
def analyze_risk_factors(self, company_data):
"""分析风险因素"""
risk_factors = []
# 这里可以添加更详细的风险因素分析逻辑
if company_data.get("debt_ratio", 0) > 0.8:
risk_factors.append("资产负债率过高")
if company_data.get("current_ratio", 0) < 1.2:
risk_factors.append("流动比率偏低")
if company_data.get("profit_margin", 0) < 0.05:
risk_factors.append("盈利能力不足")
return risk_factors
def print_monitoring_system_overview(self):
"""打印监控系统概述"""
print("=== 风险指标监控系统概述 ===\n")
print("📊 监控指标体系:")
for category, indicators in self.indicators.items():
print(f"\n🔹 {category}:")
for indicator, info in indicators.items():
print(f" • {indicator}")
print(f" 计算公式: {info['计算公式']}")
print(f" 正常范围: {info['正常范围']}")
print(f" 预警阈值: {info['预警阈值']}")
print(f" 监控频率: {info['监控频率']}")
print(f" 权重: {info['权重']}")
print(f"\n🚨 预警规则:")
for level, rule in self.alert_rules['预警级别'].items():
print(f"\n🔸 {level}级预警:")
print(f" 描述: {rule['描述']}")
print(f" 触发条件: {rule['触发条件']}")
print(f" 处理措施: {rule['处理措施']}")
print(f" 通知方式: {rule['通知方式']}")
print(f"\n⚙️ 监控配置:")
config = self.monitoring_config
print(f" 数据源: {len(config['数据源配置'])}个")
print(f" 监控策略: {len(config['监控策略'])}种")
print(f" 报告类型: {len(config['报告配置'])}种")
# 创建监控系统实例
risk_monitor = RiskIndicatorMonitoringSystem()
risk_monitor.print_monitoring_system_overview()
# 示例:风险评估
sample_company = {
"name": "示例企业",
"debt_ratio": 0.75,
"current_ratio": 1.5,
"profit_margin": 0.08
}
risk_score = risk_monitor.calculate_risk_score(sample_company)
alert = risk_monitor.generate_risk_alert(sample_company, risk_score)
print(f"\n📈 风险评估示例:")
print(f" 企业名称: {alert['企业名称']}")
print(f" 风险评分: {alert['风险评分']:.2f}")
print(f" 预警级别: {alert['预警级别']}")
print(f" 风险描述: {alert['风险描述']}")
print(f" 建议措施: {', '.join(alert['建议措施'])}")
7. 实时数据处理与更新
7.1 数据同步机制
/**
* 实时数据处理与更新系统
*/
class RealTimeDataProcessor {
constructor() {
this.websocket = null;
this.updateQueue = [];
this.isProcessing = false;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.reconnectDelay = 5000;
this.dataCache = new Map();
this.subscribers = new Map();
this.init();
}
/**
* 初始化实时数据处理器
*/
init() {
console.log('🔄 初始化实时数据处理器...');
// 建立WebSocket连接
this.connectWebSocket();
// 启动数据处理循环
this.startProcessingLoop();
// 绑定页面事件
this.bindPageEvents();
console.log('✅ 实时数据处理器初始化完成');
}
/**
* 建立WebSocket连接
*/
connectWebSocket() {
try {
// 实际应用中替换为真实的WebSocket地址
const wsUrl = this.getWebSocketUrl();
this.websocket = new WebSocket(wsUrl);
this.websocket.onopen = (event) => {
console.log('🔗 WebSocket连接已建立');
this.reconnectAttempts = 0;
this.onWebSocketOpen(event);
};
this.websocket.onmessage = (event) => {
this.onWebSocketMessage(event);
};
this.websocket.onclose = (event) => {
console.log('❌ WebSocket连接已关闭');
this.onWebSocketClose(event);
};
this.websocket.onerror = (error) => {
console.error('❌ WebSocket连接错误:', error);
this.onWebSocketError(error);
};
} catch (error) {
console.error('WebSocket连接失败:', error);
this.scheduleReconnect();
}
}
/**
* 获取WebSocket URL
*/
getWebSocketUrl() {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const host = window.location.host;
return `${protocol}//${host}/ws/risk-data`;
}
/**
* WebSocket连接打开事件
*/
onWebSocketOpen(event) {
// 发送认证信息
this.sendAuthentication();
// 订阅数据更新
this.subscribeToDataUpdates();
}
/**
* WebSocket消息接收事件
*/
onWebSocketMessage(event) {
try {
const data = JSON.parse(event.data);
this.handleIncomingData(data);
} catch (error) {
console.error('解析WebSocket消息失败:', error);
}
}
/**
* WebSocket连接关闭事件
*/
onWebSocketClose(event) {
if (event.code !== 1000) {
// 非正常关闭,尝试重连
this.scheduleReconnect();
}
}
/**
* WebSocket错误事件
*/
onWebSocketError(error) {
console.error('WebSocket错误:', error);
}
/**
* 发送认证信息
*/
sendAuthentication() {
const authData = {
type: 'auth',
token: this.getAuthToken(),
userId: this.getCurrentUserId()
};
this.sendWebSocketMessage(authData);
}
/**
* 订阅数据更新
*/
subscribeToDataUpdates() {
const subscriptionData = {
type: 'subscribe',
channels: [
'company-risk-updates',
'market-data-updates',
'alert-notifications'
]
};
this.sendWebSocketMessage(subscriptionData);
}
/**
* 发送WebSocket消息
*/
sendWebSocketMessage(data) {
if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
this.websocket.send(JSON.stringify(data));
} else {
console.warn('WebSocket未连接,消息发送失败');
}
}
/**
* 处理接收到的数据
*/
handleIncomingData(data) {
switch (data.type) {
case 'company-update':
this.handleCompanyUpdate(data);
break;
case 'market-update':
this.handleMarketUpdate(data);
break;
case 'alert':
this.handleAlert(data);
break;
case 'batch-update':
this.handleBatchUpdate(data);
break;
default:
console.log('未知数据类型:', data.type);
}
}
/**
* 处理企业数据更新
*/
handleCompanyUpdate(data) {
const { companyId, updates } = data;
// 更新缓存
this.updateDataCache('company', companyId, updates);
// 添加到更新队列
this.addToUpdateQueue({
type: 'company-update',
companyId: companyId,
data: updates,
timestamp: Date.now()
});
// 通知订阅者
this.notifySubscribers('company-update', { companyId, updates });
}
/**
* 处理市场数据更新
*/
handleMarketUpdate(data) {
const { marketData } = data;
// 更新缓存
this.updateDataCache('market', 'current', marketData);
// 添加到更新队列
this.addToUpdateQueue({
type: 'market-update',
data: marketData,
timestamp: Date.now()
});
// 通知订阅者
this.notifySubscribers('market-update', marketData);
}
/**
* 处理预警信息
*/
handleAlert(data) {
const { alert } = data;
// 显示预警通知
this.showAlertNotification(alert);
// 更新预警列表
this.updateAlertList(alert);
// 通知订阅者
this.notifySubscribers('alert', alert);
}
/**
* 处理批量更新
*/
handleBatchUpdate(data) {
const { updates } = data;
updates.forEach(update => {
this.handleIncomingData(update);
});
}
/**
* 更新数据缓存
*/
updateDataCache(category, key, data) {
const cacheKey = `${category}:${key}`;
const existingData = this.dataCache.get(cacheKey) || {};
const updatedData = { ...existingData, ...data };
this.dataCache.set(cacheKey, updatedData);
}
/**
* 添加到更新队列
*/
addToUpdateQueue(update) {
this.updateQueue.push(update);
// 限制队列大小
if (this.updateQueue.length > 1000) {
this.updateQueue.shift();
}
}
/**
* 启动数据处理循环
*/
startProcessingLoop() {
setInterval(() => {
this.processUpdateQueue();
}, 100); // 每100ms处理一次队列
}
/**
* 处理更新队列
*/
processUpdateQueue() {
if (this.isProcessing || this.updateQueue.length === 0) {
return;
}
this.isProcessing = true;
try {
const batchSize = 10;
const batch = this.updateQueue.splice(0, batchSize);
batch.forEach(update => {
this.applyUpdate(update);
});
} catch (error) {
console.error('处理更新队列失败:', error);
} finally {
this.isProcessing = false;
}
}
/**
* 应用数据更新
*/
applyUpdate(update) {
switch (update.type) {
case 'company-update':
this.applyCompanyUpdate(update);
break;
case 'market-update':
this.applyMarketUpdate(update);
break;
default:
console.log('未知更新类型:', update.type);
}
}
/**
* 应用企业数据更新
*/
applyCompanyUpdate(update) {
const { companyId, data } = update;
// 更新表格中的企业数据
this.updateCompanyInTable(companyId, data);
// 更新图表数据
this.updateChartsWithCompanyData(companyId, data);
// 重新计算风险评级
this.recalculateRiskRating(companyId, data);
}
/**
* 应用市场数据更新
*/
applyMarketUpdate(update) {
const { data } = update;
// 更新市场指标显示
this.updateMarketIndicators(data);
// 更新相关图表
this.updateMarketCharts(data);
}
/**
* 更新表格中的企业数据
*/
updateCompanyInTable(companyId, data) {
const tableRows = document.querySelectorAll('table tr');
tableRows.forEach(row => {
const companyNameCell = row.querySelector('td:first-child');
if (companyNameCell && companyNameCell.textContent.includes(data.name)) {
// 更新相应的单元格
this.updateTableRow(row, data);
}
});
}
/**
* 更新表格行数据
*/
updateTableRow(row, data) {
const cells = row.querySelectorAll('td');
if (cells.length >= 4) {
// 更新盈利覆盖能力
if (data.profitCoverage !== undefined) {
cells[1].textContent = data.profitCoverage.toFixed(2);
this.animateValueChange(cells[1]);
}
// 更新流动性能力
if (data.liquidityCapacity !== undefined) {
cells[2].textContent = data.liquidityCapacity.toFixed(2);
this.animateValueChange(cells[2]);
}
// 更新清偿能力
if (data.solvencyCapacity !== undefined) {
cells[3].textContent = data.solvencyCapacity.toFixed(2);
this.animateValueChange(cells[3]);
}
}
}
/**
* 动画显示数值变化
*/
animateValueChange(element) {
element.style.backgroundColor = 'rgba(0, 212, 255, 0.3)';
element.style.transition = 'background-color 0.5s ease';
setTimeout(() => {
element.style.backgroundColor = '';
}, 1000);
}
/**
* 显示预警通知
*/
showAlertNotification(alert) {
const notification = document.createElement('div');
notification.className = `alert-notification alert-${alert.level}`;
notification.innerHTML = `
<div class="alert-header">
<span class="alert-icon">⚠️</span>
<span class="alert-title">${alert.title}</span>
<button class="alert-close" onclick="this.parentElement.parentElement.remove()">×</button>
</div>
<div class="alert-content">
<p>${alert.message}</p>
<small>时间: ${new Date(alert.timestamp).toLocaleString()}</small>
</div>
`;
// 添加到页面
const container = document.getElementById('alertContainer') || document.body;
container.appendChild(notification);
// 自动移除
setTimeout(() => {
if (notification.parentNode) {
notification.remove();
}
}, 10000);
}
/**
* 订阅数据更新
*/
subscribe(channel, callback) {
if (!this.subscribers.has(channel)) {
this.subscribers.set(channel, []);
}
this.subscribers.get(channel).push(callback);
}
/**
* 取消订阅
*/
unsubscribe(channel, callback) {
if (this.subscribers.has(channel)) {
const callbacks = this.subscribers.get(channel);
const index = callbacks.indexOf(callback);
if (index > -1) {
callbacks.splice(index, 1);
}
}
}
/**
* 通知订阅者
*/
notifySubscribers(channel, data) {
if (this.subscribers.has(channel)) {
this.subscribers.get(channel).forEach(callback => {
try {
callback(data);
} catch (error) {
console.error('订阅者回调执行失败:', error);
}
});
}
}
/**
* 计划重连
*/
scheduleReconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
console.log(`⏰ ${this.reconnectDelay / 1000}秒后尝试第${this.reconnectAttempts}次重连...`);
setTimeout(() => {
this.connectWebSocket();
}, this.reconnectDelay);
// 增加重连延迟
this.reconnectDelay = Math.min(this.reconnectDelay * 2, 30000);
} else {
console.error('❌ 达到最大重连次数,停止重连');
this.showConnectionError();
}
}
/**
* 显示连接错误
*/
showConnectionError() {
const errorDiv = document.createElement('div');
errorDiv.className = 'connection-error';
errorDiv.innerHTML = `
<div class="error-content">
<h3>连接中断</h3>
<p>与服务器的连接已中断,实时数据更新暂停</p>
<button onclick="location.reload()">重新连接</button>
</div>
`;
document.body.appendChild(errorDiv);
}
/**
* 绑定页面事件
*/
bindPageEvents() {
// 页面可见性变化
document.addEventListener('visibilitychange', () => {
if (document.hidden) {
console.log('📱 页面隐藏,暂停数据处理');
} else {
console.log('📱 页面显示,恢复数据处理');
}
});
// 页面卸载
window.addEventListener('beforeunload', () => {
this.cleanup();
});
}
/**
* 获取认证令牌
*/
getAuthToken() {
return localStorage.getItem('authToken') || 'demo-token';
}
/**
* 获取当前用户ID
*/
getCurrentUserId() {
return localStorage.getItem('userId') || 'demo-user';
}
/**
* 清理资源
*/
cleanup() {
if (this.websocket) {
this.websocket.close();
}
this.subscribers.clear();
this.dataCache.clear();
this.updateQueue = [];
}
}
// 创建全局实时数据处理器实例
const realTimeProcessor = new RealTimeDataProcessor();
// 示例:订阅企业数据更新
realTimeProcessor.subscribe('company-update', (data) => {
console.log('企业数据更新:', data);
});
// 示例:订阅预警信息
realTimeProcessor.subscribe('alert', (alert) => {
console.log('收到预警:', alert);
});
8. 用户界面设计与交互
8.1 响应式界面设计
/* 金融风控系统界面样式 */
/* 全局样式重置 */
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
/* 根元素样式 */
:root {
--primary-color: #1e3c72;
--secondary-color: #2a5298;
--accent-color: #00d4ff;
--success-color: #00ff88;
--warning-color: #ffd93d;
--danger-color: #ff6b6b;
--text-primary: #ffffff;
--text-secondary: #e0e0e0;
--text-muted: #a0a0a0;
--bg-primary: #0f1419;
--bg-secondary: #1a2332;
--bg-card: rgba(255, 255, 255, 0.1);
--border-color: rgba(255, 255, 255, 0.2);
--shadow-light: 0 4px 12px rgba(0, 0, 0, 0.1);
--shadow-medium: 0 8px 24px rgba(0, 0, 0, 0.2);
--shadow-heavy: 0 16px 48px rgba(0, 0, 0, 0.3);
}
/* 基础样式 */
body {
font-family: 'Microsoft YaHei', 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
background: linear-gradient(135deg, var(--primary-color) 0%, var(--secondary-color) 100%);
color: var(--text-primary);
line-height: 1.6;
overflow-x: hidden;
min-height: 100vh;
}
/* 页面头部样式 */
.header {
background: rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
border-bottom: 1px solid var(--border-color);
padding: 15px 0;
position: sticky;
top: 0;
z-index: 1000;
box-shadow: var(--shadow-light);
}
.header-content {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px;
display: flex;
justify-content: space-between;
align-items: center;
}
.time-display {
font-size: 14px;
color: var(--text-muted);
font-family: 'Courier New', monospace;
}
.system-title {
font-size: 24px;
font-weight: 300;
background: linear-gradient(45deg, var(--accent-color), var(--success-color));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
margin: 0;
}
.user-info {
font-size: 14px;
color: var(--text-secondary);
}
.user-info a {
color: var(--accent-color);
text-decoration: none;
margin-left: 10px;
transition: color 0.3s ease;
}
.user-info a:hover {
color: var(--success-color);
}
/* 主标题样式 */
.main-title {
text-align: center;
padding: 30px 20px;
position: relative;
}
.main-title h2 {
font-size: 28px;
font-weight: 500;
color: var(--text-primary);
margin-bottom: 10px;
}
.title-decoration {
width: 100px;
height: 3px;
background: linear-gradient(90deg, var(--accent-color), var(--success-color));
margin: 0 auto;
border-radius: 2px;
}
/* 信用评级容器样式 */
.credit-rating-container {
max-width: 1400px;
margin: 0 auto;
padding: 0 20px 40px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(600px, 1fr));
gap: 25px;
}
/* 评级面板样式 */
.rating-panel {
background: var(--bg-card);
border: 1px solid var(--border-color);
border-radius: 16px;
padding: 25px;
backdrop-filter: blur(15px);
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.rating-panel::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--accent-color), var(--success-color));
opacity: 0;
transition: opacity 0.3s ease;
}
.rating-panel:hover {
transform: translateY(-8px);
box-shadow: var(--shadow-heavy);
border-color: var(--accent-color);
}
.rating-panel:hover::before {
opacity: 1;
}
/* 评级头部样式 */
.rating-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 2px solid var(--border-color);
}
.rating-title {
font-size: 28px;
font-weight: 600;
color: var(--text-primary);
margin: 0;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
/* 评级徽章样式 */
.rating-badge {
padding: 8px 16px;
border-radius: 20px;
font-size: 12px;
font-weight: 600;
color: #000;
text-transform: uppercase;
letter-spacing: 0.5px;
box-shadow: var(--shadow-light);
}
.rating-aaa {
background: linear-gradient(45deg, var(--success-color), #00b894);
}
.rating-aa-plus {
background: linear-gradient(45deg, var(--accent-color), #74b9ff);
}
.rating-aa {
background: linear-gradient(45deg, var(--warning-color), #fdcb6e);
}
.rating-aa-minus {
background: linear-gradient(45deg, var(--danger-color), #fd79a8);
}
/* 企业表格样式 */
.company-table {
width: 100%;
border-collapse: collapse;
margin-top: 15px;
font-size: 13px;
}
.company-table th {
background: rgba(0, 0, 0, 0.4);
color: var(--text-primary);
padding: 15px 12px;
text-align: left;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
border-bottom: 2px solid var(--border-color);
position: sticky;
top: 0;
z-index: 10;
}
.company-table td {
padding: 12px;
color: var(--text-secondary);
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
cursor: pointer;
transition: all 0.3s ease;
position: relative;
}
.company-table tr:hover {
background: rgba(0, 212, 255, 0.1);
transform: scale(1.02);
}
.company-table tr:hover td {
color: var(--text-primary);
}
/* 风险指示器样式 */
.risk-indicator {
display: inline-block;
width: 10px;
height: 10px;
border-radius: 50%;
margin-right: 8px;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.3);
animation: pulse 2s infinite;
}
.risk-low {
background: var(--success-color);
box-shadow: 0 0 12px rgba(0, 255, 136, 0.5);
}
.risk-medium {
background: var(--warning-color);
box-shadow: 0 0 12px rgba(255, 217, 61, 0.5);
}
.risk-high {
background: var(--danger-color);
box-shadow: 0 0 12px rgba(255, 107, 107, 0.5);
}
@keyframes pulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.7;
transform: scale(1.1);
}
}
/* 模态框样式 */
.modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
backdrop-filter: blur(5px);
z-index: 2000;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
animation: fadeIn 0.3s ease forwards;
}
@keyframes fadeIn {
to {
opacity: 1;
}
}
.modal-content {
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 16px;
max-width: 800px;
width: 90%;
max-height: 80vh;
overflow-y: auto;
box-shadow: var(--shadow-heavy);
animation: slideUp 0.3s ease;
}
@keyframes slideUp {
from {
transform: translateY(50px);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
.modal-header {
padding: 25px;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.modal-header h3 {
margin: 0;
font-size: 20px;
color: var(--text-primary);
}
.close {
font-size: 28px;
font-weight: bold;
color: var(--text-muted);
cursor: pointer;
transition: color 0.3s ease;
}
.close:hover {
color: var(--danger-color);
}
.modal-body {
padding: 25px;
}
/* 企业详情样式 */
.company-detail {
color: var(--text-secondary);
}
.detail-section {
margin-bottom: 30px;
}
.detail-section h4 {
color: var(--text-primary);
font-size: 16px;
margin-bottom: 15px;
padding-bottom: 8px;
border-bottom: 2px solid var(--accent-color);
}
.detail-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 15px;
}
.detail-item {
display: flex;
flex-direction: column;
gap: 5px;
}
.detail-item label {
font-size: 12px;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.detail-item span {
font-size: 14px;
color: var(--text-primary);
font-weight: 500;
}
/* 风险评估样式 */
.risk-assessment {
display: flex;
gap: 20px;
align-items: center;
}
.risk-item {
display: flex;
flex-direction: column;
gap: 5px;
}
.score {
font-size: 18px;
font-weight: 600;
color: var(--success-color);
}
/* 财务指标样式 */
.financial-indicators {
display: flex;
flex-direction: column;
gap: 15px;
}
.indicator-item {
display: flex;
flex-direction: column;
gap: 8px;
}
.indicator-item label {
font-size: 13px;
color: var(--text-muted);
}
.indicator-item span {
font-size: 16px;
font-weight: 600;
color: var(--text-primary);
}
.indicator-bar {
width: 100%;
height: 6px;
background: rgba(255, 255, 255, 0.1);
border-radius: 3px;
overflow: hidden;
}
.indicator-fill {
height: 100%;
background: linear-gradient(90deg, var(--accent-color), var(--success-color));
border-radius: 3px;
transition: width 0.5s ease;
}
/* 风险建议样式 */
.risk-suggestions p {
margin-bottom: 8px;
padding: 8px 12px;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
border-left: 3px solid var(--accent-color);
}
/* 预警通知样式 */
.alert-notification {
position: fixed;
top: 20px;
right: 20px;
max-width: 400px;
background: var(--bg-secondary);
border: 1px solid var(--border-color);
border-radius: 12px;
box-shadow: var(--shadow-heavy);
z-index: 3000;
animation: slideInRight 0.3s ease;
}
@keyframes slideInRight {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: translateX(0);
opacity: 1;
}
}
.alert-header {
padding: 15px;
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
gap: 10px;
}
.alert-icon {
font-size: 18px;
}
.alert-title {
flex: 1;
font-weight: 600;
color: var(--text-primary);
}