"""
وحدة الخرائط والمواقع - نظام تحليل المناقصات
"""
import streamlit as st
import pandas as pd
import numpy as np
import folium
from streamlit_folium import folium_static
import json
import os
import sys
from pathlib import Path
# إضافة مسار المشروع للنظام
sys.path.append(str(Path(__file__).parent.parent))
# استيراد محسن واجهة المستخدم
from styling.enhanced_ui import UIEnhancer
class MapsApp:
"""تطبيق الخرائط والمواقع"""
def __init__(self):
"""تهيئة تطبيق الخرائط والمواقع"""
self.ui = UIEnhancer(page_title="الخرائط والمواقع - نظام تحليل المناقصات", page_icon="🗺️")
self.ui.apply_theme_colors()
# بيانات المشاريع (نموذجية)
self.projects_data = [
{
"id": "P001",
"name": "إنشاء مبنى إداري - الرياض",
"location": "الرياض",
"coordinates": [24.7136, 46.6753],
"status": "جاري التنفيذ",
"budget": 15000000,
"completion": 45,
"client": "وزارة الإسكان",
"start_date": "2024-10-15",
"end_date": "2025-12-30"
},
{
"id": "P002",
"name": "تطوير طريق الملك فهد - جدة",
"location": "جدة",
"coordinates": [21.5433, 39.1728],
"status": "قيد الدراسة",
"budget": 8500000,
"completion": 0,
"client": "أمانة جدة",
"start_date": "2025-05-01",
"end_date": "2026-02-28"
},
{
"id": "P003",
"name": "إنشاء مجمع سكني - الدمام",
"location": "الدمام",
"coordinates": [26.4207, 50.0888],
"status": "مكتمل",
"budget": 22000000,
"completion": 100,
"client": "شركة الإسكان للتطوير",
"start_date": "2023-08-10",
"end_date": "2025-01-15"
},
{
"id": "P004",
"name": "بناء مدرسة - أبها",
"location": "أبها",
"coordinates": [18.2164, 42.5053],
"status": "جاري التنفيذ",
"budget": 5200000,
"completion": 75,
"client": "وزارة التعليم",
"start_date": "2024-06-20",
"end_date": "2025-07-30"
},
{
"id": "P005",
"name": "تطوير شبكة مياه - المدينة المنورة",
"location": "المدينة المنورة",
"coordinates": [24.5247, 39.5692],
"status": "جاري التنفيذ",
"budget": 12800000,
"completion": 30,
"client": "شركة المياه الوطنية",
"start_date": "2024-11-05",
"end_date": "2026-03-15"
}
]
def run(self):
"""تشغيل تطبيق الخرائط والمواقع"""
# إنشاء قائمة العناصر
menu_items = [
{"name": "لوحة المعلومات", "icon": "house"},
{"name": "المناقصات والعقود", "icon": "file-text"},
{"name": "تحليل المستندات", "icon": "file-earmark-text"},
{"name": "نظام التسعير", "icon": "calculator"},
{"name": "حاسبة تكاليف البناء", "icon": "building"},
{"name": "الموارد والتكاليف", "icon": "people"},
{"name": "تحليل المخاطر", "icon": "exclamation-triangle"},
{"name": "إدارة المشاريع", "icon": "kanban"},
{"name": "الخرائط والمواقع", "icon": "geo-alt"},
{"name": "الجدول الزمني", "icon": "calendar3"},
{"name": "الإشعارات", "icon": "bell"},
{"name": "مقارنة المستندات", "icon": "files"},
{"name": "المساعد الذكي", "icon": "robot"},
{"name": "التقارير", "icon": "bar-chart"},
{"name": "الإعدادات", "icon": "gear"}
]
# إنشاء الشريط الجانبي
selected = self.ui.create_sidebar(menu_items)
# إنشاء ترويسة الصفحة
self.ui.create_header("الخرائط والمواقع", "عرض وإدارة مواقع المشاريع")
# إنشاء علامات تبويب للوظائف المختلفة
tabs = st.tabs(["خريطة المشاريع", "تفاصيل المواقع", "إضافة موقع جديد", "تحليل المناطق"])
# علامة تبويب خريطة المشاريع
with tabs[0]:
self.show_projects_map()
# علامة تبويب تفاصيل المواقع
with tabs[1]:
self.show_location_details()
# علامة تبويب إضافة موقع جديد
with tabs[2]:
self.add_new_location()
# علامة تبويب تحليل المناطق
with tabs[3]:
self.analyze_regions()
def show_projects_map(self):
"""عرض خريطة المشاريع"""
# إنشاء فلاتر للخريطة
col1, col2, col3 = st.columns(3)
with col1:
status_filter = st.multiselect(
"حالة المشروع",
options=["الكل", "جاري التنفيذ", "قيد الدراسة", "مكتمل"],
default=["الكل"]
)
with col2:
location_filter = st.multiselect(
"الموقع",
options=["الكل"] + list(set([p["location"] for p in self.projects_data])),
default=["الكل"]
)
with col3:
budget_range = st.slider(
"نطاق الميزانية (مليون ريال)",
0.0, 25.0, (0.0, 25.0),
step=0.5
)
# تطبيق الفلاتر
filtered_projects = self.projects_data
if "الكل" not in status_filter and status_filter:
filtered_projects = [p for p in filtered_projects if p["status"] in status_filter]
if "الكل" not in location_filter and location_filter:
filtered_projects = [p for p in filtered_projects if p["location"] in location_filter]
filtered_projects = [p for p in filtered_projects if budget_range[0] * 1000000 <= p["budget"] <= budget_range[1] * 1000000]
# إنشاء الخريطة
st.markdown("### خريطة المشاريع")
# تحديد مركز الخريطة (وسط المملكة العربية السعودية تقريباً)
center = [24.0, 45.0]
# إنشاء خريطة folium
m = folium.Map(location=center, zoom_start=5, tiles="OpenStreetMap")
# إضافة المشاريع إلى الخريطة
for project in filtered_projects:
# تحديد لون العلامة بناءً على حالة المشروع
if project["status"] == "جاري التنفيذ":
color = "blue"
elif project["status"] == "قيد الدراسة":
color = "orange"
elif project["status"] == "مكتمل":
color = "green"
else:
color = "gray"
# إنشاء نص النافذة المنبثقة
popup_text = f"""
{project['name']}
الحالة: {project['status']}
الميزانية: {project['budget']:,} ريال
نسبة الإنجاز: {project['completion']}%
العميل: {project['client']}
تاريخ البدء: {project['start_date']}
تاريخ الانتهاء: {project['end_date']}
عرض التفاصيل
"""
# إضافة علامة للمشروع
folium.Marker(
location=project["coordinates"],
popup=folium.Popup(popup_text, max_width=300),
tooltip=project["name"],
icon=folium.Icon(color=color, icon="info-sign")
).add_to(m)
# عرض الخريطة
folium_static(m, width=1000, height=500)
# عرض إحصائيات المشاريع
st.markdown("### إحصائيات المشاريع")
col1, col2, col3, col4 = st.columns(4)
with col1:
self.ui.create_metric_card(
"إجمالي المشاريع",
str(len(filtered_projects)),
None,
self.ui.COLORS['primary']
)
with col2:
projects_in_progress = len([p for p in filtered_projects if p["status"] == "جاري التنفيذ"])
self.ui.create_metric_card(
"مشاريع جارية",
str(projects_in_progress),
None,
self.ui.COLORS['secondary']
)
with col3:
total_budget = sum([p["budget"] for p in filtered_projects])
self.ui.create_metric_card(
"إجمالي الميزانية",
f"{total_budget/1000000:.1f} مليون ريال",
None,
self.ui.COLORS['accent']
)
with col4:
avg_completion = np.mean([p["completion"] for p in filtered_projects])
self.ui.create_metric_card(
"متوسط نسبة الإنجاز",
f"{avg_completion:.1f}%",
None,
self.ui.COLORS['success']
)
def show_location_details(self):
"""عرض تفاصيل المواقع"""
st.markdown("### تفاصيل مواقع المشاريع")
# إنشاء جدول بيانات المشاريع
projects_df = pd.DataFrame(self.projects_data)
projects_df = projects_df.rename(columns={
"id": "رقم المشروع",
"name": "اسم المشروع",
"location": "الموقع",
"status": "الحالة",
"budget": "الميزانية (ريال)",
"completion": "نسبة الإنجاز (%)",
"client": "العميل",
"start_date": "تاريخ البدء",
"end_date": "تاريخ الانتهاء"
})
# حذف عمود الإحداثيات من العرض
projects_df = projects_df.drop(columns=["coordinates"])
# عرض الجدول
st.dataframe(
projects_df,
use_container_width=True,
hide_index=True
)
# إضافة خيار تصدير البيانات
col1, col2 = st.columns([1, 5])
with col1:
self.ui.create_button("تصدير البيانات", "primary")
# عرض تفاصيل مشروع محدد
st.markdown("### تفاصيل مشروع محدد")
selected_project = st.selectbox(
"اختر مشروعاً لعرض التفاصيل",
options=[p["name"] for p in self.projects_data]
)
# العثور على المشروع المحدد
project = next((p for p in self.projects_data if p["name"] == selected_project), None)
if project:
col1, col2 = st.columns([2, 1])
with col1:
# عرض تفاصيل المشروع
st.markdown(f"#### {project['name']}")
st.markdown(f"**الموقع:** {project['location']}")
st.markdown(f"**الحالة:** {project['status']}")
st.markdown(f"**الميزانية:** {project['budget']:,} ريال")
st.markdown(f"**نسبة الإنجاز:** {project['completion']}%")
st.markdown(f"**العميل:** {project['client']}")
st.markdown(f"**تاريخ البدء:** {project['start_date']}")
st.markdown(f"**تاريخ الانتهاء:** {project['end_date']}")
# أزرار الإجراءات
col1, col2, col3 = st.columns(3)
with col1:
self.ui.create_button("تعديل البيانات", "primary")
with col2:
self.ui.create_button("عرض المستندات", "secondary")
with col3:
self.ui.create_button("تقرير الموقع", "accent")
with col2:
# عرض خريطة مصغرة للمشروع
m = folium.Map(location=project["coordinates"], zoom_start=12)
folium.Marker(
location=project["coordinates"],
tooltip=project["name"],
icon=folium.Icon(color="red", icon="info-sign")
).add_to(m)
folium_static(m, width=300, height=300)
def add_new_location(self):
"""إضافة موقع جديد"""
st.markdown("### إضافة موقع مشروع جديد")
# نموذج إضافة موقع جديد
with st.form("new_location_form"):
col1, col2 = st.columns(2)
with col1:
project_id = st.text_input("رقم المشروع", value="P00" + str(len(self.projects_data) + 1))
project_name = st.text_input("اسم المشروع")
location = st.text_input("الموقع")
status = st.selectbox(
"الحالة",
options=["جاري التنفيذ", "قيد الدراسة", "مكتمل"]
)
budget = st.number_input("الميزانية (ريال)", min_value=0, step=100000)
with col2:
completion = st.slider("نسبة الإنجاز (%)", 0, 100, 0)
client = st.text_input("العميل")
start_date = st.date_input("تاريخ البدء")
end_date = st.date_input("تاريخ الانتهاء")
st.markdown("### تحديد الموقع على الخريطة")
st.markdown("انقر على الخريطة لتحديد موقع المشروع أو أدخل الإحداثيات يدوياً")
col1, col2 = st.columns(2)
with col1:
latitude = st.number_input("خط العرض", value=24.0, format="%.4f")
with col2:
longitude = st.number_input("خط الطول", value=45.0, format="%.4f")
# عرض الخريطة لتحديد الموقع
m = folium.Map(location=[latitude, longitude], zoom_start=5)
folium.Marker(
location=[latitude, longitude],
tooltip="موقع المشروع الجديد",
icon=folium.Icon(color="red", icon="info-sign")
).add_to(m)
folium_static(m, width=700, height=300)
# زر الإرسال
submit_button = st.form_submit_button("إضافة المشروع")
if submit_button:
# إضافة المشروع الجديد (في تطبيق حقيقي، سيتم حفظ البيانات في قاعدة البيانات)
st.success("تم إضافة المشروع بنجاح!")
# إعادة تعيين النموذج
st.experimental_rerun()
def analyze_regions(self):
"""تحليل المناطق"""
st.markdown("### تحليل المناطق")
# إنشاء بيانات المناطق (نموذجية)
regions_data = {
"المنطقة": ["الرياض", "مكة المكرمة", "المدينة المنورة", "القصيم", "المنطقة الشرقية", "عسير", "تبوك", "حائل", "الحدود الشمالية", "جازان", "نجران", "الباحة", "الجوف"],
"عدد المشاريع": [15, 12, 8, 5, 18, 7, 4, 3, 2, 6, 3, 2, 3],
"إجمالي الميزانية (مليون ريال)": [120, 95, 45, 30, 150, 40, 25, 18, 12, 35, 20, 15, 22],
"متوسط مدة المشروع (شهر)": [18, 16, 14, 12, 20, 15, 12, 10, 9, 14, 12, 10, 11]
}
regions_df = pd.DataFrame(regions_data)
# عرض خريطة حرارية للمناطق
st.markdown("#### توزيع المشاريع حسب المناطق")
# في تطبيق حقيقي، يمكن استخدام خريطة حرارية حقيقية للمملكة
st.image("https://via.placeholder.com/800x400?text=خريطة+حرارية+للمشاريع+حسب+المناطق", use_column_width=True)
# عرض إحصائيات المناطق
st.markdown("#### إحصائيات المناطق")
# عرض الجدول
st.dataframe(
regions_df,
use_container_width=True,
hide_index=True
)
# عرض رسوم بيانية للمقارنة
st.markdown("#### مقارنة المناطق")
chart_type = st.radio(
"نوع الرسم البياني",
options=["عدد المشاريع", "إجمالي الميزانية", "متوسط مدة المشروع"],
horizontal=True
)
if chart_type == "عدد المشاريع":
chart_data = regions_df[["المنطقة", "عدد المشاريع"]].sort_values(by="عدد المشاريع", ascending=False)
st.bar_chart(chart_data.set_index("المنطقة"))
elif chart_type == "إجمالي الميزانية":
chart_data = regions_df[["المنطقة", "إجمالي الميزانية (مليون ريال)"]].sort_values(by="إجمالي الميزانية (مليون ريال)", ascending=False)
st.bar_chart(chart_data.set_index("المنطقة"))
else:
chart_data = regions_df[["المنطقة", "متوسط مدة المشروع (شهر)"]].sort_values(by="متوسط مدة المشروع (شهر)", ascending=False)
st.bar_chart(chart_data.set_index("المنطقة"))
# تحليل الكثافة
st.markdown("#### تحليل كثافة المشاريع")
st.markdown("""
يوضح هذا التحليل توزيع المشاريع حسب المناطق الجغرافية، مما يساعد في:
- تحديد المناطق ذات النشاط العالي
- تحديد فرص النمو في المناطق الأقل نشاطاً
- تخطيط الموارد بناءً على التوزيع الجغرافي
""")
# في تطبيق حقيقي، يمكن إضافة تحليلات أكثر تفصيلاً
# تشغيل التطبيق
if __name__ == "__main__":
maps_app = MapsApp()
maps_app.run()