|
""" |
|
وحدة الإشعارات الذكية - نظام تحليل المناقصات |
|
""" |
|
|
|
import streamlit as st |
|
import pandas as pd |
|
import datetime |
|
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 NotificationsApp: |
|
"""تطبيق الإشعارات الذكية""" |
|
|
|
def __init__(self): |
|
"""تهيئة تطبيق الإشعارات الذكية""" |
|
self.ui = UIEnhancer(page_title="الإشعارات الذكية - نظام تحليل المناقصات", page_icon="🔔") |
|
|
|
|
|
if 'theme' not in st.session_state: |
|
st.session_state.theme = 'light' |
|
|
|
self.ui.apply_theme_colors() |
|
|
|
|
|
self.notifications_data = [ |
|
{ |
|
"id": "N001", |
|
"title": "موعد تسليم مناقصة", |
|
"message": "موعد تسليم مناقصة T-2025-001 (إنشاء مبنى إداري) بعد 5 أيام", |
|
"type": "deadline", |
|
"priority": "high", |
|
"related_entity": "T-2025-001", |
|
"created_at": "2025-03-25T10:30:00", |
|
"is_read": False |
|
}, |
|
{ |
|
"id": "N002", |
|
"title": "ترسية مناقصة", |
|
"message": "تم ترسية مناقصة T-2025-003 (توريد معدات) بنجاح", |
|
"type": "award", |
|
"priority": "medium", |
|
"related_entity": "T-2025-003", |
|
"created_at": "2025-03-28T14:15:00", |
|
"is_read": True |
|
}, |
|
{ |
|
"id": "N003", |
|
"title": "تحديث مستندات", |
|
"message": "تم تحديث مستندات مناقصة T-2025-002 (صيانة طرق)", |
|
"type": "document", |
|
"priority": "medium", |
|
"related_entity": "T-2025-002", |
|
"created_at": "2025-03-29T09:45:00", |
|
"is_read": False |
|
}, |
|
{ |
|
"id": "N004", |
|
"title": "تغيير في المواصفات", |
|
"message": "تم تغيير المواصفات الفنية لمناقصة T-2025-001 (إنشاء مبنى إداري)", |
|
"type": "change", |
|
"priority": "high", |
|
"related_entity": "T-2025-001", |
|
"created_at": "2025-03-27T11:20:00", |
|
"is_read": False |
|
}, |
|
{ |
|
"id": "N005", |
|
"title": "تأخير في المشروع", |
|
"message": "تأخير في تنفيذ مشروع P002 (تطوير طريق الملك فهد - جدة)", |
|
"type": "delay", |
|
"priority": "high", |
|
"related_entity": "P002", |
|
"created_at": "2025-03-26T16:10:00", |
|
"is_read": True |
|
}, |
|
{ |
|
"id": "N006", |
|
"title": "اكتمال مرحلة", |
|
"message": "اكتمال مرحلة الأساسات في مشروع P001 (إنشاء مبنى إداري - الرياض)", |
|
"type": "milestone", |
|
"priority": "low", |
|
"related_entity": "P001", |
|
"created_at": "2025-03-24T13:30:00", |
|
"is_read": True |
|
}, |
|
{ |
|
"id": "N007", |
|
"title": "طلب معلومات إضافية", |
|
"message": "طلب معلومات إضافية لمناقصة T-2025-004 (تجهيز مختبرات)", |
|
"type": "request", |
|
"priority": "medium", |
|
"related_entity": "T-2025-004", |
|
"created_at": "2025-03-30T08:15:00", |
|
"is_read": False |
|
}, |
|
{ |
|
"id": "N008", |
|
"title": "تحديث أسعار المواد", |
|
"message": "تم تحديث أسعار مواد البناء في قاعدة البيانات", |
|
"type": "update", |
|
"priority": "low", |
|
"related_entity": "DB-MATERIALS", |
|
"created_at": "2025-03-29T15:40:00", |
|
"is_read": False |
|
}, |
|
{ |
|
"id": "N009", |
|
"title": "اجتماع فريق العمل", |
|
"message": "اجتماع فريق العمل لمناقشة مناقصة T-2025-001 غداً الساعة 10:00 صباحاً", |
|
"type": "meeting", |
|
"priority": "medium", |
|
"related_entity": "T-2025-001", |
|
"created_at": "2025-03-28T16:20:00", |
|
"is_read": True |
|
}, |
|
{ |
|
"id": "N010", |
|
"title": "تغيير في الميزانية", |
|
"message": "تم تغيير الميزانية المخصصة لمشروع P004 (بناء مدرسة - أبها)", |
|
"type": "budget", |
|
"priority": "high", |
|
"related_entity": "P004", |
|
"created_at": "2025-03-25T14:50:00", |
|
"is_read": False |
|
} |
|
] |
|
|
|
|
|
self.notification_settings = { |
|
"deadline": True, |
|
"award": True, |
|
"document": True, |
|
"change": True, |
|
"delay": True, |
|
"milestone": True, |
|
"request": True, |
|
"update": True, |
|
"meeting": True, |
|
"budget": True, |
|
"email_notifications": True, |
|
"sms_notifications": False, |
|
"push_notifications": True, |
|
"notification_frequency": "realtime" |
|
} |
|
|
|
def run(self): |
|
"""تشغيل تطبيق الإشعارات الذكية""" |
|
|
|
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" |
|
|
|
|
|
self.ui.theme_mode = st.session_state.theme |
|
self.ui.apply_theme_colors() |
|
st.rerun() |
|
|
|
|
|
self.ui.create_header("الإشعارات الذكية", "إدارة ومتابعة الإشعارات والتنبيهات") |
|
|
|
|
|
tabs = st.tabs(["الإشعارات الحالية", "إعدادات الإشعارات", "إنشاء إشعار", "سجل الإشعارات"]) |
|
|
|
|
|
with tabs[0]: |
|
self.show_current_notifications() |
|
|
|
|
|
with tabs[1]: |
|
self.show_notification_settings() |
|
|
|
|
|
with tabs[2]: |
|
self.create_notification() |
|
|
|
|
|
with tabs[3]: |
|
self.show_notification_history() |
|
|
|
def show_current_notifications(self): |
|
"""عرض الإشعارات الحالية""" |
|
st.markdown("### الإشعارات الحالية") |
|
|
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
type_filter = st.multiselect( |
|
"نوع الإشعار", |
|
options=["الكل", "موعد نهائي", "ترسية", "مستند", "تغيير", "تأخير", "مرحلة", "طلب", "تحديث", "اجتماع", "ميزانية"], |
|
default=["الكل"] |
|
) |
|
|
|
with col2: |
|
priority_filter = st.multiselect( |
|
"الأولوية", |
|
options=["الكل", "عالية", "متوسطة", "منخفضة"], |
|
default=["الكل"] |
|
) |
|
|
|
with col3: |
|
read_filter = st.radio( |
|
"الحالة", |
|
options=["الكل", "غير مقروءة", "مقروءة"], |
|
horizontal=True |
|
) |
|
|
|
|
|
filtered_notifications = self.notifications_data |
|
|
|
|
|
type_mapping = { |
|
"موعد نهائي": "deadline", |
|
"ترسية": "award", |
|
"مستند": "document", |
|
"تغيير": "change", |
|
"تأخير": "delay", |
|
"مرحلة": "milestone", |
|
"طلب": "request", |
|
"تحديث": "update", |
|
"اجتماع": "meeting", |
|
"ميزانية": "budget" |
|
} |
|
|
|
|
|
priority_mapping = { |
|
"عالية": "high", |
|
"متوسطة": "medium", |
|
"منخفضة": "low" |
|
} |
|
|
|
if "الكل" not in type_filter and type_filter: |
|
filtered_types = [type_mapping[t] for t in type_filter if t in type_mapping] |
|
filtered_notifications = [n for n in filtered_notifications if n["type"] in filtered_types] |
|
|
|
if "الكل" not in priority_filter and priority_filter: |
|
filtered_priorities = [priority_mapping[p] for p in priority_filter if p in priority_mapping] |
|
filtered_notifications = [n for n in filtered_notifications if n["priority"] in filtered_priorities] |
|
|
|
if read_filter == "غير مقروءة": |
|
filtered_notifications = [n for n in filtered_notifications if not n["is_read"]] |
|
elif read_filter == "مقروءة": |
|
filtered_notifications = [n for n in filtered_notifications if n["is_read"]] |
|
|
|
|
|
unread_count = len([n for n in filtered_notifications if not n["is_read"]]) |
|
|
|
st.markdown(f"**عدد الإشعارات غير المقروءة:** {unread_count}") |
|
|
|
|
|
col1, col2 = st.columns([1, 1]) |
|
with col1: |
|
if st.button("تحديث الإشعارات", use_container_width=True): |
|
st.success("تم تحديث الإشعارات بنجاح") |
|
|
|
with col2: |
|
if st.button("تعليم الكل كمقروء", use_container_width=True): |
|
st.success("تم تعليم جميع الإشعارات كمقروءة") |
|
|
|
|
|
if not filtered_notifications: |
|
st.info("لا توجد إشعارات تطابق الفلاتر المحددة") |
|
else: |
|
for notification in filtered_notifications: |
|
self.display_notification(notification) |
|
|
|
def display_notification(self, notification): |
|
"""عرض إشعار واحد""" |
|
|
|
if notification["priority"] == "high": |
|
color = self.ui.COLORS['danger'] |
|
priority_text = "عالية" |
|
elif notification["priority"] == "medium": |
|
color = self.ui.COLORS['warning'] |
|
priority_text = "متوسطة" |
|
else: |
|
color = self.ui.COLORS['secondary'] |
|
priority_text = "منخفضة" |
|
|
|
|
|
type_mapping = { |
|
"deadline": "موعد نهائي", |
|
"award": "ترسية", |
|
"document": "مستند", |
|
"change": "تغيير", |
|
"delay": "تأخير", |
|
"milestone": "مرحلة", |
|
"request": "طلب", |
|
"update": "تحديث", |
|
"meeting": "اجتماع", |
|
"budget": "ميزانية" |
|
} |
|
|
|
notification_type = type_mapping.get(notification["type"], notification["type"]) |
|
|
|
|
|
created_at = datetime.datetime.fromisoformat(notification["created_at"]) |
|
formatted_date = created_at.strftime("%Y-%m-%d %H:%M") |
|
|
|
|
|
icon_mapping = { |
|
"deadline": "⏰", |
|
"award": "🏆", |
|
"document": "📄", |
|
"change": "🔄", |
|
"delay": "⚠️", |
|
"milestone": "🏁", |
|
"request": "❓", |
|
"update": "🔄", |
|
"meeting": "👥", |
|
"budget": "💰" |
|
} |
|
|
|
icon = icon_mapping.get(notification["type"], "📌") |
|
|
|
|
|
st.markdown( |
|
f""" |
|
<div style="border-left: 5px solid {color}; padding: 10px; margin-bottom: 10px; background-color: {'#f8f9fa' if st.session_state.theme == 'light' else '#2b2b2b'}; border-radius: 5px; {'opacity: 0.7;' if notification['is_read'] else ''}"> |
|
<div style="display: flex; justify-content: space-between; align-items: center;"> |
|
<div> |
|
<h4 style="margin: 0;">{icon} {notification['title']}</h4> |
|
<p style="margin: 5px 0;">{notification['message']}</p> |
|
<div style="display: flex; gap: 10px; font-size: 0.8em; color: {'#6c757d' if st.session_state.theme == 'light' else '#adb5bd'};"> |
|
<span>النوع: {notification_type}</span> |
|
<span>الأولوية: {priority_text}</span> |
|
<span>التاريخ: {formatted_date}</span> |
|
</div> |
|
</div> |
|
<div> |
|
<button style="background: none; border: none; cursor: pointer; color: {'#6c757d' if st.session_state.theme == 'light' else '#adb5bd'};">✓</button> |
|
<button style="background: none; border: none; cursor: pointer; color: {'#6c757d' if st.session_state.theme == 'light' else '#adb5bd'};">🗑️</button> |
|
</div> |
|
</div> |
|
</div> |
|
""", |
|
unsafe_allow_html=True |
|
) |
|
|
|
def show_notification_settings(self): |
|
"""عرض إعدادات الإشعارات""" |
|
st.markdown("### إعدادات الإشعارات") |
|
|
|
|
|
with st.form("notification_settings_form"): |
|
st.markdown("#### أنواع الإشعارات") |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
deadline = st.checkbox("المواعيد النهائية", value=self.notification_settings["deadline"]) |
|
award = st.checkbox("ترسية المناقصات", value=self.notification_settings["award"]) |
|
document = st.checkbox("تحديثات المستندات", value=self.notification_settings["document"]) |
|
change = st.checkbox("التغييرات في المواصفات", value=self.notification_settings["change"]) |
|
delay = st.checkbox("التأخيرات في المشاريع", value=self.notification_settings["delay"]) |
|
|
|
with col2: |
|
milestone = st.checkbox("اكتمال المراحل", value=self.notification_settings["milestone"]) |
|
request = st.checkbox("طلبات المعلومات", value=self.notification_settings["request"]) |
|
update = st.checkbox("تحديثات النظام", value=self.notification_settings["update"]) |
|
meeting = st.checkbox("الاجتماعات", value=self.notification_settings["meeting"]) |
|
budget = st.checkbox("تغييرات الميزانية", value=self.notification_settings["budget"]) |
|
|
|
st.markdown("#### طرق الإشعار") |
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
email_notifications = st.checkbox("البريد الإلكتروني", value=self.notification_settings["email_notifications"]) |
|
|
|
with col2: |
|
sms_notifications = st.checkbox("الرسائل النصية", value=self.notification_settings["sms_notifications"]) |
|
|
|
with col3: |
|
push_notifications = st.checkbox("إشعارات الويب", value=self.notification_settings["push_notifications"]) |
|
|
|
st.markdown("#### تكرار الإشعارات") |
|
|
|
notification_frequency = st.radio( |
|
"تكرار الإشعارات", |
|
options=["في الوقت الحقيقي", "مرة واحدة يومياً", "مرة واحدة أسبوعياً"], |
|
index=0 if self.notification_settings["notification_frequency"] == "realtime" else 1 if self.notification_settings["notification_frequency"] == "daily" else 2, |
|
horizontal=True |
|
) |
|
|
|
|
|
submit_button = st.form_submit_button("حفظ الإعدادات") |
|
|
|
if submit_button: |
|
|
|
self.notification_settings.update({ |
|
"deadline": deadline, |
|
"award": award, |
|
"document": document, |
|
"change": change, |
|
"delay": delay, |
|
"milestone": milestone, |
|
"request": request, |
|
"update": update, |
|
"meeting": meeting, |
|
"budget": budget, |
|
"email_notifications": email_notifications, |
|
"sms_notifications": sms_notifications, |
|
"push_notifications": push_notifications, |
|
"notification_frequency": "realtime" if notification_frequency == "في الوقت الحقيقي" else "daily" if notification_frequency == "مرة واحدة يومياً" else "weekly" |
|
}) |
|
|
|
st.success("تم حفظ الإعدادات بنجاح") |
|
|
|
|
|
st.markdown("### إعدادات متقدمة") |
|
|
|
with st.expander("إعدادات متقدمة"): |
|
st.markdown("#### جدولة الإشعارات") |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
st.time_input("وقت الإشعارات اليومية", datetime.time(9, 0)) |
|
|
|
with col2: |
|
st.selectbox( |
|
"يوم الإشعارات الأسبوعية", |
|
options=["الأحد", "الاثنين", "الثلاثاء", "الأربعاء", "الخميس", "الجمعة", "السبت"], |
|
index=0 |
|
) |
|
|
|
st.markdown("#### فلترة الإشعارات") |
|
|
|
min_priority = st.select_slider( |
|
"الحد الأدنى للأولوية", |
|
options=["منخفضة", "متوسطة", "عالية"], |
|
value="منخفضة" |
|
) |
|
|
|
st.markdown("#### حفظ الإشعارات") |
|
|
|
retention_period = st.slider( |
|
"فترة الاحتفاظ بالإشعارات (بالأيام)", |
|
min_value=7, |
|
max_value=365, |
|
value=90, |
|
step=1 |
|
) |
|
|
|
if st.button("حفظ الإعدادات المتقدمة"): |
|
st.success("تم حفظ الإعدادات المتقدمة بنجاح") |
|
|
|
def create_notification(self): |
|
"""إنشاء إشعار جديد""" |
|
st.markdown("### إنشاء إشعار جديد") |
|
|
|
|
|
with st.form("new_notification_form"): |
|
title = st.text_input("عنوان الإشعار") |
|
message = st.text_area("نص الإشعار") |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
notification_type = st.selectbox( |
|
"نوع الإشعار", |
|
options=["موعد نهائي", "ترسية", "مستند", "تغيير", "تأخير", "مرحلة", "طلب", "تحديث", "اجتماع", "ميزانية"] |
|
) |
|
|
|
|
|
type_mapping = { |
|
"موعد نهائي": "deadline", |
|
"ترسية": "award", |
|
"مستند": "document", |
|
"تغيير": "change", |
|
"تأخير": "delay", |
|
"مرحلة": "milestone", |
|
"طلب": "request", |
|
"تحديث": "update", |
|
"اجتماع": "meeting", |
|
"ميزانية": "budget" |
|
} |
|
|
|
notification_type_en = type_mapping.get(notification_type, "deadline") |
|
|
|
priority = st.selectbox( |
|
"الأولوية", |
|
options=["عالية", "متوسطة", "منخفضة"] |
|
) |
|
|
|
|
|
priority_mapping = { |
|
"عالية": "high", |
|
"متوسطة": "medium", |
|
"منخفضة": "low" |
|
} |
|
|
|
priority_en = priority_mapping.get(priority, "medium") |
|
|
|
with col2: |
|
related_entity = st.text_input("الكيان المرتبط (مثل: رقم المناقصة، رقم المشروع)") |
|
|
|
notification_date = st.date_input( |
|
"تاريخ الإشعار", |
|
value=datetime.datetime.now().date() |
|
) |
|
|
|
notification_time = st.time_input( |
|
"وقت الإشعار", |
|
value=datetime.datetime.now().time() |
|
) |
|
|
|
|
|
submit_button = st.form_submit_button("إنشاء الإشعار") |
|
|
|
if submit_button and title and message: |
|
|
|
new_id = f"N{len(self.notifications_data) + 1:03d}" |
|
|
|
|
|
notification_datetime = datetime.datetime.combine(notification_date, notification_time) |
|
notification_datetime_iso = notification_datetime.isoformat() |
|
|
|
|
|
self.notifications_data.append({ |
|
"id": new_id, |
|
"title": title, |
|
"message": message, |
|
"type": notification_type_en, |
|
"priority": priority_en, |
|
"related_entity": related_entity, |
|
"created_at": notification_datetime_iso, |
|
"is_read": False |
|
}) |
|
|
|
st.success("تم إنشاء الإشعار بنجاح") |
|
|
|
|
|
st.markdown("### الإشعار الجديد") |
|
self.display_notification(self.notifications_data[-1]) |
|
|
|
|
|
st.markdown("### إنشاء إشعارات متعددة") |
|
|
|
with st.expander("إنشاء إشعارات متعددة"): |
|
st.markdown("#### تحميل ملف إشعارات") |
|
|
|
uploaded_file = st.file_uploader("قم بتحميل ملف إشعارات (CSV, JSON)", type=["csv", "json"]) |
|
|
|
if uploaded_file is not None: |
|
if st.button("استيراد الإشعارات"): |
|
st.success("تم استيراد الإشعارات بنجاح") |
|
|
|
st.markdown("#### إنشاء إشعارات من قالب") |
|
|
|
template_type = st.selectbox( |
|
"نوع القالب", |
|
options=["إشعارات المواعيد النهائية", "إشعارات الاجتماعات", "إشعارات التحديثات"] |
|
) |
|
|
|
if st.button("إنشاء إشعارات من القالب"): |
|
st.success("تم إنشاء الإشعارات من القالب بنجاح") |
|
|
|
def show_notification_history(self): |
|
"""عرض سجل الإشعارات""" |
|
st.markdown("### سجل الإشعارات") |
|
|
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
date_range = st.date_input( |
|
"نطاق التاريخ", |
|
value=( |
|
datetime.datetime.now().date() - datetime.timedelta(days=30), |
|
datetime.datetime.now().date() |
|
) |
|
) |
|
|
|
with col2: |
|
entity_filter = st.text_input("الكيان المرتبط") |
|
|
|
|
|
notifications_df = pd.DataFrame(self.notifications_data) |
|
|
|
|
|
notifications_df["created_at"] = pd.to_datetime(notifications_df["created_at"]) |
|
|
|
|
|
if len(date_range) == 2: |
|
start_date, end_date = date_range |
|
start_date = pd.to_datetime(start_date) |
|
end_date = pd.to_datetime(end_date) + pd.Timedelta(days=1) - pd.Timedelta(seconds=1) |
|
|
|
notifications_df = notifications_df[ |
|
(notifications_df["created_at"] >= start_date) & |
|
(notifications_df["created_at"] <= end_date) |
|
] |
|
|
|
|
|
if entity_filter: |
|
notifications_df = notifications_df[ |
|
notifications_df["related_entity"].str.contains(entity_filter, case=False) |
|
] |
|
|
|
|
|
type_mapping = { |
|
"deadline": "موعد نهائي", |
|
"award": "ترسية", |
|
"document": "مستند", |
|
"change": "تغيير", |
|
"delay": "تأخير", |
|
"milestone": "مرحلة", |
|
"request": "طلب", |
|
"update": "تحديث", |
|
"meeting": "اجتماع", |
|
"budget": "ميزانية" |
|
} |
|
|
|
notifications_df["type_ar"] = notifications_df["type"].map(type_mapping) |
|
|
|
|
|
priority_mapping = { |
|
"high": "عالية", |
|
"medium": "متوسطة", |
|
"low": "منخفضة" |
|
} |
|
|
|
notifications_df["priority_ar"] = notifications_df["priority"].map(priority_mapping) |
|
|
|
|
|
notifications_df["is_read_text"] = notifications_df["is_read"].map({True: "مقروءة", False: "غير مقروءة"}) |
|
|
|
|
|
notifications_df["created_at_formatted"] = notifications_df["created_at"].dt.strftime("%Y-%m-%d %H:%M") |
|
|
|
|
|
display_df = notifications_df[[ |
|
"id", "title", "type_ar", "priority_ar", "related_entity", |
|
"created_at_formatted", "is_read_text" |
|
]].rename(columns={ |
|
"id": "الرقم", |
|
"title": "العنوان", |
|
"type_ar": "النوع", |
|
"priority_ar": "الأولوية", |
|
"related_entity": "الكيان المرتبط", |
|
"created_at_formatted": "التاريخ", |
|
"is_read_text": "الحالة" |
|
}) |
|
|
|
|
|
st.dataframe(display_df, use_container_width=True, hide_index=True) |
|
|
|
|
|
st.markdown("### إحصائيات الإشعارات") |
|
|
|
col1, col2, col3 = st.columns(3) |
|
|
|
with col1: |
|
total_count = len(notifications_df) |
|
st.metric("إجمالي الإشعارات", total_count) |
|
|
|
with col2: |
|
read_count = len(notifications_df[notifications_df["is_read"] == True]) |
|
st.metric("الإشعارات المقروءة", read_count) |
|
|
|
with col3: |
|
unread_count = len(notifications_df[notifications_df["is_read"] == False]) |
|
st.metric("الإشعارات غير المقروءة", unread_count) |
|
|
|
|
|
st.markdown("#### توزيع الإشعارات حسب النوع") |
|
|
|
type_counts = notifications_df["type_ar"].value_counts().reset_index() |
|
type_counts.columns = ["النوع", "العدد"] |
|
|
|
st.bar_chart(type_counts, x="النوع", y="العدد") |
|
|
|
|
|
st.markdown("#### توزيع الإشعارات حسب الأولوية") |
|
|
|
priority_counts = notifications_df["priority_ar"].value_counts().reset_index() |
|
priority_counts.columns = ["الأولوية", "العدد"] |
|
|
|
st.bar_chart(priority_counts, x="الأولوية", y="العدد") |
|
|
|
|
|
st.markdown("### تصدير البيانات") |
|
|
|
col1, col2 = st.columns(2) |
|
|
|
with col1: |
|
if st.button("تصدير إلى CSV"): |
|
st.success("تم تصدير البيانات إلى CSV بنجاح") |
|
|
|
with col2: |
|
if st.button("تصدير إلى Excel"): |
|
st.success("تم تصدير البيانات إلى Excel بنجاح") |
|
|