Spaces:
Paused
Paused
import streamlit as st | |
import pandas as pd | |
import numpy as np | |
import plotly.express as px | |
def show_requirements_analysis(): | |
""" | |
عرض صفحة تحليل متطلبات المناقصة | |
""" | |
st.subheader("تحليل متطلبات المناقصة") | |
# التحقق من وجود نتائج تحليل سابقة | |
if "analysis_results" not in st.session_state or not st.session_state.analysis_results: | |
st.warning("لا توجد نتائج تحليل متاحة. يرجى تحليل مناقصة أولاً.") | |
if st.button("الانتقال إلى صفحة تحليل المناقصات"): | |
st.session_state.page = "تحليل المناقصات" | |
st.experimental_rerun() | |
# عرض بيانات توضيحية | |
st.markdown("### بيانات توضيحية لمتطلبات المناقصة") | |
sample_requirements = [ | |
{"المتطلب": "توريد وتركيب معدات الشبكة", "النوع": "فني", "الأولوية": "عالية", "التخصص": "تقنية المعلومات"}, | |
{"المتطلب": "تدريب الموظفين", "النوع": "إداري", "الأولوية": "متوسطة", "التخصص": "تدريب"}, | |
{"المتطلب": "توفير الصيانة لمدة 3 سنوات", "النوع": "تعاقدي", "الأولوية": "عالية", "التخصص": "صيانة"}, | |
{"المتطلب": "الالتزام بمعايير الأمن السيبراني", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "أمن المعلومات"}, | |
{"المتطلب": "نسبة محتوى محلي لا تقل عن 50%", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "محتوى محلي"}, | |
{"المتطلب": "تقديم ضمان بنكي بنسبة 10%", "النوع": "مالي", "الأولوية": "متوسطة", "التخصص": "مالي"}, | |
{"المتطلب": "تنفيذ المشروع في مدة لا تتجاوز 18 شهر", "النوع": "زمني", "الأولوية": "عالية", "التخصص": "إدارة مشاريع"}, | |
] | |
sample_df = pd.DataFrame(sample_requirements) | |
st.table(sample_df) | |
return | |
# عرض معلومات المناقصة | |
results = st.session_state.analysis_results | |
st.markdown(f"### تحليل متطلبات المناقصة رقم {results['tender_id']}") | |
# إنشاء بيانات المتطلبات (نستخدم البيانات المتاحة أو نضيف تفاصيل إضافية) | |
# في التطبيق الفعلي، ستكون هذه البيانات من نتائج التحليل الحقيقي | |
requirements = [] | |
for i, req in enumerate(results.get("requirements", [])): | |
# إنشاء تفاصيل عشوائية لكل متطلب للتوضيح | |
req_type = np.random.choice(["فني", "إداري", "تعاقدي", "تنظيمي", "مالي", "زمني"]) | |
priority = np.random.choice(["عالية", "متوسطة", "منخفضة"], p=[0.5, 0.3, 0.2]) | |
specializations = { | |
"فني": ["هندسة", "تقنية المعلومات", "اتصالات", "كهرباء", "ميكانيكا"], | |
"إداري": ["إدارة مشاريع", "موارد بشرية", "تدريب", "جودة"], | |
"تعاقدي": ["قانوني", "مشتريات", "عقود", "صيانة"], | |
"تنظيمي": ["امتثال", "أمن المعلومات", "محتوى محلي", "بيئة"], | |
"مالي": ["محاسبة", "ضمانات", "تمويل", "مالي"], | |
"زمني": ["إدارة مشاريع", "جدولة", "تخطيط"] | |
} | |
specialization = np.random.choice(specializations.get(req_type, ["عام"])) | |
requirements.append({ | |
"المتطلب": req, | |
"النوع": req_type, | |
"الأولوية": priority, | |
"التخصص": specialization | |
}) | |
# إذا لم تكن هناك متطلبات، إنشاء بيانات توضيحية | |
if not requirements: | |
requirements = [ | |
{"المتطلب": "توريد وتركيب معدات", "النوع": "فني", "الأولوية": "عالية", "التخصص": "هندسة"}, | |
{"المتطلب": "تدريب الموظفين", "النوع": "إداري", "الأولوية": "متوسطة", "التخصص": "تدريب"}, | |
{"المتطلب": "صيانة دورية", "النوع": "تعاقدي", "الأولوية": "متوسطة", "التخصص": "صيانة"}, | |
{"المتطلب": "الامتثال للمعايير", "النوع": "تنظيمي", "الأولوية": "عالية", "التخصص": "امتثال"}, | |
{"المتطلب": "تقديم ضمانات مالية", "النوع": "مالي", "الأولوية": "عالية", "التخصص": "مالي"} | |
] | |
# تحويل البيانات إلى DataFrame | |
requirements_df = pd.DataFrame(requirements) | |
# تبويبات لعرض المتطلبات بطرق مختلفة | |
tab1, tab2, tab3 = st.tabs(["قائمة المتطلبات", "تصنيف المتطلبات", "تحليل المتطلبات"]) | |
# تبويب قائمة المتطلبات | |
with tab1: | |
st.markdown("### قائمة متطلبات المناقصة") | |
st.dataframe(requirements_df, use_container_width=True) | |
# خيار تصفية المتطلبات | |
st.markdown("### تصفية المتطلبات") | |
col1, col2 = st.columns(2) | |
with col1: | |
selected_type = st.selectbox( | |
"تصفية حسب النوع", | |
["الكل"] + sorted(requirements_df["النوع"].unique().tolist()) | |
) | |
with col2: | |
selected_priority = st.selectbox( | |
"تصفية حسب الأولوية", | |
["الكل"] + sorted(requirements_df["الأولوية"].unique().tolist()) | |
) | |
# تطبيق التصفية | |
filtered_df = requirements_df.copy() | |
if selected_type != "الكل": | |
filtered_df = filtered_df[filtered_df["النوع"] == selected_type] | |
if selected_priority != "الكل": | |
filtered_df = filtered_df[filtered_df["الأولوية"] == selected_priority] | |
if selected_type != "الكل" or selected_priority != "الكل": | |
st.markdown("### المتطلبات المصفاة") | |
st.dataframe(filtered_df, use_container_width=True) | |
# تبويب تصنيف المتطلبات | |
with tab2: | |
st.markdown("### تصنيف المتطلبات حسب النوع والأولوية") | |
# رسم بياني للمتطلبات حسب النوع | |
type_counts = requirements_df["النوع"].value_counts().reset_index() | |
type_counts.columns = ["النوع", "العدد"] | |
fig1 = px.bar( | |
type_counts, | |
x="النوع", | |
y="العدد", | |
color="النوع", | |
title="توزيع المتطلبات حسب النوع" | |
) | |
st.plotly_chart(fig1, use_container_width=True) | |
# رسم بياني للمتطلبات حسب الأولوية | |
priority_counts = requirements_df["الأولوية"].value_counts().reset_index() | |
priority_counts.columns = ["الأولوية", "العدد"] | |
# ترتيب الأولويات | |
priority_order = {"عالية": 1, "متوسطة": 2, "منخفضة": 3} | |
priority_counts["الترتيب"] = priority_counts["الأولوية"].map(priority_order) | |
priority_counts = priority_counts.sort_values("الترتيب") | |
# اختيار الألوان حسب الأولوية | |
color_map = {"عالية": "#FF5733", "متوسطة": "#FFC300", "منخفضة": "#33FF57"} | |
colors = priority_counts["الأولوية"].map(color_map) | |
fig2 = px.bar( | |
priority_counts, | |
x="الأولوية", | |
y="العدد", | |
color="الأولوية", | |
color_discrete_map=color_map, | |
title="توزيع المتطلبات حسب الأولوية" | |
) | |
st.plotly_chart(fig2, use_container_width=True) | |
# تبويب تحليل المتطلبات | |
with tab3: | |
st.markdown("### تحليل المتطلبات") | |
# توزيع المتطلبات حسب التخصص | |
specialization_counts = requirements_df["التخصص"].value_counts().reset_index() | |
specialization_counts.columns = ["التخصص", "العدد"] | |
fig3 = px.pie( | |
specialization_counts, | |
values="العدد", | |
names="التخصص", | |
title="توزيع المتطلبات حسب التخصص", | |
color_discrete_sequence=px.colors.qualitative.Bold | |
) | |
fig3.update_traces(textposition="inside", textinfo="percent+label") | |
st.plotly_chart(fig3, use_container_width=True) | |
# مصفوفة المتطلبات (النوع × الأولوية) | |
heatmap_data = pd.crosstab( | |
requirements_df["النوع"], | |
requirements_df["الأولوية"], | |
margins=True, | |
margins_name="الإجمالي" | |
) | |
# ترتيب الأعمدة (الأولويات) | |
priority_columns = ["عالية", "متوسطة", "منخفضة", "الإجمالي"] | |
heatmap_data = heatmap_data.reindex(columns=priority_columns, fill_value=0) | |
st.markdown("### مصفوفة المتطلبات (النوع × الأولوية)") | |
st.dataframe(heatmap_data, use_container_width=True) | |
# خيارات إضافية | |
st.markdown("### خيارات إضافية") | |
col1, col2 = st.columns(2) | |
with col1: | |
if st.button("تصدير المتطلبات إلى Excel"): | |
st.success("تم تصدير المتطلبات إلى ملف Excel بنجاح!") | |
with col2: | |
if st.button("العودة إلى تحليل المناقصة"): | |
st.session_state.page = "تحليل المناقصات" | |
st.experimental_rerun() | |
# اختبار مستقل للصفحة | |
if __name__ == "__main__": | |
st.set_page_config( | |
page_title="نظام تحليل المناقصات - تحليل المتطلبات", | |
page_icon="📊", | |
layout="wide", | |
) | |
show_requirements_analysis() |