|
import streamlit as st |
|
import pandas as pd |
|
import plotly.express as px |
|
from datetime import datetime, timedelta |
|
import time |
|
|
|
class ReportsApp: |
|
"""وحدة التقارير والتحليلات""" |
|
|
|
def __init__(self): |
|
"""تهيئة وحدة التقارير والتحليلات""" |
|
|
|
if 'theme' not in st.session_state: |
|
st.session_state.theme = 'light' |
|
|
|
def run(self): |
|
""" |
|
تشغيل وحدة التقارير والتحليلات |
|
|
|
هذه الدالة هي نقطة الدخول الرئيسية لوحدة التقارير والتحليلات. |
|
تقوم بتهيئة واجهة المستخدم وعرض الوظائف المختلفة للتقارير والتحليلات. |
|
""" |
|
try: |
|
|
|
st.set_page_config( |
|
page_title="وحدة التقارير والتحليلات - نظام المناقصات", |
|
page_icon="📊", |
|
layout="wide", |
|
initial_sidebar_state="expanded" |
|
) |
|
|
|
|
|
st.markdown(""" |
|
<style> |
|
.module-title { |
|
color: #2c3e50; |
|
text-align: center; |
|
font-size: 2.5rem; |
|
margin-bottom: 1rem; |
|
padding-bottom: 1rem; |
|
border-bottom: 2px solid #3498db; |
|
} |
|
.stTabs [data-baseweb="tab-list"] { |
|
gap: 10px; |
|
} |
|
.stTabs [data-baseweb="tab"] { |
|
height: 50px; |
|
white-space: pre-wrap; |
|
background-color: #f8f9fa; |
|
border-radius: 4px 4px 0px 0px; |
|
gap: 1px; |
|
padding-top: 10px; |
|
padding-bottom: 10px; |
|
} |
|
.stTabs [aria-selected="true"] { |
|
background-color: #3498db; |
|
color: white; |
|
} |
|
</style> |
|
""", unsafe_allow_html=True) |
|
|
|
|
|
col1, col2, col3 = st.columns([1, 8, 1]) |
|
with col3: |
|
if st.button("🌓 تبديل السمة"): |
|
|
|
if st.session_state.theme == "light": |
|
st.session_state.theme = "dark" |
|
else: |
|
st.session_state.theme = "light" |
|
|
|
|
|
st.rerun() |
|
|
|
|
|
with st.sidebar: |
|
st.image("/home/ubuntu/tender_system/tender_system/assets/images/logo.png", width=200) |
|
st.markdown("## نظام تحليل المناقصات") |
|
st.markdown("### وحدة التقارير والتحليلات") |
|
|
|
st.markdown("---") |
|
|
|
|
|
st.markdown("### خيارات التصفية") |
|
|
|
|
|
date_range = st.selectbox( |
|
"الفترة الزمنية", |
|
["آخر 7 أيام", "آخر 30 يوم", "آخر 90 يوم", "آخر 365 يوم", "كل الفترات"] |
|
) |
|
|
|
|
|
project_type = st.multiselect( |
|
"نوع المشروع", |
|
["مباني", "طرق", "جسور", "أنفاق", "بنية تحتية", "أخرى"], |
|
default=["مباني", "طرق", "جسور", "أنفاق", "بنية تحتية", "أخرى"] |
|
) |
|
|
|
|
|
project_status = st.multiselect( |
|
"حالة المشروع", |
|
["جديد", "قيد التقديم", "تم التقديم", "فائز", "خاسر", "ملغي"], |
|
default=["جديد", "قيد التقديم", "تم التقديم", "فائز", "خاسر"] |
|
) |
|
|
|
|
|
if st.button("تطبيق التصفية"): |
|
st.success("تم تطبيق التصفية بنجاح!") |
|
|
|
st.markdown("---") |
|
|
|
|
|
st.markdown("### معلومات المستخدم") |
|
st.markdown("**المستخدم:** مهندس تامر الجوهري") |
|
st.markdown("**الدور:** محلل مناقصات") |
|
st.markdown("**تاريخ آخر دخول:** " + datetime.now().strftime("%Y-%m-%d %H:%M")) |
|
|
|
|
|
self.render() |
|
|
|
|
|
st.markdown("---") |
|
st.markdown("### نظام تحليل المناقصات - وحدة التقارير والتحليلات") |
|
st.markdown("**الإصدار:** 2.0.0") |
|
st.markdown("**تاريخ التحديث:** 2025-03-31") |
|
st.markdown("**جميع الحقوق محفوظة © 2025**") |
|
|
|
return True |
|
|
|
except Exception as e: |
|
st.error(f"حدث خطأ أثناء تشغيل وحدة التقارير والتحليلات: {str(e)}") |
|
return False |
|
|
|
def render(self): |
|
"""عرض واجهة وحدة التقارير والتحليلات""" |
|
|
|
st.markdown("<h1 class='module-title'>وحدة التقارير والتحليلات</h1>", unsafe_allow_html=True) |
|
|
|
tabs = st.tabs(["لوحة المعلومات", "تقارير المشاريع", "تقارير التسعير", "تقارير المخاطر", "التقارير المخصصة"]) |
|
|
|
with tabs[0]: |
|
self._render_dashboard_tab() |
|
|
|
with tabs[1]: |
|
self._render_projects_reports_tab() |
|
|
|
with tabs[2]: |
|
self._render_pricing_reports_tab() |
|
|
|
with tabs[3]: |
|
self._render_risk_reports_tab() |
|
|
|
with tabs[4]: |
|
self._render_custom_reports_tab() |
|
|
|
def _render_dashboard_tab(self): |
|
"""عرض تبويب لوحة المعلومات""" |
|
|
|
st.markdown("### لوحة معلومات النظام") |
|
|
|
col1, col2, col3, col4 = st.columns(4) |
|
|
|
with col1: |
|
total_projects = self._get_total_projects() |
|
st.metric("إجمالي المشاريع", total_projects) |
|
|
|
with col2: |
|
active_projects = self._get_active_projects() |
|
st.metric("المشاريع النشطة", active_projects, delta=f"{active_projects/total_projects*100:.1f}%" if total_projects > 0 else "0%") |
|
|
|
with col3: |
|
won_projects = self._get_won_projects() |
|
st.metric("المشاريع المرساة", won_projects, delta=f"{won_projects/total_projects*100:.1f}%" if total_projects > 0 else "0%") |
|
|
|
with col4: |
|
avg_local_content = self._get_avg_local_content() |
|
st.metric("متوسط المحتوى المحلي", f"{avg_local_content:.1f}%", delta=f"{avg_local_content-70:.1f}%" if avg_local_content > 0 else "0%") |
|
|
|
st.markdown("#### توزيع المشاريع حسب الحالة") |
|
project_status_data = self._get_project_status_data() |
|
fig = px.pie(project_status_data, values='count', names='status', title='توزيع المشاريع حسب الحالة', hole=0.4) |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
st.markdown("#### اتجاه المشاريع الشهري") |
|
monthly_data = self._get_monthly_project_data() |
|
fig = px.line(monthly_data, x='month', y=['new', 'submitted', 'won'], title='اتجاه المشاريع الشهري') |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
st.markdown("#### توزيع المشاريع حسب النوع") |
|
project_type_data = self._get_project_type_data() |
|
fig = px.bar(project_type_data, x='type', y='count', title='توزيع المشاريع حسب النوع') |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
with col2: |
|
st.markdown("#### توزيع المشاريع حسب الموقع") |
|
project_location_data = self._get_project_location_data() |
|
fig = px.bar(project_location_data, x='location', y='count', title='توزيع المشاريع حسب الموقع') |
|
st.plotly_chart(fig, use_container_width=True) |
|
|
|
st.markdown("#### أحدث المشاريع") |
|
latest_projects = self._get_latest_projects() |
|
st.dataframe(latest_projects) |
|
|
|
def _render_projects_reports_tab(self): |
|
"""عرض تبويب تقارير المشاريع""" |
|
|
|
st.markdown("### تقارير المشاريع") |
|
|
|
report_type = st.selectbox( |
|
"نوع التقرير", |
|
["تقرير حالة المشاريع", "تقرير أداء المشاريع", "تقرير المشاريع المتأخرة", "تقرير المشاريع المكتملة"] |
|
) |
|
|
|
if report_type == "تقرير حالة المشاريع": |
|
self._render_project_status_report() |
|
elif report_type == "تقرير أداء المشاريع": |
|
self._render_project_performance_report() |
|
elif report_type == "تقرير المشاريع المتأخرة": |
|
self._render_delayed_projects_report() |
|
elif report_type == "تقرير المشاريع المكتملة": |
|
self._render_completed_projects_report() |
|
|
|
def _render_pricing_reports_tab(self): |
|
"""عرض تبويب تقارير التسعير""" |
|
|
|
st.markdown("### تقارير التسعير") |
|
|
|
report_type = st.selectbox( |
|
"نوع التقرير", |
|
["تقرير تحليل الأسعار", "تقرير مقارنة الأسعار", "تقرير اتجاهات الأسعار", "تقرير تحليل المنافسين"] |
|
) |
|
|
|
if report_type == "تقرير تحليل الأسعار": |
|
self._render_price_analysis_report() |
|
elif report_type == "تقرير مقارنة الأسعار": |
|
self._render_price_comparison_report() |
|
elif report_type == "تقرير اتجاهات الأسعار": |
|
self._render_price_trends_report() |
|
elif report_type == "تقرير تحليل المنافسين": |
|
self._render_competitors_analysis_report() |
|
|
|
def _render_risk_reports_tab(self): |
|
"""عرض تبويب تقارير المخاطر""" |
|
|
|
st.markdown("### تقارير المخاطر") |
|
|
|
report_type = st.selectbox( |
|
"نوع التقرير", |
|
["تقرير تحليل المخاطر", "تقرير مصفوفة المخاطر", "تقرير متابعة المخاطر", "تقرير استراتيجيات التخفيف"] |
|
) |
|
|
|
if report_type == "تقرير تحليل المخاطر": |
|
self._render_risk_analysis_report() |
|
elif report_type == "تقرير مصفوفة المخاطر": |
|
self._render_risk_matrix_report() |
|
elif report_type == "تقرير متابعة المخاطر": |
|
self._render_risk_monitoring_report() |
|
elif report_type == "تقرير استراتيجيات التخفيف": |
|
self._render_risk_mitigation_report() |
|
|
|
def _render_custom_reports_tab(self): |
|
"""عرض تبويب التقارير المخصصة""" |
|
|
|
st.markdown("### التقارير المخصصة") |
|
|
|
st.markdown("#### إنشاء تقرير مخصص") |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
report_name = st.text_input("اسم التقرير") |
|
report_description = st.text_area("وصف التقرير") |
|
|
|
with col2: |
|
report_fields = st.multiselect( |
|
"حقول التقرير", |
|
["رقم المشروع", "اسم المشروع", "نوع المشروع", "حالة المشروع", "تاريخ البدء", "تاريخ الانتهاء", "الميزانية", "التكلفة الفعلية", "نسبة الإنجاز", "المخاطر", "الموقع", "المالك", "المقاول"] |
|
) |
|
|
|
report_filters = st.multiselect( |
|
"تصفية التقرير", |
|
["نوع المشروع", "حالة المشروع", "الفترة الزمنية", "الميزانية", "الموقع", "المالك", "المقاول"] |
|
) |
|
|
|
if st.button("إنشاء التقرير"): |
|
if report_name and report_description and report_fields: |
|
with st.spinner("جاري إنشاء التقرير..."): |
|
time.sleep(2) |
|
st.success("تم إنشاء التقرير بنجاح!") |
|
|
|
|
|
custom_report_data = self._generate_custom_report(report_fields) |
|
st.dataframe(custom_report_data) |
|
|
|
|
|
st.download_button( |
|
label="تصدير التقرير (Excel)", |
|
data=self._export_to_excel(custom_report_data), |
|
file_name=f"{report_name}.xlsx", |
|
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" |
|
) |
|
else: |
|
st.warning("يرجى ملء جميع الحقول المطلوبة") |
|
|
|
st.markdown("#### التقارير المخصصة المحفوظة") |
|
|
|
saved_reports = [ |
|
{"id": 1, "name": "تقرير المشاريع المتأخرة في الرياض", "created_at": "2025-03-15", "last_run": "2025-03-30"}, |
|
{"id": 2, "name": "تقرير مشاريع الطرق ذات المخاطر العالية", "created_at": "2025-03-10", "last_run": "2025-03-28"}, |
|
{"id": 3, "name": "تقرير المشاريع المكتملة في الربع الأول", "created_at": "2025-03-05", "last_run": "2025-03-25"} |
|
] |
|
|
|
saved_reports_df = pd.DataFrame(saved_reports) |
|
st.dataframe(saved_reports_df) |
|
|
|
|
|
|
|
def _get_total_projects(self): |
|
"""الحصول على إجمالي عدد المشاريع""" |
|
|
|
return 120 |
|
|
|
def _get_active_projects(self): |
|
"""الحصول على عدد المشاريع النشطة""" |
|
|
|
return 45 |
|
|
|
def _get_won_projects(self): |
|
"""الحصول على عدد المشاريع المرساة""" |
|
|
|
return 30 |
|
|
|
def _get_avg_local_content(self): |
|
"""الحصول على متوسط المحتوى المحلي""" |
|
|
|
return 75.5 |
|
|
|
def _get_project_status_data(self): |
|
"""الحصول على بيانات توزيع المشاريع حسب الحالة""" |
|
|
|
data = { |
|
'status': ['جديد', 'قيد التقديم', 'تم التقديم', 'فائز', 'خاسر', 'ملغي'], |
|
'count': [25, 20, 15, 30, 25, 5] |
|
} |
|
return pd.DataFrame(data) |
|
|
|
def _get_monthly_project_data(self): |
|
"""الحصول على بيانات اتجاه المشاريع الشهري""" |
|
|
|
data = { |
|
'month': ['يناير', 'فبراير', 'مارس', 'أبريل', 'مايو', 'يونيو'], |
|
'new': [10, 15, 12, 8, 20, 18], |
|
'submitted': [8, 12, 10, 6, 15, 14], |
|
'won': [5, 8, 6, 4, 10, 9] |
|
} |
|
return pd.DataFrame(data) |
|
|
|
def _get_project_type_data(self): |
|
"""الحصول على بيانات توزيع المشاريع حسب النوع""" |
|
|
|
data = { |
|
'type': ['مباني', 'طرق', 'جسور', 'أنفاق', 'بنية تحتية', 'أخرى'], |
|
'count': [40, 30, 15, 10, 20, 5] |
|
} |
|
return pd.DataFrame(data) |
|
|
|
def _get_project_location_data(self): |
|
"""الحصول على بيانات توزيع المشاريع حسب الموقع""" |
|
|
|
data = { |
|
'location': ['الرياض', 'جدة', 'الدمام', 'مكة', 'المدينة', 'أخرى'], |
|
'count': [35, 25, 20, 15, 10, 15] |
|
} |
|
return pd.DataFrame(data) |
|
|
|
def _get_latest_projects(self): |
|
"""الحصول على بيانات أحدث المشاريع""" |
|
|
|
data = { |
|
'رقم المشروع': ['P-2025-001', 'P-2025-002', 'P-2025-003', 'P-2025-004', 'P-2025-005'], |
|
'اسم المشروع': ['إنشاء مبنى إداري', 'تطوير شبكة طرق', 'إنشاء جسر', 'بناء مدرسة', 'تطوير شبكة مياه'], |
|
'نوع المشروع': ['مباني', 'طرق', 'جسور', 'مباني', 'بنية تحتية'], |
|
'حالة المشروع': ['جديد', 'قيد التقديم', 'تم التقديم', 'فائز', 'جديد'], |
|
'تاريخ الإضافة': ['2025-03-30', '2025-03-28', '2025-03-25', '2025-03-20', '2025-03-18'] |
|
} |
|
return pd.DataFrame(data) |
|
|
|
|
|
|
|
def _render_project_status_report(self): |
|
"""عرض تقرير حالة المشاريع""" |
|
|
|
st.markdown("#### تقرير حالة المشاريع") |
|
|
|
|
|
data = { |
|
'رقم المشروع': ['P-2025-001', 'P-2025-002', 'P-2025-003', 'P-2025-004', 'P-2025-005', 'P-2025-006', 'P-2025-007', 'P-2025-008', 'P-2025-009', 'P-2025-010'], |
|
'اسم المشروع': ['إنشاء مبنى إداري', 'تطوير شبكة طرق', 'إنشاء جسر', 'بناء مدرسة', 'تطوير شبكة مياه', 'إنشاء مستشفى', 'بناء مركز تجاري', 'تطوير حديقة عامة', 'إنشاء مصنع', 'تطوير مطار'], |
|
'نوع المشروع': ['مباني', 'طرق', 'جسور', 'مباني', 'بنية تحتية', 'مباني', 'مباني', 'أخرى', 'مباني', 'بنية تحتية'], |
|
' |
|
(Content truncated due to size limit. Use line ranges to read in chunks) |
|
|