v3 / utils /helpers /utils.py
EGYADMIN's picture
Upload 115 files
82676b8 verified
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
وحدة المساعدات العامة
توفر هذه الوحدة مجموعة من الدوال المساعدة المستخدمة في مختلف أجزاء النظام
"""
import os
import datetime
import json
import re
import streamlit as st
def create_directory_if_not_exists(directory_path):
"""إنشاء مجلد إذا لم يكن موجوداً بالفعل"""
if not os.path.exists(directory_path):
os.makedirs(directory_path)
return True
return False
def get_data_folder():
"""الحصول على مسار مجلد البيانات"""
data_folder = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..', 'data'))
create_directory_if_not_exists(data_folder)
return data_folder
def format_time(timestamp=None):
"""تنسيق الوقت بصيغة قابلة للقراءة"""
if timestamp is None:
timestamp = datetime.datetime.now()
return timestamp.strftime("%Y-%m-%d %H:%M:%S")
def get_user_info():
"""الحصول على معلومات المستخدم الحالي"""
# في الوقت الحالي، نستخدم معلومات مستخدم افتراضية
# يمكن تعديل هذه الدالة لاحقاً للتكامل مع نظام المصادقة
return {
"id": 1,
"username": "admin",
"name": "مدير النظام",
"role": "admin"
}
def load_css():
"""تحميل أنماط CSS المخصصة"""
st.markdown("""
<style>
.module-title {
color: #1E88E5;
text-align: center;
margin-bottom: 20px;
font-weight: bold;
}
.section-title {
color: #1565C0;
margin-top: 20px;
margin-bottom: 10px;
font-weight: bold;
}
.info-box {
background-color: #E3F2FD;
padding: 15px;
border-radius: 5px;
margin-bottom: 15px;
}
.warning-box {
background-color: #FFF8E1;
padding: 15px;
border-radius: 5px;
margin-bottom: 15px;
}
.error-box {
background-color: #FFEBEE;
padding: 15px;
border-radius: 5px;
margin-bottom: 15px;
}
.success-box {
background-color: #E8F5E9;
padding: 15px;
border-radius: 5px;
margin-bottom: 15px;
}
.centered {
text-align: center;
}
.footer {
text-align: center;
margin-top: 30px;
color: #78909C;
font-size: 0.8em;
}
/* تحسين تصميم الجداول */
table {
width: 100%;
}
thead th {
background-color: #1976D2 !important;
color: white !important;
}
tbody tr:nth-child(even) {
background-color: #f2f2f2;
}
tbody tr:hover {
background-color: #E3F2FD;
}
/* تحسين ظهور الفورم */
input, select, textarea {
border-radius: 5px !important;
border: 1px solid #ddd !important;
padding: 10px !important;
}
.stButton>button {
border-radius: 5px !important;
}
/* زيادة حجم الخط للتوافق مع اللغة العربية */
html, body, [class*="css"] {
font-family: 'Tajawal', sans-serif;
}
</style>
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700&display=swap">
""", unsafe_allow_html=True)
def render_credits():
"""عرض المعلومات عن حقوق الملكية وإصدار النظام"""
st.markdown("""
<div class="footer">
<p>هذا النظام يعمل لصالح شركة شبه الجزيرة للمقاولات، جميع الحقوق محفوظة 2025</p>
<p>نظام WAHBi AI - الإصدار 2.0</p>
</div>
""", unsafe_allow_html=True)
def load_icons():
"""تحميل الأيقونات المستخدمة في النظام"""
icons = {
"project": "🏗️",
"document": "📄",
"analysis": "🔍",
"warning": "⚠️",
"success": "✅",
"error": "❌",
"info": "ℹ️",
"settings": "⚙️",
"user": "👤",
"money": "💰",
"time": "⏱️",
"location": "📍",
"notification": "🔔",
"edit": "✏️",
"delete": "🗑️",
"upload": "📤",
"download": "📥",
"save": "💾",
"cancel": "❌",
"add": "➕",
"calendar": "📅",
"chat": "💬",
"search": "🔎",
"star": "⭐",
"trophy": "🏆",
"medal": "🥇",
"chart": "📊",
"map": "🗺️",
"building": "🏢",
"road": "🛣️",
"bridge": "🌉",
}
return icons
def format_number(number, decimal_places=2):
"""تنسيق الأرقام بطريقة أنيقة"""
if isinstance(number, (int, float)):
if decimal_places == 0:
return "{:,.0f}".format(number)
else:
return "{:,.{dp}f}".format(number, dp=decimal_places)
return str(number)
def format_currency(amount, currency="ريال", decimal_places=2):
"""تنسيق المبالغ المالية"""
if amount is None:
return "غير محدد"
formatted = format_number(amount, decimal_places)
return f"{formatted} {currency}"
def styled_button(label, key=None, type="primary", on_click=None, args=None, full_width=False, icon=None, is_link=False, help=None):
"""
إنشاء زر بتنسيق معين
:param label: نص الزر
:param key: مفتاح الزر الفريد
:param type: نوع التنسيق ('primary', 'secondary', 'success', 'warning', 'danger', 'info', 'glass', 'flat')
:param on_click: الدالة التي سيتم تنفيذها عند النقر
:param args: معاملات الدالة
:param full_width: هل يأخذ الزر العرض كاملاً
:param icon: أيقونة لعرضها قبل النص (emoji أو HTML)
:param is_link: إذا كان الزر رابطاً بدلاً من زر عادي
:param help: نص المساعدة للزر
:return: زر مُنسّق
"""
if is_link:
btn_class = f"{type}-btn"
if icon:
btn_class += " action-btn"
label_with_icon = f"{icon} {label}"
else:
label_with_icon = label
button_html = f"""
<div class="{btn_class}">
{label_with_icon}
</div>
"""
return st.markdown(button_html, unsafe_allow_html=True)
else:
with st.container():
btn_class = f"{type}-btn"
if icon:
btn_class += " action-btn"
label_with_icon = f"{icon} {label}"
else:
label_with_icon = label
st.markdown(f'<div class="{btn_class}">', unsafe_allow_html=True)
clicked = st.button(label_with_icon, key=key, on_click=on_click, args=args, use_container_width=full_width, help=help)
st.markdown('</div>', unsafe_allow_html=True)
return clicked
def filter_dataframe(df, column, value):
"""ترشيح إطار البيانات"""
if value == "الكل":
return df
return df[df[column] == value]
def get_file_extension(filename):
"""استخراج امتداد الملف"""
if not filename:
return ""
return os.path.splitext(filename)[-1].lower()
def extract_numbers_from_text(text):
"""استخراج الأرقام من النص
Args:
text (str): النص المراد استخراج الأرقام منه
Returns:
list: قائمة بالأرقام المستخرجة
"""
if not text:
return []
# نمط للعثور على الأرقام (صحيحة أو عشرية) في النص
pattern = r'[-+]?\d*\.\d+|\d+'
# استخراج جميع الأرقام من النص
numbers = re.findall(pattern, text)
# تحويل النصوص المستخرجة إلى أرقام (صحيحة أو عشرية)
converted_numbers = []
for num in numbers:
if '.' in num:
converted_numbers.append(float(num))
else:
converted_numbers.append(int(num))
return converted_numbers