"""
وحدة الموارد - التطبيق الرئيسي
"""
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, timedelta
import time
import io
import os
import json
import base64
from pathlib import Path
class ResourcesApp:
"""وحدة الموارد"""
def __init__(self):
"""تهيئة وحدة الموارد"""
# تهيئة حالة الجلسة
if 'resources_data' not in st.session_state:
# إنشاء بيانات افتراضية للموارد البشرية
np.random.seed(42)
# إنشاء بيانات الموظفين
n_employees = 50
employee_ids = [f"EMP-{i+1:03d}" for i in range(n_employees)]
employee_names = [
"أحمد محمد", "محمد علي", "علي إبراهيم", "إبراهيم خالد", "خالد عبدالله",
"عبدالله سعد", "سعد فهد", "فهد ناصر", "ناصر سلطان", "سلطان عمر",
"عمر يوسف", "يوسف عبدالرحمن", "عبدالرحمن حسن", "حسن أحمد", "أحمد عبدالعزيز",
"عبدالعزيز سعود", "سعود فيصل", "فيصل تركي", "تركي بندر", "بندر سلمان",
"سلمان محمد", "محمد عبدالله", "عبدالله فهد", "فهد سعد", "سعد خالد",
"خالد علي", "علي عمر", "عمر سعيد", "سعيد ماجد", "ماجد فارس",
"فارس نايف", "نايف سامي", "سامي راشد", "راشد وليد", "وليد هاني",
"هاني زياد", "زياد طارق", "طارق عادل", "عادل فراس", "فراس باسم",
"باسم جمال", "جمال كريم", "كريم نبيل", "نبيل هشام", "هشام عماد",
"عماد أيمن", "أيمن رامي", "رامي سمير", "سمير وائل", "وائل مازن"
]
employee_departments = np.random.choice(["الهندسة", "المشتريات", "المالية", "الموارد البشرية", "تقنية المعلومات", "التسويق", "المبيعات"], n_employees)
employee_positions = np.random.choice(["مدير", "مهندس", "محاسب", "مشرف", "أخصائي", "مساعد", "فني"], n_employees)
employee_skills = [
np.random.choice(["إدارة المشاريع", "التصميم الهندسي", "تحليل البيانات", "إدارة العقود", "التخطيط الاستراتيجي"],
size=np.random.randint(1, 4),
replace=False).tolist()
for _ in range(n_employees)
]
employee_experiences = np.random.randint(1, 20, n_employees)
employee_costs = np.random.randint(5000, 25000, n_employees)
employee_availabilities = np.random.choice([True, False], n_employees, p=[0.8, 0.2])
employee_ratings = np.random.uniform(3.0, 5.0, n_employees)
# إنشاء DataFrame للموظفين
employees_data = {
"رقم الموظف": employee_ids,
"اسم الموظف": employee_names,
"القسم": employee_departments,
"المنصب": employee_positions,
"المهارات": employee_skills,
"سنوات الخبرة": employee_experiences,
"التكلفة الشهرية": employee_costs,
"متاح": employee_availabilities,
"التقييم": employee_ratings
}
# إنشاء بيانات المعدات
n_equipment = 30
equipment_ids = [f"EQ-{i+1:03d}" for i in range(n_equipment)]
equipment_names = [
"حفارة كبيرة", "حفارة صغيرة", "جرافة", "شاحنة نقل", "رافعة كبيرة",
"رافعة متوسطة", "رافعة صغيرة", "خلاطة خرسانة", "مضخة خرسانة", "مولد كهرباء كبير",
"مولد كهرباء متوسط", "مولد كهرباء صغير", "ضاغط هواء", "آلة لحام", "معدات قياس",
"معدات اختبار", "سقالات", "قوالب خرسانية", "معدات سباكة", "معدات كهربائية",
"معدات تكييف", "معدات تدفئة", "معدات إضاءة", "معدات سلامة", "معدات إطفاء",
"سيارة نقل صغيرة", "سيارة نقل متوسطة", "سيارة نقل كبيرة", "معدات حفر يدوية", "معدات بناء يدوية"
]
equipment_types = np.random.choice(["حفر", "نقل", "رفع", "خرسانة", "كهرباء", "قياس", "بناء", "سلامة"], n_equipment)
equipment_costs = np.random.randint(500, 5000, n_equipment)
equipment_availabilities = np.random.choice([True, False], n_equipment, p=[0.7, 0.3])
equipment_conditions = np.random.choice(["ممتاز", "جيد", "متوسط", "سيء"], n_equipment, p=[0.4, 0.3, 0.2, 0.1])
equipment_locations = np.random.choice(["المستودع", "موقع المشروع 1", "موقع المشروع 2", "موقع المشروع 3", "في الصيانة"], n_equipment)
# إنشاء DataFrame للمعدات
equipment_data = {
"رقم المعدة": equipment_ids,
"اسم المعدة": equipment_names,
"النوع": equipment_types,
"التكلفة اليومية": equipment_costs,
"متاحة": equipment_availabilities,
"الحالة": equipment_conditions,
"الموقع": equipment_locations
}
# إنشاء بيانات المواد
n_materials = 40
material_ids = [f"MAT-{i+1:03d}" for i in range(n_materials)]
material_names = [
"خرسانة جاهزة", "حديد تسليح", "طابوق", "أسمنت", "رمل", "بحص", "خشب", "ألمنيوم", "زجاج", "دهان",
"سيراميك", "رخام", "جبس", "عازل مائي", "عازل حراري", "أنابيب PVC", "أسلاك كهربائية", "مفاتيح كهربائية",
"إنارة", "تكييف", "مصاعد", "أبواب خشبية", "أبواب حديدية", "نوافذ ألمنيوم", "نوافذ زجاجية",
"أرضيات خشبية", "أرضيات بلاط", "أرضيات رخام", "أرضيات سيراميك", "أرضيات بورسلين",
"دهان داخلي", "دهان خارجي", "مواد عزل", "مواد تشطيب", "مواد كهربائية", "مواد سباكة",
"مواد تكييف", "مواد إضاءة", "مواد سلامة", "مواد متنوعة"
]
material_units = np.random.choice(["م3", "طن", "م2", "كجم", "لتر", "قطعة", "متر"], n_materials)
material_quantities = np.random.randint(10, 1000, n_materials)
material_costs = np.random.randint(50, 5000, n_materials)
material_suppliers = np.random.choice(["المورد 1", "المورد 2", "المورد 3", "المورد 4", "المورد 5"], n_materials)
material_lead_times = np.random.randint(1, 30, n_materials)
# إنشاء DataFrame للمواد
materials_data = {
"رقم المادة": material_ids,
"اسم المادة": material_names,
"الوحدة": material_units,
"الكمية المتاحة": material_quantities,
"تكلفة الوحدة": material_costs,
"المورد": material_suppliers,
"مدة التوريد (يوم)": material_lead_times
}
# إنشاء بيانات المشاريع
n_projects = 10
project_ids = [f"PRJ-{i+1:03d}" for i in range(n_projects)]
project_names = [
"مشروع إنشاء مبنى إداري", "مشروع إنشاء مبنى سكني", "مشروع إنشاء مدرسة",
"مشروع إنشاء مستشفى", "مشروع تطوير طرق", "مشروع إنشاء جسر",
"مشروع بنية تحتية", "مشروع إنشاء مركز تجاري", "مشروع إنشاء فندق",
"مشروع إنشاء مصنع"
]
project_locations = np.random.choice(["الرياض", "جدة", "الدمام", "مكة", "المدينة", "أبها", "تبوك"], n_projects)
project_start_dates = [
(datetime.now() - timedelta(days=np.random.randint(0, 180))).strftime("%Y-%m-%d")
for _ in range(n_projects)
]
project_end_dates = [
(datetime.strptime(start_date, "%Y-%m-%d") + timedelta(days=np.random.randint(180, 720))).strftime("%Y-%m-%d")
for start_date in project_start_dates
]
project_budgets = np.random.randint(1000000, 50000000, n_projects)
project_statuses = np.random.choice(["قيد التنفيذ", "مكتمل", "متوقف", "مخطط"], n_projects)
# إنشاء DataFrame للمشاريع
projects_data = {
"رقم المشروع": project_ids,
"اسم المشروع": project_names,
"الموقع": project_locations,
"تاريخ البدء": project_start_dates,
"تاريخ الانتهاء": project_end_dates,
"الميزانية": project_budgets,
"الحالة": project_statuses
}
# إنشاء بيانات تخصيص الموارد للمشاريع
n_allocations = 100
allocation_ids = [f"ALLOC-{i+1:03d}" for i in range(n_allocations)]
allocation_projects = np.random.choice(project_ids, n_allocations)
allocation_resource_types = np.random.choice(["موظف", "معدة", "مادة"], n_allocations)
allocation_resource_ids = []
for res_type in allocation_resource_types:
if res_type == "موظف":
allocation_resource_ids.append(np.random.choice(employee_ids))
elif res_type == "معدة":
allocation_resource_ids.append(np.random.choice(equipment_ids))
else:
allocation_resource_ids.append(np.random.choice(material_ids))
allocation_start_dates = [
(datetime.now() - timedelta(days=np.random.randint(0, 90))).strftime("%Y-%m-%d")
for _ in range(n_allocations)
]
allocation_end_dates = [
(datetime.strptime(start_date, "%Y-%m-%d") + timedelta(days=np.random.randint(30, 180))).strftime("%Y-%m-%d")
for start_date in allocation_start_dates
]
allocation_quantities = np.random.randint(1, 10, n_allocations)
allocation_costs = np.random.randint(5000, 50000, n_allocations)
# إنشاء DataFrame لتخصيص الموارد
allocations_data = {
"رقم التخصيص": allocation_ids,
"رقم المشروع": allocation_projects,
"نوع المورد": allocation_resource_types,
"رقم المورد": allocation_resource_ids,
"تاريخ البدء": allocation_start_dates,
"تاريخ الانتهاء": allocation_end_dates,
"الكمية": allocation_quantities,
"التكلفة": allocation_costs
}
# تخزين البيانات في حالة الجلسة
st.session_state.resources_data = {
"employees": pd.DataFrame(employees_data),
"equipment": pd.DataFrame(equipment_data),
"materials": pd.DataFrame(materials_data),
"projects": pd.DataFrame(projects_data),
"allocations": pd.DataFrame(allocations_data)
}
def render(self):
"""عرض واجهة وحدة الموارد"""
st.markdown("
وحدة الموارد
", unsafe_allow_html=True)
tabs = st.tabs([
"لوحة المعلومات",
"الموارد البشرية",
"المعدات",
"المواد",
"تخصيص الموارد",
"تخطيط الموارد"
])
with tabs[0]:
self._render_dashboard_tab()
with tabs[1]:
self._render_human_resources_tab()
with tabs[2]:
self._render_equipment_tab()
with tabs[3]:
self._render_materials_tab()
with tabs[4]:
self._render_resource_allocation_tab()
with tabs[5]:
self._render_resource_planning_tab()
def _render_dashboard_tab(self):
"""عرض تبويب لوحة المعلومات"""
st.markdown("### لوحة معلومات الموارد")
# استخراج البيانات
employees_df = st.session_state.resources_data["employees"]
equipment_df = st.session_state.resources_data["equipment"]
materials_df = st.session_state.resources_data["materials"]
projects_df = st.session_state.resources_data["projects"]
allocations_df = st.session_state.resources_data["allocations"]
# عرض مؤشرات الأداء الرئيسية
st.markdown("#### مؤشرات الأداء الرئيسية")
col1, col2, col3, col4 = st.columns(4)
with col1:
total_employees = len(employees_df)
available_employees = len(employees_df[employees_df["متاح"] == True])
st.metric("الموظفون", f"{available_employees}/{total_employees}")
with col2:
total_equipment = len(equipment_df)
available_equipment = len(equipment_df[equipment_df["متاحة"] == True])
st.metric("المعدات", f"{available_equipment}/{total_equipment}")
with col3:
total_materials = len(materials_df)
low_stock_materials = len(materials_df[materials_df["الكمية المتاحة"] < 50])
st.metric("المواد", f"{total_materials}", f"-{low_stock_materials} منخفضة المخزون")
with col4:
total_projects = len(projects_df)
active_projects = len(projects_df[projects_df["الحالة"] == "قيد التنفيذ"])
st.metric("المشاريع النشطة", f"{active_projects}/{total_projects}")
# عرض توزيع الموارد البشرية حسب القسم
st.markdown("#### توزيع الموارد البشرية حسب القسم")
dept_counts = employees_df["القسم"].value_counts().reset_index()
dept_counts.columns = ["القسم", "العدد"]
fig = px.pie(
dept_counts,
values="العدد",
names="القسم",
title="توزيع الموظفين حسب القسم",
color="القسم"
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المعدات حسب النوع
st.markdown("#### توزيع المعدات حسب النوع")
type_counts = equipment_df["النوع"].value_counts().reset_index()
type_counts.columns = ["النوع", "العدد"]
fig = px.bar(
type_counts,
x="النوع",
y="العدد",
title="توزيع المعدات حسب النوع",
color="النوع",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المواد حسب المورد
st.markdown("#### توزيع المواد حسب المورد")
supplier_counts = materials_df["المورد"].value_counts().reset_index()
supplier_counts.columns = ["المورد", "العدد"]
fig = px.pie(
supplier_counts,
values="العدد",
names="المورد",
title="توزيع المواد حسب المورد",
color="المورد"
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع تكاليف الموارد
st.markdown("#### توزيع تكاليف الموارد")
# حساب إجمالي تكاليف الموظفين
total_employee_cost = employees_df["التكلفة الشهرية"].sum()
# حساب إجمالي تكاليف المعدات (افتراضياً لشهر واحد)
total_equipment_cost = equipment_df["التكلفة اليومية"].sum() * 30
# حساب إجمالي تكاليف المواد
total_material_cost = (materials_df["الكمية المتاحة"] * materials_df["تكلفة الوحدة"]).sum()
# إنشاء DataFrame لتوزيع التكاليف
cost_distribution = pd.DataFrame({
"نوع المورد": ["الموظفون", "المعدات", "المواد"],
"التكلفة": [total_employee_cost, total_equipment_cost, total_material_cost]
})
fig = px.pie(
cost_distribution,
values="التكلفة",
names="نوع المورد",
title="توزيع تكاليف الموارد",
color="نوع المورد",
color_discrete_map={
"الموظفون": "#3498db",
"المعدات": "#2ecc71",
"المواد": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض تخصيص الموارد للمشاريع
st.markdown("#### تخصيص الموارد للمشاريع")
# حساب عدد الموارد المخصصة لكل مشروع
project_allocations = allocations_df["رقم المشروع"].value_counts().reset_index()
project_allocations.columns = ["رقم المشروع", "عدد الموارد المخصصة"]
# دمج بيانات المشاريع مع بيانات التخصيص
project_allocations = project_allocations.merge(
projects_df[["رقم المشروع", "اسم المشروع", "الحالة"]],
on="رقم المشروع",
how="left"
)
fig = px.bar(
project_allocations,
x="اسم المشروع",
y="عدد الموارد المخصصة",
title="تخصيص الموارد للمشاريع",
color="الحالة",
text_auto=True,
color_discrete_map={
"قيد التنفيذ": "#3498db",
"مكتمل": "#2ecc71",
"متوقف": "#e74c3c",
"مخطط": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع أنواع الموارد المخصصة
st.markdown("#### توزيع أنواع الموارد المخصصة")
resource_type_counts = allocations_df["نوع المورد"].value_counts().reset_index()
resource_type_counts.columns = ["نوع المورد", "العدد"]
fig = px.pie(
resource_type_counts,
values="العدد",
names="نوع المورد",
title="توزيع أنواع الموارد المخصصة",
color="نوع المورد",
color_discrete_map={
"موظف": "#3498db",
"معدة": "#2ecc71",
"مادة": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
def _render_human_resources_tab(self):
"""عرض تبويب الموارد البشرية"""
st.markdown("### إدارة الموارد البشرية")
# استخراج البيانات
employees_df = st.session_state.resources_data["employees"]
# عرض خيارات التصفية
st.markdown("#### خيارات التصفية")
col1, col2, col3 = st.columns(3)
with col1:
selected_departments = st.multiselect(
"القسم",
options=employees_df["القسم"].unique(),
default=employees_df["القسم"].unique()
)
with col2:
selected_positions = st.multiselect(
"المنصب",
options=employees_df["المنصب"].unique(),
default=employees_df["المنصب"].unique()
)
with col3:
availability_filter = st.selectbox(
"الإتاحة",
options=["الكل", "متاح فقط", "غير متاح فقط"]
)
# تطبيق التصفية
filtered_df = employees_df[
employees_df["القسم"].isin(selected_departments) &
employees_df["المنصب"].isin(selected_positions)
]
if availability_filter == "متاح فقط":
filtered_df = filtered_df[filtered_df["متاح"] == True]
elif availability_filter == "غير متاح فقط":
filtered_df = filtered_df[filtered_df["متاح"] == False]
# عرض البيانات المصفاة
st.markdown("#### قائمة الموظفين")
st.dataframe(
filtered_df,
column_config={
"رقم الموظف": st.column_config.TextColumn("رقم الموظف"),
"اسم الموظف": st.column_config.TextColumn("اسم الموظف"),
"القسم": st.column_config.TextColumn("القسم"),
"المنصب": st.column_config.TextColumn("المنصب"),
"المهارات": st.column_config.ListColumn("المهارات"),
"سنوات الخبرة": st.column_config.NumberColumn("سنوات الخبرة"),
"التكلفة الشهرية": st.column_config.NumberColumn("التكلفة الشهرية", format="%.2f ريال"),
"متاح": st.column_config.CheckboxColumn("متاح"),
"التقييم": st.column_config.ProgressColumn("التقييم", min_value=0, max_value=5)
},
use_container_width=True,
hide_index=True
)
# عرض إحصائيات الموارد البشرية
st.markdown("#### إحصائيات الموارد البشرية")
col1, col2, col3, col4 = st.columns(4)
with col1:
total_employees = len(filtered_df)
st.metric("إجمالي الموظفين", f"{total_employees}")
with col2:
available_employees = len(filtered_df[filtered_df["متاح"] == True])
availability_rate = available_employees / total_employees * 100 if total_employees > 0 else 0
st.metric("معدل الإتاحة", f"{availability_rate:.1f}%")
with col3:
avg_experience = filtered_df["سنوات الخبرة"].mean()
st.metric("متوسط سنوات الخبرة", f"{avg_experience:.1f} سنة")
with col4:
avg_cost = filtered_df["التكلفة الشهرية"].mean()
st.metric("متوسط التكلفة الشهرية", f"{avg_cost:.0f} ريال")
# عرض توزيع الموظفين حسب القسم
st.markdown("#### توزيع الموظفين حسب القسم")
dept_counts = filtered_df["القسم"].value_counts().reset_index()
dept_counts.columns = ["القسم", "العدد"]
fig = px.bar(
dept_counts,
x="القسم",
y="العدد",
title="توزيع الموظفين حسب القسم",
color="القسم",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع الموظفين حسب المنصب
st.markdown("#### توزيع الموظفين حسب المنصب")
position_counts = filtered_df["المنصب"].value_counts().reset_index()
position_counts.columns = ["المنصب", "العدد"]
fig = px.pie(
position_counts,
values="العدد",
names="المنصب",
title="توزيع الموظفين حسب المنصب",
color="المنصب"
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع الموظفين حسب سنوات الخبرة
st.markdown("#### توزيع الموظفين حسب سنوات الخبرة")
# إنشاء فئات لسنوات الخبرة
experience_bins = [0, 3, 5, 10, 15, 20]
experience_labels = ["أقل من 3 سنوات", "3-5 سنوات", "6-10 سنوات", "11-15 سنة", "أكثر من 15 سنة"]
filtered_df["فئة الخبرة"] = pd.cut(filtered_df["سنوات الخبرة"], bins=experience_bins, labels=experience_labels, right=False)
experience_counts = filtered_df["فئة الخبرة"].value_counts().reset_index()
experience_counts.columns = ["فئة الخبرة", "العدد"]
fig = px.bar(
experience_counts,
x="فئة الخبرة",
y="العدد",
title="توزيع الموظفين حسب سنوات الخبرة",
color="فئة الخبرة",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المهارات
st.markdown("#### توزيع المهارات")
# استخراج جميع المهارات
all_skills = []
for skills_list in filtered_df["المهارات"]:
all_skills.extend(skills_list)
skill_counts = pd.Series(all_skills).value_counts().reset_index()
skill_counts.columns = ["المهارة", "العدد"]
fig = px.bar(
skill_counts,
x="المهارة",
y="العدد",
title="توزيع المهارات",
color="المهارة",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض العلاقة بين سنوات الخبرة والتكلفة
st.markdown("#### العلاقة بين سنوات الخبرة والتكلفة")
fig = px.scatter(
filtered_df,
x="سنوات الخبرة",
y="التكلفة الشهرية",
color="القسم",
size="التقييم",
hover_name="اسم الموظف",
hover_data=["المنصب", "متاح"],
title="العلاقة بين سنوات الخبرة والتكلفة الشهرية"
)
st.plotly_chart(fig, use_container_width=True)
# إضافة موظف جديد
st.markdown("#### إضافة موظف جديد")
with st.form("add_employee_form"):
col1, col2 = st.columns(2)
with col1:
new_employee_name = st.text_input("اسم الموظف")
new_employee_department = st.selectbox("القسم", options=employees_df["القسم"].unique())
new_employee_position = st.selectbox("المنصب", options=employees_df["المنصب"].unique())
new_employee_experience = st.number_input("سنوات الخبرة", min_value=0, max_value=40, value=5)
with col2:
new_employee_skills = st.multiselect(
"المهارات",
options=["إدارة المشاريع", "التصميم الهندسي", "تحليل البيانات", "إدارة العقود", "التخطيط الاستراتيجي", "إدارة الموارد", "إدارة المخاطر", "إدارة الجودة", "إدارة التكاليف", "إدارة الوقت"]
)
new_employee_cost = st.number_input("التكلفة الشهرية", min_value=3000, max_value=50000, value=10000)
new_employee_available = st.checkbox("متاح", value=True)
new_employee_rating = st.slider("التقييم", min_value=1.0, max_value=5.0, value=4.0, step=0.1)
submit_button = st.form_submit_button("إضافة موظف")
if submit_button:
if new_employee_name:
# إنشاء رقم موظف جديد
new_employee_id = f"EMP-{len(employees_df) + 1:03d}"
# إضافة الموظف الجديد
new_employee = pd.DataFrame({
"رقم الموظف": [new_employee_id],
"اسم الموظف": [new_employee_name],
"القسم": [new_employee_department],
"المنصب": [new_employee_position],
"المهارات": [new_employee_skills],
"سنوات الخبرة": [new_employee_experience],
"التكلفة الشهرية": [new_employee_cost],
"متاح": [new_employee_available],
"التقييم": [new_employee_rating]
})
# تحديث DataFrame الموظفين
st.session_state.resources_data["employees"] = pd.concat([employees_df, new_employee], ignore_index=True)
st.success(f"تم إضافة الموظف {new_employee_name} بنجاح!")
st.rerun()
else:
st.error("يرجى إدخال اسم الموظف")
def _render_equipment_tab(self):
"""عرض تبويب المعدات"""
st.markdown("### إدارة المعدات")
# استخراج البيانات
equipment_df = st.session_state.resources_data["equipment"]
# عرض خيارات التصفية
st.markdown("#### خيارات التصفية")
col1, col2, col3 = st.columns(3)
with col1:
selected_types = st.multiselect(
"النوع",
options=equipment_df["النوع"].unique(),
default=equipment_df["النوع"].unique()
)
with col2:
selected_conditions = st.multiselect(
"الحالة",
options=equipment_df["الحالة"].unique(),
default=equipment_df["الحالة"].unique()
)
with col3:
availability_filter = st.selectbox(
"الإتاحة",
options=["الكل", "متاحة فقط", "غير متاحة فقط"],
key="equipment_availability"
)
# تطبيق التصفية
filtered_df = equipment_df[
equipment_df["النوع"].isin(selected_types) &
equipment_df["الحالة"].isin(selected_conditions)
]
if availability_filter == "متاحة فقط":
filtered_df = filtered_df[filtered_df["متاحة"] == True]
elif availability_filter == "غير متاحة فقط":
filtered_df = filtered_df[filtered_df["متاحة"] == False]
# عرض البيانات المصفاة
st.markdown("#### قائمة المعدات")
st.dataframe(
filtered_df,
column_config={
"رقم المعدة": st.column_config.TextColumn("رقم المعدة"),
"اسم المعدة": st.column_config.TextColumn("اسم المعدة"),
"النوع": st.column_config.TextColumn("النوع"),
"التكلفة اليومية": st.column_config.NumberColumn("التكلفة اليومية", format="%.2f ريال"),
"متاحة": st.column_config.CheckboxColumn("متاحة"),
"الحالة": st.column_config.TextColumn("الحالة"),
"الموقع": st.column_config.TextColumn("الموقع")
},
use_container_width=True,
hide_index=True
)
# عرض إحصائيات المعدات
st.markdown("#### إحصائيات المعدات")
col1, col2, col3, col4 = st.columns(4)
with col1:
total_equipment = len(filtered_df)
st.metric("إجمالي المعدات", f"{total_equipment}")
with col2:
available_equipment = len(filtered_df[filtered_df["متاحة"] == True])
availability_rate = available_equipment / total_equipment * 100 if total_equipment > 0 else 0
st.metric("معدل الإتاحة", f"{availability_rate:.1f}%")
with col3:
good_condition = len(filtered_df[filtered_df["الحالة"].isin(["ممتاز", "جيد"])])
good_condition_rate = good_condition / total_equipment * 100 if total_equipment > 0 else 0
st.metric("معدل الحالة الجيدة", f"{good_condition_rate:.1f}%")
with col4:
avg_cost = filtered_df["التكلفة اليومية"].mean()
st.metric("متوسط التكلفة اليومية", f"{avg_cost:.0f} ريال")
# عرض توزيع المعدات حسب النوع
st.markdown("#### توزيع المعدات حسب النوع")
type_counts = filtered_df["النوع"].value_counts().reset_index()
type_counts.columns = ["النوع", "العدد"]
fig = px.bar(
type_counts,
x="النوع",
y="العدد",
title="توزيع المعدات حسب النوع",
color="النوع",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المعدات حسب الحالة
st.markdown("#### توزيع المعدات حسب الحالة")
condition_counts = filtered_df["الحالة"].value_counts().reset_index()
condition_counts.columns = ["الحالة", "العدد"]
fig = px.pie(
condition_counts,
values="العدد",
names="الحالة",
title="توزيع المعدات حسب الحالة",
color="الحالة",
color_discrete_map={
"ممتاز": "#2ecc71",
"جيد": "#3498db",
"متوسط": "#f39c12",
"سيء": "#e74c3c"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المعدات حسب الموقع
st.markdown("#### توزيع المعدات حسب الموقع")
location_counts = filtered_df["الموقع"].value_counts().reset_index()
location_counts.columns = ["الموقع", "العدد"]
fig = px.bar(
location_counts,
x="الموقع",
y="العدد",
title="توزيع المعدات حسب الموقع",
color="الموقع",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض العلاقة بين نوع المعدة والتكلفة
st.markdown("#### العلاقة بين نوع المعدة والتكلفة")
type_cost = filtered_df.groupby("النوع")["التكلفة اليومية"].mean().reset_index()
type_cost.columns = ["النوع", "متوسط التكلفة اليومية"]
fig = px.bar(
type_cost,
x="النوع",
y="متوسط التكلفة اليومية",
title="متوسط التكلفة اليومية حسب نوع المعدة",
color="النوع",
text_auto=".0f"
)
st.plotly_chart(fig, use_container_width=True)
# إضافة معدة جديدة
st.markdown("#### إضافة معدة جديدة")
with st.form("add_equipment_form"):
col1, col2 = st.columns(2)
with col1:
new_equipment_name = st.text_input("اسم المعدة")
new_equipment_type = st.selectbox("النوع", options=equipment_df["النوع"].unique())
new_equipment_cost = st.number_input("التكلفة اليومية", min_value=100, max_value=10000, value=1000)
with col2:
new_equipment_available = st.checkbox("متاحة", value=True)
new_equipment_condition = st.selectbox("الحالة", options=["ممتاز", "جيد", "متوسط", "سيء"])
new_equipment_location = st.selectbox("الموقع", options=equipment_df["الموقع"].unique())
submit_button = st.form_submit_button("إضافة معدة")
if submit_button:
if new_equipment_name:
# إنشاء رقم معدة جديد
new_equipment_id = f"EQ-{len(equipment_df) + 1:03d}"
# إضافة المعدة الجديدة
new_equipment = pd.DataFrame({
"رقم المعدة": [new_equipment_id],
"اسم المعدة": [new_equipment_name],
"النوع": [new_equipment_type],
"التكلفة اليومية": [new_equipment_cost],
"متاحة": [new_equipment_available],
"الحالة": [new_equipment_condition],
"الموقع": [new_equipment_location]
})
# تحديث DataFrame المعدات
st.session_state.resources_data["equipment"] = pd.concat([equipment_df, new_equipment], ignore_index=True)
st.success(f"تم إضافة المعدة {new_equipment_name} بنجاح!")
st.rerun()
else:
st.error("يرجى إدخال اسم المعدة")
def _render_materials_tab(self):
"""عرض تبويب المواد"""
st.markdown("### إدارة المواد")
# استخراج البيانات
materials_df = st.session_state.resources_data["materials"]
# عرض خيارات التصفية
st.markdown("#### خيارات التصفية")
col1, col2, col3 = st.columns(3)
with col1:
selected_units = st.multiselect(
"الوحدة",
options=materials_df["الوحدة"].unique(),
default=materials_df["الوحدة"].unique()
)
with col2:
selected_suppliers = st.multiselect(
"المورد",
options=materials_df["المورد"].unique(),
default=materials_df["المورد"].unique()
)
with col3:
stock_filter = st.selectbox(
"المخزون",
options=["الكل", "منخفض المخزون", "مخزون كافي"]
)
# تطبيق التصفية
filtered_df = materials_df[
materials_df["الوحدة"].isin(selected_units) &
materials_df["المورد"].isin(selected_suppliers)
]
if stock_filter == "منخفض المخزون":
filtered_df = filtered_df[filtered_df["الكمية المتاحة"] < 50]
elif stock_filter == "مخزون كافي":
filtered_df = filtered_df[filtered_df["الكمية المتاحة"] >= 50]
# عرض البيانات المصفاة
st.markdown("#### قائمة المواد")
st.dataframe(
filtered_df,
column_config={
"رقم المادة": st.column_config.TextColumn("رقم المادة"),
"اسم المادة": st.column_config.TextColumn("اسم المادة"),
"الوحدة": st.column_config.TextColumn("الوحدة"),
"الكمية المتاحة": st.column_config.NumberColumn("الكمية المتاحة"),
"تكلفة الوحدة": st.column_config.NumberColumn("تكلفة الوحدة", format="%.2f ريال"),
"المورد": st.column_config.TextColumn("المورد"),
"مدة التوريد (يوم)": st.column_config.NumberColumn("مدة التوريد (يوم)")
},
use_container_width=True,
hide_index=True
)
# عرض إحصائيات المواد
st.markdown("#### إحصائيات المواد")
col1, col2, col3, col4 = st.columns(4)
with col1:
total_materials = len(filtered_df)
st.metric("إجمالي المواد", f"{total_materials}")
with col2:
low_stock_materials = len(filtered_df[filtered_df["الكمية المتاحة"] < 50])
low_stock_rate = low_stock_materials / total_materials * 100 if total_materials > 0 else 0
st.metric("نسبة المواد منخفضة المخزون", f"{low_stock_rate:.1f}%")
with col3:
avg_lead_time = filtered_df["مدة التوريد (يوم)"].mean()
st.metric("متوسط مدة التوريد", f"{avg_lead_time:.1f} يوم")
with col4:
total_inventory_value = (filtered_df["الكمية المتاحة"] * filtered_df["تكلفة الوحدة"]).sum()
st.metric("إجمالي قيمة المخزون", f"{total_inventory_value:,.0f} ريال")
# عرض توزيع المواد حسب المورد
st.markdown("#### توزيع المواد حسب المورد")
supplier_counts = filtered_df["المورد"].value_counts().reset_index()
supplier_counts.columns = ["المورد", "العدد"]
fig = px.pie(
supplier_counts,
values="العدد",
names="المورد",
title="توزيع المواد حسب المورد",
color="المورد"
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع المواد حسب الوحدة
st.markdown("#### توزيع المواد حسب الوحدة")
unit_counts = filtered_df["الوحدة"].value_counts().reset_index()
unit_counts.columns = ["الوحدة", "العدد"]
fig = px.bar(
unit_counts,
x="الوحدة",
y="العدد",
title="توزيع المواد حسب الوحدة",
color="الوحدة",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض المواد منخفضة المخزون
st.markdown("#### المواد منخفضة المخزون")
low_stock_df = filtered_df[filtered_df["الكمية المتاحة"] < 50].sort_values("الكمية المتاحة")
if not low_stock_df.empty:
fig = px.bar(
low_stock_df,
x="اسم المادة",
y="الكمية المتاحة",
title="المواد منخفضة المخزون",
color="الكمية المتاحة",
color_continuous_scale="Reds_r",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
else:
st.info("لا توجد مواد منخفضة المخزون")
# عرض العلاقة بين مدة التوريد والمورد
st.markdown("#### العلاقة بين مدة التوريد والمورد")
supplier_lead_time = filtered_df.groupby("المورد")["مدة التوريد (يوم)"].mean().reset_index()
supplier_lead_time.columns = ["المورد", "متوسط مدة التوريد (يوم)"]
fig = px.bar(
supplier_lead_time,
x="المورد",
y="متوسط مدة التوريد (يوم)",
title="متوسط مدة التوريد حسب المورد",
color="المورد",
text_auto=".1f"
)
st.plotly_chart(fig, use_container_width=True)
# إضافة مادة جديدة
st.markdown("#### إضافة مادة جديدة")
with st.form("add_material_form"):
col1, col2 = st.columns(2)
with col1:
new_material_name = st.text_input("اسم المادة")
new_material_unit = st.selectbox("الوحدة", options=materials_df["الوحدة"].unique())
new_material_quantity = st.number_input("الكمية المتاحة", min_value=0, max_value=10000, value=100)
with col2:
new_material_cost = st.number_input("تكلفة الوحدة", min_value=1, max_value=10000, value=100)
new_material_supplier = st.selectbox("المورد", options=materials_df["المورد"].unique())
new_material_lead_time = st.number_input("مدة التوريد (يوم)", min_value=1, max_value=90, value=7)
submit_button = st.form_submit_button("إضافة مادة")
if submit_button:
if new_material_name:
# إنشاء رقم مادة جديد
new_material_id = f"MAT-{len(materials_df) + 1:03d}"
# إضافة المادة الجديدة
new_material = pd.DataFrame({
"رقم المادة": [new_material_id],
"اسم المادة": [new_material_name],
"الوحدة": [new_material_unit],
"الكمية المتاحة": [new_material_quantity],
"تكلفة الوحدة": [new_material_cost],
"المورد": [new_material_supplier],
"مدة التوريد (يوم)": [new_material_lead_time]
})
# تحديث DataFrame المواد
st.session_state.resources_data["materials"] = pd.concat([materials_df, new_material], ignore_index=True)
st.success(f"تم إضافة المادة {new_material_name} بنجاح!")
st.rerun()
else:
st.error("يرجى إدخال اسم المادة")
# طلب مواد
st.markdown("#### طلب مواد")
with st.form("order_materials_form"):
col1, col2, col3 = st.columns(3)
with col1:
material_to_order = st.selectbox("المادة", options=materials_df["اسم المادة"].unique())
with col2:
order_quantity = st.number_input("الكمية المطلوبة", min_value=1, max_value=1000, value=50)
with col3:
order_date = st.date_input("تاريخ الطلب", value=datetime.now())
submit_button = st.form_submit_button("طلب المادة")
if submit_button:
# محاكاة طلب المادة
st.success(f"تم طلب {order_quantity} {materials_df[materials_df['اسم المادة'] == material_to_order]['الوحدة'].values[0]} من {material_to_order} بنجاح!")
# عرض تفاصيل الطلب
material_info = materials_df[materials_df["اسم المادة"] == material_to_order].iloc[0]
lead_time = material_info["مدة التوريد (يوم)"]
expected_delivery = order_date + timedelta(days=lead_time)
st.info(f"تاريخ التسليم المتوقع: {expected_delivery.strftime('%Y-%m-%d')}")
# حساب التكلفة الإجمالية
unit_cost = material_info["تكلفة الوحدة"]
total_cost = unit_cost * order_quantity
st.metric("التكلفة الإجمالية", f"{total_cost:,.2f} ريال")
def _render_resource_allocation_tab(self):
"""عرض تبويب تخصيص الموارد"""
st.markdown("### تخصيص الموارد")
# استخراج البيانات
employees_df = st.session_state.resources_data["employees"]
equipment_df = st.session_state.resources_data["equipment"]
materials_df = st.session_state.resources_data["materials"]
projects_df = st.session_state.resources_data["projects"]
allocations_df = st.session_state.resources_data["allocations"]
# عرض خيارات التصفية
st.markdown("#### خيارات التصفية")
col1, col2 = st.columns(2)
with col1:
selected_projects = st.multiselect(
"المشروع",
options=projects_df["اسم المشروع"].unique(),
default=projects_df["اسم المشروع"].unique()
)
with col2:
selected_resource_types = st.multiselect(
"نوع المورد",
options=allocations_df["نوع المورد"].unique(),
default=allocations_df["نوع المورد"].unique()
)
# تحويل أسماء المشاريع إلى أرقام المشاريع
selected_project_ids = projects_df[projects_df["اسم المشروع"].isin(selected_projects)]["رقم المشروع"].tolist()
# تطبيق التصفية
filtered_df = allocations_df[
allocations_df["رقم المشروع"].isin(selected_project_ids) &
allocations_df["نوع المورد"].isin(selected_resource_types)
]
# دمج البيانات مع بيانات المشاريع
merged_df = filtered_df.merge(
projects_df[["رقم المشروع", "اسم المشروع"]],
on="رقم المشروع",
how="left"
)
# إضافة أسماء الموارد
merged_df["اسم المورد"] = ""
for i, row in merged_df.iterrows():
if row["نوع المورد"] == "موظف":
resource_name = employees_df[employees_df["رقم الموظف"] == row["رقم المورد"]]["اسم الموظف"].values
if len(resource_name) > 0:
merged_df.at[i, "اسم المورد"] = resource_name[0]
elif row["نوع المورد"] == "معدة":
resource_name = equipment_df[equipment_df["رقم المعدة"] == row["رقم المورد"]]["اسم المعدة"].values
if len(resource_name) > 0:
merged_df.at[i, "اسم المورد"] = resource_name[0]
elif row["نوع المورد"] == "مادة":
resource_name = materials_df[materials_df["رقم المادة"] == row["رقم المورد"]]["اسم المادة"].values
if len(resource_name) > 0:
merged_df.at[i, "اسم المورد"] = resource_name[0]
# عرض البيانات المصفاة
st.markdown("#### قائمة تخصيص الموارد")
display_df = merged_df[["رقم التخصيص", "اسم المشروع", "نوع المورد", "اسم المورد", "تاريخ البدء", "تاريخ الانتهاء", "الكمية", "التكلفة"]]
st.dataframe(
display_df,
column_config={
"رقم التخصيص": st.column_config.TextColumn("رقم التخصيص"),
"اسم المشروع": st.column_config.TextColumn("اسم المشروع"),
"نوع المورد": st.column_config.TextColumn("نوع المورد"),
"اسم المورد": st.column_config.TextColumn("اسم المورد"),
"تاريخ البدء": st.column_config.DateColumn("تاريخ البدء"),
"تاريخ الانتهاء": st.column_config.DateColumn("تاريخ الانتهاء"),
"الكمية": st.column_config.NumberColumn("الكمية"),
"التكلفة": st.column_config.NumberColumn("التكلفة", format="%.2f ريال")
},
use_container_width=True,
hide_index=True
)
# عرض إحصائيات تخصيص الموارد
st.markdown("#### إحصائيات تخصيص الموارد")
col1, col2, col3, col4 = st.columns(4)
with col1:
total_allocations = len(merged_df)
st.metric("إجمالي التخصيصات", f"{total_allocations}")
with col2:
total_cost = merged_df["التكلفة"].sum()
st.metric("إجمالي التكلفة", f"{total_cost:,.0f} ريال")
with col3:
avg_duration = (pd.to_datetime(merged_df["تاريخ الانتهاء"]) - pd.to_datetime(merged_df["تاريخ البدء"])).mean().days
st.metric("متوسط مدة التخصيص", f"{avg_duration:.0f} يوم")
with col4:
resource_types = merged_df["نوع المورد"].value_counts()
most_common_type = resource_types.index[0] if not resource_types.empty else ""
st.metric("أكثر أنواع الموارد تخصيصاً", f"{most_common_type}")
# عرض توزيع تخصيص الموارد حسب المشروع
st.markdown("#### توزيع تخصيص الموارد حسب المشروع")
project_allocations = merged_df.groupby("اسم المشروع").size().reset_index()
project_allocations.columns = ["اسم المشروع", "عدد التخصيصات"]
fig = px.bar(
project_allocations,
x="اسم المشروع",
y="عدد التخصيصات",
title="توزيع تخصيص الموارد حسب المشروع",
color="اسم المشروع",
text_auto=True
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع تخصيص الموارد حسب نوع المورد
st.markdown("#### توزيع تخصيص الموارد حسب نوع المورد")
resource_type_allocations = merged_df.groupby("نوع المورد").size().reset_index()
resource_type_allocations.columns = ["نوع المورد", "عدد التخصيصات"]
fig = px.pie(
resource_type_allocations,
values="عدد التخصيصات",
names="نوع المورد",
title="توزيع تخصيص الموارد حسب نوع المورد",
color="نوع المورد",
color_discrete_map={
"موظف": "#3498db",
"معدة": "#2ecc71",
"مادة": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع تكاليف الموارد حسب المشروع
st.markdown("#### توزيع تكاليف الموارد حسب المشروع")
project_costs = merged_df.groupby("اسم المشروع")["التكلفة"].sum().reset_index()
project_costs.columns = ["اسم المشروع", "إجمالي التكلفة"]
fig = px.bar(
project_costs,
x="اسم المشروع",
y="إجمالي التكلفة",
title="توزيع تكاليف الموارد حسب المشروع",
color="اسم المشروع",
text_auto=".0f"
)
st.plotly_chart(fig, use_container_width=True)
# عرض توزيع تكاليف الموارد حسب نوع المورد
st.markdown("#### توزيع تكاليف الموارد حسب نوع المورد")
resource_type_costs = merged_df.groupby("نوع المورد")["التكلفة"].sum().reset_index()
resource_type_costs.columns = ["نوع المورد", "إجمالي التكلفة"]
fig = px.pie(
resource_type_costs,
values="إجمالي التكلفة",
names="نوع المورد",
title="توزيع تكاليف الموارد حسب نوع المورد",
color="نوع المورد",
color_discrete_map={
"موظف": "#3498db",
"معدة": "#2ecc71",
"مادة": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
# إضافة تخصيص جديد
st.markdown("#### إضافة تخصيص جديد")
with st.form("add_allocation_form"):
col1, col2 = st.columns(2)
with col1:
new_allocation_project = st.selectbox("المشروع", options=projects_df["اسم المشروع"].unique())
new_allocation_resource_type = st.selectbox("نوع المورد", options=["موظف", "معدة", "مادة"])
# تحديد خيارات الموارد بناءً على النوع
if new_allocation_resource_type == "موظف":
resource_options = employees_df[employees_df["متاح"] == True]["اسم الموظف"].unique()
elif new_allocation_resource_type == "معدة":
resource_options = equipment_df[equipment_df["متاحة"] == True]["اسم المعدة"].unique()
else:
resource_options = materials_df["اسم المادة"].unique()
new_allocation_resource = st.selectbox("المورد", options=resource_options)
with col2:
new_allocation_start_date = st.date_input("تاريخ البدء", value=datetime.now())
new_allocation_end_date = st.date_input("تاريخ الانتهاء", value=datetime.now() + timedelta(days=30))
new_allocation_quantity = st.number_input("الكمية", min_value=1, max_value=100, value=1)
submit_button = st.form_submit_button("إضافة تخصيص")
if submit_button:
# التحقق من صحة التواريخ
if new_allocation_end_date <= new_allocation_start_date:
st.error("يجب أن يكون تاريخ الانتهاء بعد تاريخ البدء")
else:
# الحصول على رقم المشروع
project_id = projects_df[projects_df["اسم المشروع"] == new_allocation_project]["رقم المشروع"].values[0]
# الحصول على رقم المورد
if new_allocation_resource_type == "موظف":
resource_id = employees_df[employees_df["اسم الموظف"] == new_allocation_resource]["رقم الموظف"].values[0]
# حساب التكلفة
cost = employees_df[employees_df["رقم الموظف"] == resource_id]["التكلفة الشهرية"].values[0] * new_allocation_quantity
elif new_allocation_resource_type == "معدة":
resource_id = equipment_df[equipment_df["اسم المعدة"] == new_allocation_resource]["رقم المعدة"].values[0]
# حساب التكلفة
days = (new_allocation_end_date - new_allocation_start_date).days
cost = equipment_df[equipment_df["رقم المعدة"] == resource_id]["التكلفة اليومية"].values[0] * days * new_allocation_quantity
else:
resource_id = materials_df[materials_df["اسم المادة"] == new_allocation_resource]["رقم المادة"].values[0]
# حساب التكلفة
cost = materials_df[materials_df["رقم المادة"] == resource_id]["تكلفة الوحدة"].values[0] * new_allocation_quantity
# إنشاء رقم تخصيص جديد
new_allocation_id = f"ALLOC-{len(allocations_df) + 1:03d}"
# إضافة التخصيص الجديد
new_allocation = pd.DataFrame({
"رقم التخصيص": [new_allocation_id],
"رقم المشروع": [project_id],
"نوع المورد": [new_allocation_resource_type],
"رقم المورد": [resource_id],
"تاريخ البدء": [new_allocation_start_date.strftime("%Y-%m-%d")],
"تاريخ الانتهاء": [new_allocation_end_date.strftime("%Y-%m-%d")],
"الكمية": [new_allocation_quantity],
"التكلفة": [cost]
})
# تحديث DataFrame التخصيصات
st.session_state.resources_data["allocations"] = pd.concat([allocations_df, new_allocation], ignore_index=True)
# تحديث حالة المورد إذا كان موظف أو معدة
if new_allocation_resource_type == "موظف":
employees_idx = employees_df[employees_df["رقم الموظف"] == resource_id].index
st.session_state.resources_data["employees"].at[employees_idx[0], "متاح"] = False
elif new_allocation_resource_type == "معدة":
equipment_idx = equipment_df[equipment_df["رقم المعدة"] == resource_id].index
st.session_state.resources_data["equipment"].at[equipment_idx[0], "متاحة"] = False
elif new_allocation_resource_type == "مادة":
materials_idx = materials_df[materials_df["رقم المادة"] == resource_id].index
current_quantity = st.session_state.resources_data["materials"].at[materials_idx[0], "الكمية المتاحة"]
st.session_state.resources_data["materials"].at[materials_idx[0], "الكمية المتاحة"] = max(0, current_quantity - new_allocation_quantity)
st.success(f"تم إضافة تخصيص {new_allocation_resource_type} ({new_allocation_resource}) لمشروع {new_allocation_project} بنجاح!")
st.rerun()
def _render_resource_planning_tab(self):
"""عرض تبويب تخطيط الموارد"""
st.markdown("### تخطيط الموارد")
# استخراج البيانات
employees_df = st.session_state.resources_data["employees"]
equipment_df = st.session_state.resources_data["equipment"]
materials_df = st.session_state.resources_data["materials"]
projects_df = st.session_state.resources_data["projects"]
allocations_df = st.session_state.resources_data["allocations"]
# عرض المشاريع القادمة
st.markdown("#### المشاريع القادمة")
upcoming_projects = projects_df[projects_df["الحالة"] == "مخطط"].sort_values("تاريخ البدء")
if not upcoming_projects.empty:
st.dataframe(
upcoming_projects,
column_config={
"رقم المشروع": st.column_config.TextColumn("رقم المشروع"),
"اسم المشروع": st.column_config.TextColumn("اسم المشروع"),
"الموقع": st.column_config.TextColumn("الموقع"),
"تاريخ البدء": st.column_config.DateColumn("تاريخ البدء"),
"تاريخ الانتهاء": st.column_config.DateColumn("تاريخ الانتهاء"),
"الميزانية": st.column_config.NumberColumn("الميزانية", format="%.2f ريال"),
"الحالة": st.column_config.TextColumn("الحالة")
},
use_container_width=True,
hide_index=True
)
else:
st.info("لا توجد مشاريع قادمة")
# عرض توافر الموارد
st.markdown("#### توافر الموارد")
col1, col2, col3 = st.columns(3)
with col1:
total_employees = len(employees_df)
available_employees = len(employees_df[employees_df["متاح"] == True])
availability_rate = available_employees / total_employees * 100 if total_employees > 0 else 0
st.metric("الموظفون المتاحون", f"{available_employees}/{total_employees}", f"{availability_rate:.1f}%")
# عرض توزيع توافر الموظفين
availability_data = pd.DataFrame({
"الحالة": ["متاح", "غير متاح"],
"العدد": [available_employees, total_employees - available_employees]
})
fig = px.pie(
availability_data,
values="العدد",
names="الحالة",
title="توافر الموظفين",
color="الحالة",
color_discrete_map={
"متاح": "#2ecc71",
"غير متاح": "#e74c3c"
}
)
st.plotly_chart(fig, use_container_width=True)
with col2:
total_equipment = len(equipment_df)
available_equipment = len(equipment_df[equipment_df["متاحة"] == True])
availability_rate = available_equipment / total_equipment * 100 if total_equipment > 0 else 0
st.metric("المعدات المتاحة", f"{available_equipment}/{total_equipment}", f"{availability_rate:.1f}%")
# عرض توزيع توافر المعدات
availability_data = pd.DataFrame({
"الحالة": ["متاحة", "غير متاحة"],
"العدد": [available_equipment, total_equipment - available_equipment]
})
fig = px.pie(
availability_data,
values="العدد",
names="الحالة",
title="توافر المعدات",
color="الحالة",
color_discrete_map={
"متاحة": "#2ecc71",
"غير متاحة": "#e74c3c"
}
)
st.plotly_chart(fig, use_container_width=True)
with col3:
total_materials = len(materials_df)
low_stock_materials = len(materials_df[materials_df["الكمية المتاحة"] < 50])
low_stock_rate = low_stock_materials / total_materials * 100 if total_materials > 0 else 0
st.metric("المواد منخفضة المخزون", f"{low_stock_materials}/{total_materials}", f"{low_stock_rate:.1f}%")
# عرض توزيع حالة المخزون
stock_data = pd.DataFrame({
"حالة المخزون": ["مخزون كافي", "مخزون منخفض"],
"العدد": [total_materials - low_stock_materials, low_stock_materials]
})
fig = px.pie(
stock_data,
values="العدد",
names="حالة المخزون",
title="حالة مخزون المواد",
color="حالة المخزون",
color_discrete_map={
"مخزون كافي": "#2ecc71",
"مخزون منخفض": "#e74c3c"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض جدول زمني للموارد
st.markdown("#### الجدول الزمني للموارد")
# إنشاء DataFrame للجدول الزمني
timeline_df = allocations_df.copy()
timeline_df["تاريخ البدء"] = pd.to_datetime(timeline_df["تاريخ البدء"])
timeline_df["تاريخ الانتهاء"] = pd.to_datetime(timeline_df["تاريخ الانتهاء"])
# دمج البيانات مع بيانات المشاريع
timeline_df = timeline_df.merge(
projects_df[["رقم المشروع", "اسم المشروع"]],
on="رقم المشروع",
how="left"
)
# إضافة أسماء الموارد
timeline_df["اسم المورد"] = ""
for i, row in timeline_df.iterrows():
if row["نوع المورد"] == "موظف":
resource_name = employees_df[employees_df["رقم الموظف"] == row["رقم المورد"]]["اسم الموظف"].values
if len(resource_name) > 0:
timeline_df.at[i, "اسم المورد"] = resource_name[0]
elif row["نوع المورد"] == "معدة":
resource_name = equipment_df[equipment_df["رقم المعدة"] == row["رقم المورد"]]["اسم المعدة"].values
if len(resource_name) > 0:
timeline_df.at[i, "اسم المورد"] = resource_name[0]
elif row["نوع المورد"] == "مادة":
resource_name = materials_df[materials_df["رقم المادة"] == row["رقم المورد"]]["اسم المادة"].values
if len(resource_name) > 0:
timeline_df.at[i, "اسم المورد"] = resource_name[0]
# إنشاء رسم بياني للجدول الزمني
fig = px.timeline(
timeline_df,
x_start="تاريخ البدء",
x_end="تاريخ الانتهاء",
y="اسم المورد",
color="اسم المشروع",
hover_name="اسم المشروع",
hover_data=["نوع المورد", "الكمية", "التكلفة"],
title="الجدول الزمني لتخصيص الموارد"
)
fig.update_yaxes(autorange="reversed")
st.plotly_chart(fig, use_container_width=True)
# عرض توقعات الاحتياجات المستقبلية
st.markdown("#### توقعات الاحتياجات المستقبلية")
# اختيار المشروع للتخطيط
project_for_planning = st.selectbox("اختر المشروع للتخطيط", options=upcoming_projects["اسم المشروع"] if not upcoming_projects.empty else ["لا توجد مشاريع قادمة"])
if project_for_planning != "لا توجد مشاريع قادمة":
# الحصول على بيانات المشروع
project_data = upcoming_projects[upcoming_projects["اسم المشروع"] == project_for_planning].iloc[0]
st.markdown(f"**تاريخ البدء:** {project_data['تاريخ البدء']}")
st.markdown(f"**تاريخ الانتهاء:** {project_data['تاريخ الانتهاء']}")
st.markdown(f"**الميزانية:** {project_data['الميزانية']:,.0f} ريال")
# تقدير الاحتياجات بناءً على المشاريع المماثلة
st.markdown("##### تقدير الاحتياجات بناءً على المشاريع المماثلة")
# محاكاة تقدير الاحتياجات
estimated_resources = {
"الموظفون": {
"مهندس": 5,
"فني": 10,
"مشرف": 2,
"محاسب": 1,
"مساعد": 3
},
"المعدات": {
"حفارة كبيرة": 1,
"حفارة صغيرة": 2,
"شاحنة نقل": 3,
"رافعة متوسطة": 1,
"خلاطة خرسانة": 2
},
"المواد": {
"خرسانة جاهزة": 500,
"حديد تسليح": 200,
"طابوق": 10000,
"أسمنت": 1000,
"رمل": 300
}
}
# عرض تقدير الاحتياجات
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("**الموظفون المطلوبون:**")
for position, count in estimated_resources["الموظفون"].items():
st.markdown(f"- {position}: {count}")
# التحقق من توافر الموظفين
available_positions = {}
for position, count in estimated_resources["الموظفون"].items():
available_count = len(employees_df[(employees_df["المنصب"] == position) & (employees_df["متاح"] == True)])
available_positions[position] = available_count
if available_count < count:
st.warning(f"نقص في {position}: متاح {available_count}/{count}")
else:
st.success(f"متوفر: {available_count}/{count}")
with col2:
st.markdown("**المعدات المطلوبة:**")
for equipment_name, count in estimated_resources["المعدات"].items():
st.markdown(f"- {equipment_name}: {count}")
# التحقق من توافر المعدات
available_equipment = {}
for equipment_name, count in estimated_resources["المعدات"].items():
available_count = len(equipment_df[(equipment_df["اسم المعدة"] == equipment_name) & (equipment_df["متاحة"] == True)])
available_equipment[equipment_name] = available_count
if available_count < count:
st.warning(f"نقص في {equipment_name}: متاح {available_count}/{count}")
else:
st.success(f"متوفر: {available_count}/{count}")
with col3:
st.markdown("**المواد المطلوبة:**")
for material_name, quantity in estimated_resources["المواد"].items():
st.markdown(f"- {material_name}: {quantity}")
# التحقق من توافر المواد
available_materials = {}
for material_name, quantity in estimated_resources["المواد"].items():
available_quantity = materials_df[materials_df["اسم المادة"] == material_name]["الكمية المتاحة"].sum()
available_materials[material_name] = available_quantity
if available_quantity < quantity:
st.warning(f"نقص في {material_name}: متاح {available_quantity}/{quantity}")
else:
st.success(f"متوفر: {available_quantity}/{quantity}")
# عرض تقدير التكاليف
st.markdown("##### تقدير تكاليف الموارد")
# حساب تكاليف الموظفين
employee_costs = 0
for position, count in estimated_resources["الموظفون"].items():
avg_cost = employees_df[employees_df["المنصب"] == position]["التكلفة الشهرية"].mean()
# افتراض مدة المشروع 6 أشهر
employee_costs += avg_cost * count * 6
# حساب تكاليف المعدات
equipment_costs = 0
for equipment_name, count in estimated_resources["المعدات"].items():
avg_cost = equipment_df[equipment_df["اسم المعدة"] == equipment_name]["التكلفة اليومية"].mean()
# افتراض مدة المشروع 180 يوم
equipment_costs += avg_cost * count * 180
# حساب تكاليف المواد
material_costs = 0
for material_name, quantity in estimated_resources["المواد"].items():
avg_cost = materials_df[materials_df["اسم المادة"] == material_name]["تكلفة الوحدة"].mean()
material_costs += avg_cost * quantity
# إجمالي التكاليف
total_costs = employee_costs + equipment_costs + material_costs
# عرض التكاليف
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("تكاليف الموظفين", f"{employee_costs:,.0f} ريال")
with col2:
st.metric("تكاليف المعدات", f"{equipment_costs:,.0f} ريال")
with col3:
st.metric("تكاليف المواد", f"{material_costs:,.0f} ريال")
with col4:
st.metric("إجمالي التكاليف", f"{total_costs:,.0f} ريال")
# عرض توزيع التكاليف
cost_distribution = pd.DataFrame({
"نوع التكلفة": ["تكاليف الموظفين", "تكاليف المعدات", "تكاليف المواد"],
"التكلفة": [employee_costs, equipment_costs, material_costs]
})
fig = px.pie(
cost_distribution,
values="التكلفة",
names="نوع التكلفة",
title="توزيع تكاليف الموارد",
color="نوع التكلفة",
color_discrete_map={
"تكاليف الموظفين": "#3498db",
"تكاليف المعدات": "#2ecc71",
"تكاليف المواد": "#f39c12"
}
)
st.plotly_chart(fig, use_container_width=True)
# عرض توصيات لتخطيط الموارد
st.markdown("##### توصيات لتخطيط الموارد")
recommendations = []
# توصيات للموظفين
for position, count in estimated_resources["الموظفون"].items():
available_count = available_positions[position]
if available_count < count:
recommendations.append(f"توظيف {count - available_count} {position} إضافي")
# توصيات للمعدات
for equipment_name, count in estimated_resources["المعدات"].items():
available_count = available_equipment[equipment_name]
if available_count < count:
recommendations.append(f"استئجار {count - available_count} {equipment_name} إضافية")
# توصيات للمواد
for material_name, quantity in estimated_resources["المواد"].items():
available_quantity = available_materials[material_name]
if available_quantity < quantity:
recommendations.append(f"شراء {quantity - available_quantity} وحدة إضافية من {material_name}")
if recommendations:
for recommendation in recommendations:
st.markdown(f"- {recommendation}")
else:
st.success("جميع الموارد المطلوبة متوفرة")
# زر لإنشاء خطة الموارد
if st.button("إنشاء خطة الموارد"):
st.success("تم إنشاء خطة الموارد بنجاح!")
# عرض ملخص الخطة
st.markdown("##### ملخص خطة الموارد")
st.markdown(f"**المشروع:** {project_for_planning}")
st.markdown(f"**تاريخ البدء:** {project_data['تاريخ البدء']}")
st.markdown(f"**تاريخ الانتهاء:** {project_data['تاريخ الانتهاء']}")
st.markdown(f"**إجمالي تكاليف الموارد:** {total_costs:,.0f} ريال")
st.markdown(f"**نسبة تكاليف الموارد من الميزانية:** {total_costs / project_data['الميزانية'] * 100:.1f}%")
if recommendations:
st.markdown("**الإجراءات المطلوبة:**")
for recommendation in recommendations:
st.markdown(f"- {recommendation}")
else:
st.markdown("**الإجراءات المطلوبة:** لا توجد إجراءات مطلوبة، جميع الموارد متوفرة")
else:
st.info("لا توجد مشاريع قادمة للتخطيط")