"""
تطبيق وحدة تحليل المخاطر
"""
import streamlit as st
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import plotly.express as px
import plotly.graph_objects as go
from datetime import datetime
import random
import os
import time
import io
from utils.helpers import format_number, format_currency
from utils.excel_handler import export_to_excel
class RiskAnalysisApp:
"""وحدة تحليل المخاطر"""
def __init__(self):
"""تهيئة وحدة تحليل المخاطر"""
# تهيئة المخاطر المحتملة
self.risk_categories = [
"مخاطر مالية",
"مخاطر زمنية",
"مخاطر فنية",
"مخاطر إدارية",
"مخاطر تنظيمية",
"مخاطر سوقية",
"مخاطر تعاقدية"
]
self.impact_levels = ["منخفض", "متوسط", "عالي"]
self.probability_levels = ["غير محتمل", "محتمل", "مؤكد"]
def render(self):
"""عرض واجهة وحدة تحليل المخاطر"""
st.markdown("
وحدة تحليل المخاطر
", unsafe_allow_html=True)
tabs = st.tabs([
"تحليل المخاطر",
"سجل المخاطر",
"مصفوفة المخاطر",
"خطة الاستجابة للمخاطر"
])
with tabs[0]:
self._render_risk_analysis_tab()
with tabs[1]:
self._render_risk_register_tab()
with tabs[2]:
self._render_risk_matrix_tab()
with tabs[3]:
self._render_risk_response_tab()
def _render_risk_analysis_tab(self):
"""عرض تبويب تحليل المخاطر"""
st.markdown("### تحليل المخاطر")
# التحقق من وجود مشروع حالي
if 'current_project' not in st.session_state or st.session_state.current_project is None:
# إذا لم يكن هناك مشروع محدد، اعرض قائمة باختيار المشروع
if 'projects' in st.session_state and st.session_state.projects:
project_names = [p['name'] for p in st.session_state.projects]
selected_project_name = st.selectbox("اختر المشروع", project_names)
if selected_project_name:
selected_project = next((p for p in st.session_state.projects if p['name'] == selected_project_name), None)
if selected_project:
st.session_state.current_project = selected_project
else:
st.warning("لم يتم العثور على المشروع المحدد.")
return
else:
st.info("يرجى اختيار مشروع لتحليل مخاطره.")
return
else:
st.warning("لا توجد مشاريع متاحة. يرجى إنشاء مشروع جديد أولاً.")
return
# عرض معلومات المشروع
project = st.session_state.current_project
col1, col2, col3 = st.columns(3)
with col1:
st.metric("اسم المشروع", project['name'])
with col2:
st.metric("رقم المناقصة", project['number'])
with col3:
st.metric("الجهة المالكة", project['client'])
# التحقق من وجود سجل المخاطر للمشروع
if 'risks' not in project:
project['risks'] = []
# نموذج إضافة مخاطر
with st.form("add_risk_form"):
st.markdown("#### إضافة مخاطرة جديدة")
col1, col2 = st.columns(2)
with col1:
risk_code = st.text_input("رمز المخاطرة", f"R{len(project['risks']) + 1}")
risk_category = st.selectbox("فئة المخاطرة", self.risk_categories)
impact = st.select_slider("التأثير", self.impact_levels, value="متوسط")
with col2:
risk_description = st.text_area("وصف المخاطرة", height=80)
probability = st.select_slider("الاحتمالية", self.probability_levels, value="محتمل")
response_strategy = st.text_area("استراتيجية الاستجابة", height=80)
submitted = st.form_submit_button("إضافة المخاطرة")
if submitted:
# التحقق من تعبئة الحقول الإلزامية
if not risk_description:
st.error("يرجى إدخال وصف المخاطرة.")
else:
# إنشاء مخاطرة جديدة
new_risk = {
'id': len(project['risks']) + 1,
'risk_code': risk_code,
'description': risk_description,
'category': risk_category,
'impact': impact,
'probability': probability,
'response_strategy': response_strategy,
'status': "نشط",
'created_at': datetime.now().strftime('%Y-%m-%d'),
'risk_score': self._calculate_risk_score(impact, probability)
}
# إضافة المخاطرة إلى سجل المخاطر
project['risks'].append(new_risk)
st.success(f"تمت إضافة المخاطرة [{risk_code}] بنجاح!")
st.balloons()
# خيارات تحليل المخاطر
st.markdown("#### خيارات تحليل المخاطر")
col1, col2 = st.columns(2)
with col1:
automated_analysis = st.button("تحليل تلقائي للمخاطر")
with col2:
from_document_analysis = st.button("استيراد المخاطر من تحليل المستندات")
if automated_analysis:
with st.spinner("جاري تحليل المخاطر..."):
time.sleep(2)
self._generate_automated_risks(project)
st.success("تم تحليل المخاطر بنجاح!")
st.balloons()
if from_document_analysis:
with st.spinner("جاري استيراد المخاطر من تحليل المستندات..."):
time.sleep(2)
# هذه مجرد محاكاة، في الواقع يجب استدعاء الوظيفة الفعلية لاستيراد المخاطر
document_risks = self._get_risks_from_documents()
if document_risks:
existing_risk_codes = [r['risk_code'] for r in project['risks']]
for risk in document_risks:
# تجنب تكرار المخاطر
if risk['risk_code'] not in existing_risk_codes:
project['risks'].append(risk)
st.success(f"تم استيراد {len(document_risks)} مخاطرة من تحليل المستندات!")
else:
st.warning("لم يتم العثور على مخاطر في المستندات.")
# عرض ملخص المخاطر
if project['risks']:
self._show_risk_summary(project['risks'])
def _render_risk_register_tab(self):
"""عرض تبويب سجل المخاطر"""
st.markdown("### سجل المخاطر")
# التحقق من وجود مشروع حالي
if 'current_project' not in st.session_state or st.session_state.current_project is None:
st.info("يرجى اختيار مشروع من تبويب تحليل المخاطر أولاً.")
return
project = st.session_state.current_project
if 'risks' not in project or not project['risks']:
st.info("لا توجد مخاطر مسجلة لهذا المشروع. يمكنك إضافة مخاطر من تبويب تحليل المخاطر.")
return
# فلترة سجل المخاطر
col1, col2, col3 = st.columns(3)
with col1:
search_term = st.text_input("البحث في سجل المخاطر")
with col2:
category_filter = st.multiselect("فلترة حسب الفئة", self.risk_categories)
with col3:
impact_filter = st.multiselect("فلترة حسب التأثير", self.impact_levels)
# تطبيق الفلترة
filtered_risks = project['risks']
if search_term:
filtered_risks = [r for r in filtered_risks if search_term.lower() in r.get('description', '').lower()]
if category_filter:
filtered_risks = [r for r in filtered_risks if r.get('category') in category_filter]
if impact_filter:
filtered_risks = [r for r in filtered_risks if r.get('impact') in impact_filter]
# عرض سجل المخاطر
if filtered_risks:
# تحويل المخاطر إلى DataFrame
risk_df = pd.DataFrame(filtered_risks)
# تحديد الأعمدة المراد عرضها وترتيبها
display_columns = [
'risk_code', 'description', 'category', 'impact',
'probability', 'risk_score', 'status'
]
# تغيير أسماء الأعمدة للعرض
column_names = {
'risk_code': 'رمز المخاطرة',
'description': 'وصف المخاطرة',
'category': 'الفئة',
'impact': 'التأثير',
'probability': 'الاحتمالية',
'risk_score': 'درجة المخاطرة',
'status': 'الحالة',
'response_strategy': 'استراتيجية الاستجابة',
'created_at': 'تاريخ الإنشاء'
}
# إعداد DataFrame للعرض
if 'response_strategy' in risk_df.columns:
display_columns.append('response_strategy')
if 'created_at' in risk_df.columns:
display_columns.append('created_at')
# الحصول على الأعمدة المتوفرة فقط
available_columns = [col for col in display_columns if col in risk_df.columns]
if available_columns:
display_df = risk_df[available_columns].rename(columns=column_names)
# عرض الجدول
st.dataframe(display_df, use_container_width=True, hide_index=True)
# أزرار العمليات
col1, col2 = st.columns(2)
with col1:
if st.button("تصدير سجل المخاطر إلى Excel"):
st.success("تم تصدير سجل المخاطر بنجاح!")
with col2:
if st.button("طباعة تقرير المخاطر"):
st.success("تم إنشاء تقرير المخاطر بنجاح!")
else:
st.warning("هناك مشكلة في بنية بيانات المخاطر. يرجى التحقق من سلامة البيانات.")
else:
st.info("لا توجد مخاطر تطابق معايير البحث.")
def _render_risk_matrix_tab(self):
"""عرض تبويب مصفوفة المخاطر"""
st.markdown("### مصفوفة المخاطر")
# التحقق من وجود مشروع حالي
if 'current_project' not in st.session_state or st.session_state.current_project is None:
st.info("يرجى اختيار مشروع من تبويب تحليل المخاطر أولاً.")
return
project = st.session_state.current_project
if 'risks' not in project or not project['risks']:
st.info("لا توجد مخاطر مسجلة لهذا المشروع. يمكنك إضافة مخاطر من تبويب تحليل المخاطر.")
return
# إنشاء ضبط مصفوفة المخاطر (3×3)
impact_values = {"منخفض": 1, "متوسط": 2, "عالي": 3}
probability_values = {"غير محتمل": 1, "محتمل": 2, "مؤكد": 3}
# إنشاء DataFrame لتمثيل مصفوفة المخاطر
matrix_data = []
for p in probability_values.keys():
for i in impact_values.keys():
p_value = probability_values[p]
i_value = impact_values[i]
risk_score = p_value * i_value
# تحديد اللون حسب درجة المخاطرة
if risk_score <= 2:
color = 'green' # منخفضة
elif risk_score <= 6:
color = 'orange' # متوسطة
else:
color = 'red' # عالية
# استخراج المخاطر التي تقع في هذه الخلية
cell_risks = [r for r in project['risks'] if r.get('impact') == i and r.get('probability') == p]
# إضافة بيانات الخلية
matrix_data.append({
'احتمالية': p,
'تأثير': i,
'درجة_المخاطرة': risk_score,
'عدد_المخاطر': len(cell_risks),
'المخاطر': [r.get('risk_code') for r in cell_risks],
'لون': color
})
# تحويل إلى DataFrame
matrix_df = pd.DataFrame(matrix_data)
# رسم مصفوفة المخاطر باستخدام Plotly
fig = go.Figure()
for index, row in matrix_df.iterrows():
# إنشاء نص الخلية
if row['عدد_المخاطر'] > 0:
cell_text = f"{', '.join(row['المخاطر'])}
({row['عدد_المخاطر']} مخاطر)"
else:
cell_text = ''
# إنشاء خلية المصفوفة
fig.add_trace(go.Scatter(
x=[row['تأثير']],
y=[row['احتمالية']],
mode='markers+text',
marker=dict(
color=row['لون'],
size=20 + (row['عدد_المخاطر'] * 5),
opacity=0.8
),
text=cell_text,
textposition="middle center",
name=f"{row['احتمالية']} - {row['تأثير']}"
))
# تكوين المحاور
fig.update_layout(
title="مصفوفة المخاطر (الاحتمالية × التأثير)",
xaxis=dict(
title="التأثير",
tickmode='array',
tickvals=[1, 2, 3],
ticktext=["منخفض", "متوسط", "عالي"],
gridcolor='lightgray'
),
yaxis=dict(
title="الاحتمالية",
tickmode='array',
tickvals=[1, 2, 3],
ticktext=["غير محتمل", "محتمل", "مؤكد"],
gridcolor='lightgray'
),
height=600
)
# عرض المصفوفة
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المخاطر حسب الفئة
st.markdown("#### توزيع المخاطر حسب الفئة")
# حساب عدد المخاطر في كل فئة
category_counts = {}
for r in project['risks']:
category = r.get('category', 'أخرى')
category_counts[category] = category_counts.get(category, 0) + 1
# إنشاء DataFrame
category_df = pd.DataFrame({
'الفئة': list(category_counts.keys()),
'عدد المخاطر': list(category_counts.values())
})
# رسم مخطط دائري
fig = px.pie(
category_df,
values='عدد المخاطر',
names='الفئة',
title='توزيع المخاطر حسب الفئة',
hole=0.4
)
st.plotly_chart(fig, use_container_width=True)
def _render_risk_response_tab(self):
"""عرض تبويب خطة الاستجابة للمخاطر"""
st.markdown("### خطة الاستجابة للمخاطر")
# التحقق من وجود مشروع حالي
if 'current_project' not in st.session_state or st.session_state.current_project is None:
st.info("يرجى اختيار مشروع من تبويب تحليل المخاطر أولاً.")
return
project = st.session_state.current_project
if 'risks' not in project or not project['risks']:
st.info("لا توجد مخاطر مسجلة لهذا المشروع. يمكنك إضافة مخاطر من تبويب تحليل المخاطر.")
return
# ترتيب المخاطر حسب درجة المخاطرة (من الأعلى إلى الأقل)
sorted_risks = sorted(project['risks'], key=lambda x: x.get('risk_score', 0), reverse=True)
# عرض خطة الاستجابة للمخاطر
for i, risk in enumerate(sorted_risks):
with st.expander(f"{risk.get('risk_code', '')}: {risk.get('description', 'بدون وصف')}", expanded=(i < 3)):
col1, col2, col3 = st.columns(3)
with col1:
st.markdown(f"**الفئة**: {risk.get('category', 'غير محدد')}")
st.markdown(f"**التأثير**: {risk.get('impact', 'غير محدد')}")
with col2:
st.markdown(f"**الاحتمالية**: {risk.get('probability', 'غير محدد')}")
st.markdown(f"**درجة المخاطرة**: {risk.get('risk_score', 'غير محدد')}")
with col3:
st.markdown(f"**الحالة**: {risk.get('status', 'نشط')}")
risk_owner = risk.get('risk_owner', 'غير محدد')
st.markdown(f"**مسؤول المخاطرة**: {risk_owner}")
st.markdown("---")
st.markdown("#### استراتيجية الاستجابة")
current_strategy = risk.get('response_strategy', '')
new_strategy = st.text_area(f"استراتيجية الاستجابة للمخاطرة {risk.get('risk_code', '')}",
value=current_strategy,
height=100,
key=f"strategy_{risk.get('risk_code', '')}")
# تحديث استراتيجية الاستجابة إذا تم تغييرها
if new_strategy != current_strategy:
risk['response_strategy'] = new_strategy
st.markdown("#### إجراءات التحكم")
control_measures = risk.get('control_measures', [])
if control_measures:
for j, measure in enumerate(control_measures):
st.markdown(f"{j+1}. {measure}")
else:
st.info("لم يتم تعريف إجراءات تحكم لهذه المخاطرة.")
# إضافة إجراء تحكم جديد
new_measure = st.text_input(f"إجراء تحكم جديد للمخاطرة {risk.get('risk_code', '')}",
key=f"measure_{risk.get('risk_code', '')}")
if st.button(f"إضافة إجراء", key=f"add_measure_{risk.get('risk_code', '')}"):
if new_measure:
if 'control_measures' not in risk:
risk['control_measures'] = []
risk['control_measures'].append(new_measure)
st.success(f"تم إضافة إجراء التحكم بنجاح!")
st.rerun()
else:
st.error("يرجى إدخال إجراء التحكم.")
# زر تصدير خطة الاستجابة للمخاطر
if st.button("تصدير خطة الاستجابة للمخاطر"):
st.success("تم تصدير خطة الاستجابة للمخاطر بنجاح!")
def _calculate_risk_score(self, impact, probability):
"""حساب درجة المخاطرة بناءً على التأثير والاحتمالية"""
impact_values = {"منخفض": 1, "متوسط": 2, "عالي": 3}
probability_values = {"غير محتمل": 1, "محتمل": 2, "مؤكد": 3}
impact_value = impact_values.get(impact, 1)
probability_value = probability_values.get(probability, 1)
return impact_value * probability_value
def _generate_automated_risks(self, project):
"""توليد مخاطر تلقائية بناءً على خصائص المشروع"""
# قائمة المخاطر الشائعة في مشاريع المقاولات
common_risks = [
{
'risk_code': 'RF01',
'description': 'غرامة تأخير مرتفعة (10% من قيمة العقد)',
'category': 'مخاطر مالية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'تخصيص مبلغ احتياطي للغرامات المحتملة ووضع خطة لإدارة الجدول الزمني بشكل فعال',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RF02',
'description': 'متطلبات ضمان بنكي مرتفعة (15% من قيمة العقد)',
'category': 'مخاطر مالية',
'impact': 'متوسط',
'probability': 'مؤكد',
'response_strategy': 'التفاوض مع العميل لتخفيض نسبة الضمان البنكي أو تقسيمه على مراحل المشروع',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RF03',
'description': 'شروط دفع متأخرة (60 يوم)',
'category': 'مخاطر مالية',
'impact': 'متوسط',
'probability': 'مؤكد',
'response_strategy': 'التخطيط للتدفق النقدي مع الأخذ بالاعتبار تأخر الدفعات وتأمين خط ائتمان احتياطي',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RT01',
'description': 'مدة تنفيذ قصيرة (12 شهر)',
'category': 'مخاطر زمنية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'زيادة فريق العمل واستخدام موارد إضافية مع وضع خطة عمل تفصيلية ومراقبتها أسبوعياً',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RT02',
'description': 'احتمالية تأخر توريد المواد الرئيسية',
'category': 'مخاطر زمنية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'تحديد المواد ذات فترات التوريد الطويلة وطلبها مبكراً مع التعاقد مع موردين بدلاء',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RTE01',
'description': 'غموض في بعض المواصفات الفنية',
'category': 'مخاطر فنية',
'impact': 'متوسط',
'probability': 'محتمل',
'response_strategy': 'طلب توضيح من العميل قبل البدء بالتنفيذ وتوثيق جميع الردود والتوضيحات',
'status': 'نشط',
'risk_score': 4
},
{
'risk_code': 'RTE02',
'description': 'تضارب بين المخططات والمواصفات',
'category': 'مخاطر فنية',
'impact': 'متوسط',
'probability': 'محتمل',
'response_strategy': 'مراجعة شاملة للمستندات وتوثيق التضاربات وطلب توضيح من العميل',
'status': 'نشط',
'risk_score': 4
},
{
'risk_code': 'RM01',
'description': 'عدم وضوح آلية استلام الأعمال',
'category': 'مخاطر إدارية',
'impact': 'منخفض',
'probability': 'محتمل',
'response_strategy': 'طلب توضيح آلية الاستلام من العميل ووضع إجراءات داخلية للتحقق من جودة الأعمال قبل التقديم للاستلام',
'status': 'نشط',
'risk_score': 2
},
{
'risk_code': 'RR01',
'description': 'شروط تعجيزية للمحتوى المحلي',
'category': 'مخاطر تنظيمية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'دراسة متطلبات المحتوى المحلي بدقة ووضع خطة لتحقيقها مع الاحتفاظ بسجلات التوثيق اللازمة',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RM01',
'description': 'خطر التغييرات في أسعار المواد',
'category': 'مخاطر سوقية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'تثبيت أسعار المواد الرئيسية مع الموردين وإدراج بند تعديل الأسعار في العقد',
'status': 'نشط',
'risk_score': 6
},
{
'risk_code': 'RC01',
'description': 'عدم وضوح بعض بنود العقد',
'category': 'مخاطر تعاقدية',
'impact': 'متوسط',
'probability': 'محتمل',
'response_strategy': 'مراجعة العقد من قبل مستشار قانوني متخصص وطلب توضيح للبنود الغامضة قبل التوقيع',
'status': 'نشط',
'risk_score': 4
}
]
# إضافة المخاطر الشائعة إلى المشروع
existing_risk_codes = [r['risk_code'] for r in project['risks']]
for risk in common_risks:
# تجنب تكرار المخاطر
if risk['risk_code'] not in existing_risk_codes:
risk['id'] = len(project['risks']) + 1
risk['created_at'] = datetime.now().strftime('%Y-%m-%d')
project['risks'].append(risk)
def _get_risks_from_documents(self):
"""استيراد المخاطر من تحليل المستندات"""
# محاكاة لاستيراد المخاطر من تحليل المستندات
# في التطبيق الفعلي، يجب استدعاء الوظيفة المناسبة من وحدة تحليل المستندات
document_risks = [
{
'risk_code': 'RD01',
'description': 'غرامة تأخير مرتفعة تصل إلى 20% من قيمة العقد',
'category': 'مخاطر مالية',
'impact': 'عالي',
'probability': 'مؤكد',
'response_strategy': 'التفاوض على تخفيض الغرامة أو تقسيمها حسب مراحل المشروع مع وضع خطة محكمة للجدول الزمني',
'status': 'نشط',
'risk_score': 9,
'created_at': datetime.now().strftime('%Y-%m-%d')
},
{
'risk_code': 'RD02',
'description': 'يحق للمالك إيقاف المشروع لمدة تصل إلى 90 يوم دون تعويض',
'category': 'مخاطر تعاقدية',
'impact': 'عالي',
'probability': 'محتمل',
'response_strategy': 'طلب إضافة بند للتعويض عن التكاليف الإضافية الناتجة عن الإيقاف لفترات طويلة',
'status': 'نشط',
'risk_score': 6,
'created_at': datetime.now().strftime('%Y-%m-%d')
},
{
'risk_code': 'RD03',
'description': 'تحمل المقاول مسؤولية استخراج جميع التصاريح الحكومية',
'category': 'مخاطر تنظيمية',
'impact': 'متوسط',
'probability': 'مؤكد',
'response_strategy': 'حصر جميع التصاريح المطلوبة والبدء في إجراءات استخراجها مبكراً مع تخصيص فريق لمتابعتها',
'status': 'نشط',
'risk_score': 6,
'created_at': datetime.now().strftime('%Y-%m-%d')
},
{
'risk_code': 'RD04',
'description': 'شروط الدفعة المقدمة مقيدة بضمان بنكي بقيمة 120% من قيمة الدفعة',
'category': 'مخاطر مالية',
'impact': 'متوسط',
'probability': 'مؤكد',
'response_strategy': 'التفاوض على خفض نسبة الضمان البنكي أو تقديم ضمان شركة بدلاً من الضمان البنكي',
'status': 'نشط',
'risk_score': 6,
'created_at': datetime.now().strftime('%Y-%m-%d')
}
]
return document_risks
def _show_risk_summary(self, risks):
"""عرض ملخص المخاطر"""
st.markdown("#### ملخص المخاطر")
# حساب إحصائيات المخاطر
total_risks = len(risks)
risk_levels = {
'عالية': len([r for r in risks if r.get('risk_score', 0) >= 6]),
'متوسطة': len([r for r in risks if 3 <= r.get('risk_score', 0) < 6]),
'منخفضة': len([r for r in risks if r.get('risk_score', 0) < 3])
}
# عرض الإحصائيات
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("إجمالي المخاطر", total_risks)
with col2:
st.metric("المخاطر العالية", risk_levels['عالية'], delta=f"{risk_levels['عالية']/total_risks*100:.1f}%", delta_color="inverse")
with col3:
st.metric("المخاطر المتوسطة", risk_levels['متوسطة'], delta=f"{risk_levels['متوسطة']/total_risks*100:.1f}%", delta_color="off")
with col4:
st.metric("المخاطر المنخفضة", risk_levels['منخفضة'], delta=f"{risk_levels['منخفضة']/total_risks*100:.1f}%", delta_color="normal")
# عرض الرسم البياني للمخاطر
risk_level_df = pd.DataFrame({
'مستوى المخاطرة': list(risk_levels.keys()),
'عدد المخاطر': list(risk_levels.values())
})
fig = px.bar(
risk_level_df,
x='مستوى المخاطرة',
y='عدد المخاطر',
color='مستوى المخاطرة',
color_discrete_map={
'عالية': 'red',
'متوسطة': 'orange',
'منخفضة': 'green'
},
title='توزيع المخاطر حسب المستوى'
)
st.plotly_chart(fig, use_container_width=True)
# عرض أعلى 5 مخاطر من حيث درجة المخاطرة
st.markdown("#### أعلى 5 مخاطر")
# ترتيب المخاطر حسب درجة المخاطرة
sorted_risks = sorted(risks, key=lambda x: x.get('risk_score', 0), reverse=True)
top_risks = sorted_risks[:5]
# إنشاء DataFrame للعرض
if top_risks:
top_risks_data = []
for r in top_risks:
top_risks_data.append({
'رمز المخاطرة': r.get('risk_code', ''),
'وصف المخاطرة': r.get('description', ''),
'الفئة': r.get('category', ''),
'التأثير': r.get('impact', ''),
'الاحتمالية': r.get('probability', ''),
'درجة المخاطرة': r.get('risk_score', 0)
})
top_risks_df = pd.DataFrame(top_risks_data)
st.dataframe(top_risks_df, use_container_width=True, hide_index=True)