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
# ملاحظة: تم نقل إعداد الصفحة إلى ملف app.py الرئيسي
# لتجنب أخطاء set_page_config يجب أن يكون في ملف واحد فقط
st.title("عرض تحسينات واجهة المستخدم")
# بيانات تجريبية للعرض
@st.cache_data
def get_sample_data():
items = pd.DataFrame({
'رقم البند': ['UB1', 'UB2', 'UB3', 'UB4', 'UB5'],
'وصف البند': ['حفر أساسات', 'صب خرسانة مسلحة', 'أعمال طوب', 'أعمال تشطيبات', 'أعمال كهرباء'],
'الوحدة': ['م3', 'م3', 'م2', 'م2', 'نقطة'],
'الكمية': [350.0, 120.0, 500.0, 800.0, 150.0],
'سعر الوحدة': [80.0, 950.0, 45.0, 120.0, 90.0],
'الإجمالي': [28000.0, 114000.0, 22500.0, 96000.0, 13500.0],
'إستراتيجية التسعير': ['نقص', 'زيادة', 'متوازن', 'زيادة', 'نقص']
})
return items
items = get_sample_data()
# 1. عرض الجدول مع تنسيق محسن
st.markdown("
بنود التسعير غير المتوازن
", unsafe_allow_html=True)
# تعيين ألوان للإستراتيجيات وتنسيق الجدول بشكل متقدم
def highlight_row(row):
strategy = row['إستراتيجية التسعير']
styles = [''] * len(row)
# تطبيق لون خلفية لكل صف حسب الإستراتيجية
if strategy == 'زيادة':
background = 'linear-gradient(90deg, rgba(168, 230, 207, 0.3), rgba(168, 230, 207, 0.1))'
text_color = '#1F7A8C'
elif strategy == 'نقص':
background = 'linear-gradient(90deg, rgba(255, 154, 162, 0.3), rgba(255, 154, 162, 0.1))'
text_color = '#9D2A45'
else:
background = 'linear-gradient(90deg, rgba(220, 237, 255, 0.3), rgba(220, 237, 255, 0.1))'
text_color = '#555555'
# تطبيق النمط على جميع الخلايا في الصف
for i in range(len(styles)):
styles[i] = f'background: {background}; color: {text_color}; border-bottom: 1px solid #ddd;'
# تطبيق نمط خاص على خلية الإستراتيجية
if strategy == 'زيادة':
styles[list(row.index).index('إستراتيجية التسعير')] = 'background-color: #a8e6cf; color: #007263; font-weight: bold; border-radius: 5px; text-align: center;'
elif strategy == 'نقص':
styles[list(row.index).index('إستراتيجية التسعير')] = 'background-color: #ff9aa2; color: #9D2A45; font-weight: bold; border-radius: 5px; text-align: center;'
else:
styles[list(row.index).index('إستراتيجية التسعير')] = 'background-color: #dceeff; color: #555555; font-weight: bold; border-radius: 5px; text-align: center;'
# تنسيق عمود السعر
price_idx = list(row.index).index('سعر الوحدة')
styles[price_idx] = styles[price_idx] + 'font-weight: bold;'
# تنسيق عمود الإجمالي
total_idx = list(row.index).index('الإجمالي')
styles[total_idx] = styles[total_idx] + 'font-weight: bold;'
return styles
# تطبيق التنسيق على الجدول
styled_items = items.style.apply(highlight_row, axis=1)
# تنسيق تنسيق الأرقام
styled_items = styled_items.format({
'الكمية': '{:,.2f}',
'سعر الوحدة': '{:,.2f}',
'الإجمالي': '{:,.2f}'
})
st.dataframe(styled_items, use_container_width=True, height=None)
# 2. عرض المقارنة مع تصميم محسن
st.markdown("مقارنة التسعير المتوازن وغير المتوازن
", unsafe_allow_html=True)
# بيانات المقارنة
original_items = items.copy()
original_items['سعر الوحدة'] = [70.0, 820.0, 45.0, 100.0, 110.0]
original_items['الإجمالي'] = original_items['الكمية'] * original_items['سعر الوحدة']
original_total = original_items['الإجمالي'].sum()
unbalanced_total = items['الإجمالي'].sum()
# عرض بطاقات المقارنة بتصميم متقدم
st.markdown("""
""", unsafe_allow_html=True)
col1, col2, col3 = st.columns(3)
with col1:
st.markdown("""
إجمالي التسعير المتوازن
{:,.2f} ريال
التسعير الأصلي
""".format(original_total), unsafe_allow_html=True)
with col2:
st.markdown("""
إجمالي التسعير غير المتوازن
{:,.2f} ريال
بعد إعادة توزيع الأسعار
""".format(
unbalanced_total,
"positive-delta" if unbalanced_total > original_total else "negative-delta" if unbalanced_total < original_total else "neutral-delta"
), unsafe_allow_html=True)
with col3:
diff = unbalanced_total - original_total
delta_percent = diff/original_total*100 if original_total > 0 else 0
st.markdown("""
الفرق بين التسعيرين
{:,.2f} ريال
نسبة الفرق: {:+.1f}%
""".format(
diff,
"positive-delta" if diff > 0 else "negative-delta" if diff < 0 else "neutral-delta",
delta_percent
), unsafe_allow_html=True)
# 3. رسم بياني للمقارنة
st.markdown("تحليل بصري للتسعير غير المتوازن
", unsafe_allow_html=True)
# إعداد البيانات للرسم البياني
chart_data = pd.DataFrame({
'وصف البند': original_items['وصف البند'],
'التسعير المتوازن': original_items['الإجمالي'],
'التسعير غير المتوازن': items['الإجمالي']
})
# إضافة عمود للنسبة المئوية للتغيير
chart_data['نسبة التغيير'] = (chart_data['التسعير غير المتوازن'] - chart_data['التسعير المتوازن']) / chart_data['التسعير المتوازن'] * 100
# تحديد لون الأعمدة بناءً على نسبة التغيير
bar_colors = []
for change in chart_data['نسبة التغيير']:
if change > 5: # زيادة كبيرة
bar_colors.append('#1F7A8C') # أزرق مخضر
elif change > 0: # زيادة صغيرة
bar_colors.append('#81B29A') # أخضر فاتح
elif change > -5: # نقص صغير
bar_colors.append('#F2CC8F') # أصفر
else: # نقص كبير
bar_colors.append('#E07A5F') # أحمر
# التبويب بين مخططات مختلفة للمقارنة
chart_tabs = st.tabs(["مخطط شريطي", "مخطط مقارنة", "مخطط نسبة التغيير"])
with chart_tabs[0]: # رسم بياني شريطي
# رسم بياني شريطي للمقارنة
fig = go.Figure()
fig.add_trace(go.Bar(
x=chart_data['وصف البند'],
y=chart_data['التسعير المتوازن'],
name='التسعير المتوازن',
marker_color='rgba(55, 83, 109, 0.7)'
))
fig.add_trace(go.Bar(
x=chart_data['وصف البند'],
y=chart_data['التسعير غير المتوازن'],
name='التسعير غير المتوازن',
marker_color=bar_colors
))
fig.update_layout(
title='مقارنة بين التسعير المتوازن وغير المتوازن',
xaxis_tickfont_size=14,
yaxis=dict(
title='الإجمالي (ريال)',
titlefont_size=16,
tickfont_size=14,
),
legend=dict(
x=0.01,
y=0.99,
bgcolor='rgba(255, 255, 255, 0.8)',
bordercolor='rgba(0, 0, 0, 0.1)',
borderwidth=1
),
barmode='group',
bargap=0.15,
bargroupgap=0.1,
plot_bgcolor='rgba(240, 249, 255, 0.5)',
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
with chart_tabs[1]: # رسم مقارنة
# رسم مقارنة بين التسعيرين
fig = go.Figure()
# إضافة خط للتسعير المتوازن
fig.add_trace(go.Scatter(
x=chart_data['وصف البند'],
y=chart_data['التسعير المتوازن'],
name='التسعير المتوازن',
mode='lines+markers',
line=dict(color='rgb(55, 83, 109)', width=3),
marker=dict(size=10, color='rgb(55, 83, 109)')
))
# إضافة نقاط للتسعير غير المتوازن
fig.add_trace(go.Scatter(
x=chart_data['وصف البند'],
y=chart_data['التسعير غير المتوازن'],
name='التسعير غير المتوازن',
mode='lines+markers',
line=dict(color='rgb(26, 118, 255)', width=3),
marker=dict(
size=12,
color=bar_colors,
line=dict(width=2, color='white')
)
))
# تحديثات التخطيط
fig.update_layout(
title='مقارنة مرئية بين استراتيجيات التسعير',
xaxis_tickfont_size=14,
yaxis=dict(
title='القيمة الإجمالية (ريال)',
titlefont_size=16,
tickfont_size=14,
gridcolor='rgba(200, 200, 200, 0.2)'
),
legend=dict(
x=0.01,
y=0.99,
bgcolor='rgba(255, 255, 255, 0.8)',
bordercolor='rgba(0, 0, 0, 0.1)',
borderwidth=1
),
plot_bgcolor='rgba(240, 249, 255, 0.5)',
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
with chart_tabs[2]: # مخطط نسبة التغيير
# مخطط للنسبة المئوية للتغيير
fig = go.Figure()
# إضافة أعمدة لنسبة التغيير مع ألوان مختلفة حسب القيمة
fig.add_trace(go.Bar(
x=chart_data['وصف البند'],
y=chart_data['نسبة التغيير'],
name='نسبة التغيير',
marker_color=bar_colors,
text=[f"{val:.1f}%" for val in chart_data['نسبة التغيير']],
textposition='auto'
))
# إضافة خط أفقي عند الصفر
fig.add_shape(
type="line",
x0=-0.5,
y0=0,
x1=len(chart_data['وصف البند'])-0.5,
y1=0,
line=dict(
color="black",
width=2,
dash="dash",
)
)
# تحديثات التخطيط
fig.update_layout(
title='نسبة التغيير في أسعار البنود (%)',
xaxis_tickfont_size=14,
yaxis=dict(
title='نسبة التغيير (%)',
titlefont_size=16,
tickfont_size=14,
gridcolor='rgba(200, 200, 200, 0.2)',
zeroline=True,
zerolinecolor='black',
zerolinewidth=2
),
plot_bgcolor='rgba(240, 249, 255, 0.5)',
margin=dict(t=50, b=50, l=20, r=20)
)
st.plotly_chart(fig, use_container_width=True)
# إضافة جدول مع نسب التغيير
st.markdown("#### جدول مفصل بنسب التغيير")
# إعداد بيانات الجدول
table_data = chart_data[['وصف البند', 'التسعير المتوازن', 'التسعير غير المتوازن', 'نسبة التغيير']]
# تنسيق الجدول
def highlight_change(row):
change = row['نسبة التغيير']
if change > 5:
return ['', '', '', 'background-color: rgba(31, 122, 140, 0.3); color: #1F7A8C; font-weight: bold;']
elif change > 0:
return ['', '', '', 'background-color: rgba(129, 178, 154, 0.3); color: #2A9D8F; font-weight: bold;']
elif change > -5:
return ['', '', '', 'background-color: rgba(242, 204, 143, 0.3); color: #BC6C25; font-weight: bold;']
else:
return ['', '', '', 'background-color: rgba(224, 122, 95, 0.3); color: #AE2012; font-weight: bold;']
# تطبيق التنسيق
styled_table = table_data.style.apply(highlight_change, axis=1).format({
'التسعير المتوازن': '{:,.2f} ريال',
'التسعير غير المتوازن': '{:,.2f} ريال',
'نسبة التغيير': '{:+.1f}%'
})
st.dataframe(styled_table, use_container_width=True)
# 4. أزرار الحفظ والتصدير مع تصميم محسن
st.markdown("
", unsafe_allow_html=True)
st.markdown("حفظ وتصدير البيانات
", unsafe_allow_html=True)
st.markdown("""
""", unsafe_allow_html=True)
col1, col2 = st.columns(2)
with col1:
# بطاقة حفظ التسعير
st.markdown("""
💾
حفظ التسعير غير المتوازن
قم بحفظ التسعير الحالي في المشروع لاستخدامه لاحقاً في التقارير وفي إجمالي التسعير.
""", unsafe_allow_html=True)
# زر حفظ التسعير غير المتوازن
if st.button("حفظ التسعير غير المتوازن", type="primary", use_container_width=True):
st.success("تم حفظ التسعير غير المتوازن بنجاح!")
st.balloons() # إضافة تأثير احتفالي عند الحفظ
with col2:
# بطاقة تصدير التسعير
st.markdown("""
📊
تصدير البيانات
قم بتصدير جدول التسعير الحالي بصيغة CSV لاستخدامه في برامج أخرى مثل Excel.
""", unsafe_allow_html=True)
# زر تصدير التسعير
export_button = st.button("تجهيز ملف للتصدير", use_container_width=True)
if export_button:
# تحويل البيانات إلى CSV
csv = items.to_csv(index=False)
st.success("تم تجهيز ملف التصدير بنجاح! يمكنك تنزيله الآن.")
# تقديم البيانات للتنزيل
st.download_button(
label="تنزيل ملف CSV",
data=csv,
file_name="unbalanced_pricing.csv",
mime="text/csv",
use_container_width=True
)