import streamlit as st
import pandas as pd
import io
import xlsxwriter
# --- إعدادات الصفحة ---
st.set_page_config(page_title="رايات إلى إكسل - رقيم", layout="wide")
st.markdown("""
""", unsafe_allow_html=True)
st.title("📊 محول كشوف درجات رايات (نسخة رقيم)")
st.caption("برمجة خاصة لـ: أبو سعد")
st.divider()
# --- القائمة الجانبية: إعدادات الكشف ---
with st.sidebar:
st.header("⚙️ إعدادات الترويسة والبنود")
with st.expander("1. بيانات الترويسة", expanded=True):
semester = st.text_input("الفصل التدريبي", "الفصل الثاني 1446-1447")
report_date = st.text_input("التاريخ", "1446/08/20")
crn_number = st.text_input("رقم الشعبة", "58472")
course_name = st.text_input("اسم المقرر", "الجداول الإلكترونية")
college_name = st.text_input("الكلية", "الكلية التقنية بحائل")
instructor_name = st.text_input("المدرب", "أبو سعد")
with st.expander("2. توزيع الدرجات (البنود)", expanded=True):
st.info("أضف الأعمدة التي ستدخل درجاتها يدوياً (مثلاً: عملي، نظري)")
# إدارة البنود
if 'items' not in st.session_state:
st.session_state['items'] = [{"name": "أعمال السنة", "max": 60}, {"name": "الاختبار النهائي", "max": 40}]
# عرض البنود الحالية للحذف أو التعديل
items_to_remove = []
for i, item in enumerate(st.session_state['items']):
c1, c2, c3 = st.columns([3, 1.5, 0.5])
with c1:
item['name'] = st.text_input(f"اسم البند {i+1}", item['name'], key=f"n_{i}")
with c2:
item['max'] = st.number_input(f"من كم؟", 0, 100, item['max'], key=f"m_{i}")
with c3:
st.write("") # مسافة
st.write("")
if st.button("❌", key=f"del_{i}"):
items_to_remove.append(i)
# حذف العناصر المطلوبة
if items_to_remove:
for i in sorted(items_to_remove, reverse=True):
del st.session_state['items'][i]
st.rerun()
if st.button("➕ إضافة بند جديد"):
st.session_state['items'].append({"name": "جديد", "max": 10})
st.rerun()
# --- المنطقة الرئيسية: رفع ومعالجة الملف ---
st.header("📥 استيراد ملف رايات")
uploaded_file = st.file_uploader("ارفع ملف CSV أو Excel من رايات", type=['csv', 'xlsx'])
if uploaded_file:
try:
# قراءة الملف بناء على نوعه
if uploaded_file.name.endswith('.csv'):
# ملفات رايات CSV أحياناً تكون مفصولة بفاصلة وتدعم العربية
try:
df = pd.read_csv(uploaded_file)
except:
df = pd.read_csv(uploaded_file, encoding='utf-16', sep='\t') # محاولة ترميز آخر
else:
df = pd.read_excel(uploaded_file)
# --- تنظيف البيانات (حسب ملفك المرسل) ---
# البحث عن الأعمدة المطلوبة
req_cols = {
'first_name': ['الاسم الأول', 'First Name'],
'last_name': ['الاسم الأخير', 'Last Name'],
'user_id': ['اسم المستخدم', 'Username', 'رقم المتدرب'] # في ملفك الرقم هو اسم المستخدم
}
found_cols = {}
for key, candidates in req_cols.items():
for col in df.columns:
if col in candidates:
found_cols[key] = col
break
if len(found_cols) == 3:
# دمج الاسم
df['Full_Name'] = df[found_cols['first_name']].astype(str) + " " + df[found_cols['last_name']].astype(str)
# تجهيز الجدول النهائي
final_df = pd.DataFrame({
'الرقم التدريبي': df[found_cols['user_id']],
'اسم المتدرب': df['Full_Name']
})
st.success(f"تم استخراج بيانات {len(final_df)} متدرب/ة بنجاح.")
st.dataframe(final_df.head(), use_container_width=True)
# --- إنشاء ملف الإكسل (Engine) ---
output = io.BytesIO()
workbook = xlsxwriter.Workbook(output, {'in_memory': True})
worksheet = workbook.add_worksheet("كشف الدرجات")
# التنسيقات (Formats)
fmt_header = workbook.add_format({'bold': True, 'align': 'center', 'valign': 'vcenter', 'font_name': 'Arial', 'font_size': 16, 'color': '#1F4E79'})
fmt_th = workbook.add_format({'bold': True, 'align': 'center', 'valign': 'vcenter', 'bg_color': '#1F4E79', 'font_color': 'white', 'border': 1, 'font_name': 'Arial', 'font_size': 11})
fmt_cell = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 1, 'font_name': 'Arial', 'font_size': 11})
fmt_input = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 1, 'bg_color': '#FFFFFF', 'font_name': 'Arial', 'font_size': 11})
fmt_calc = workbook.add_format({'align': 'center', 'valign': 'vcenter', 'border': 1, 'bg_color': '#E7E6E6', 'bold': True, 'font_name': 'Arial', 'font_size': 11})
fmt_label = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'bold': True, 'font_name': 'Arial', 'font_size': 11, 'color': '#1F4E79'})
fmt_val = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'font_name': 'Arial', 'font_size': 11})
fmt_line = workbook.add_format({'bottom': 2, 'bottom_color': '#1F4E79'})
# إعدادات الصفحة
worksheet.right_to_left()
worksheet.set_landscape()
worksheet.set_paper(9) # A4
worksheet.set_margins(0.5, 0.5, 0.5, 0.5)
worksheet.fit_to_pages(1, 0)
# 1. رسم الترويسة
worksheet.merge_range('A1:L2', "كشف درجات المتدربين (رصد)", fmt_header)
# بيانات الترويسة
# الصف 4
worksheet.write_rich_string('K4', fmt_label, "المقرر: ", fmt_val, course_name, fmt_val)
worksheet.write_rich_string('F4', fmt_label, "الشعبة: ", fmt_val, crn_number, fmt_val)
worksheet.write_rich_string('B4', fmt_label, "الفصل: ", fmt_val, semester, fmt_val)
# الصف 5
worksheet.write_rich_string('K5', fmt_label, "المدرب: ", fmt_val, instructor_name, fmt_val)
worksheet.write_rich_string('F5', fmt_label, "الكلية: ", fmt_val, college_name, fmt_val)
worksheet.write_rich_string('B5', fmt_label, "التاريخ: ", fmt_val, report_date, fmt_val)
# خط فاصل
for c in range(12): worksheet.write_blank(5, c, None, fmt_line)
# 2. رسم الجدول
start_row = 7
cols = ['#', 'الرقم التدريبي', 'اسم المتدرب']
# إضافة أعمدة البنود
for item in st.session_state['items']:
cols.append(f"{item['name']}\n({item['max']})")
# أعمدة الحسابات
cols.extend(['المجموع', 'التقدير', 'الحالة'])
# كتابة رؤوس الأعمدة
for i, col_name in enumerate(cols):
worksheet.write(start_row, i, col_name, fmt_th)
# 3. تعبئة البيانات والمعادلات
for i, row in final_df.iterrows():
r = start_row + 1 + i
xls_r = r + 1 # رقم الصف في الإكسل
worksheet.write(r, 0, i+1, fmt_cell)
worksheet.write(r, 1, row['الرقم التدريبي'], fmt_cell)
worksheet.write(r, 2, row['اسم المتدرب'], fmt_cell)
# الخلايا الفارغة للدرجات
col_idx = 3
first_grade_col = xlsxwriter.utility.xl_col_to_name(3)
last_grade_col = xlsxwriter.utility.xl_col_to_name(3 + len(st.session_state['items']) - 1)
for _ in st.session_state['items']:
worksheet.write(r, col_idx, "", fmt_input)
col_idx += 1
# المعادلات
# المجموع
sum_cell = f"=SUM({first_grade_col}{xls_r}:{last_grade_col}{xls_r})"
worksheet.write_formula(r, col_idx, sum_cell, fmt_calc)
total_cell_ref = f"{xlsxwriter.utility.xl_col_to_name(col_idx)}{xls_r}"
col_idx += 1
# التقدير (TVTC Standard)
grade_formula = (
f'=IF({total_cell_ref}>=95,"A+",IF({total_cell_ref}>=90,"A",'
f'IF({total_cell_ref}>=85,"B+",IF({total_cell_ref}>=80,"B",'
f'IF({total_cell_ref}>=75,"C+",IF({total_cell_ref}>=70,"C",'
f'IF({total_cell_ref}>=60,"D+",IF({total_cell_ref}>=60,"D","F"))))))))' # تصحيح D
)
worksheet.write_formula(r, col_idx, grade_formula, fmt_calc)
grade_cell_ref = f"{xlsxwriter.utility.xl_col_to_name(col_idx)}{xls_r}"
col_idx += 1
# الحالة
status_formula = f'=IF({grade_cell_ref}="F","راسب","ناجح")'
worksheet.write_formula(r, col_idx, status_formula, fmt_calc)
# تنسيق عرض الأعمدة
worksheet.set_column(0, 0, 5) # م
worksheet.set_column(1, 1, 13) # الرقم
worksheet.set_column(2, 2, 35) # الاسم
for j in range(len(st.session_state['items'])):
worksheet.set_column(3+j, 3+j, 10) # أعمدة الدرجات
workbook.close()
output.seek(0)
# زر التحميل النهائي
st.success("✅ تم تجهيز الملف!")
st.download_button(
label="📥 تحميل ملف رصد الدرجات (Excel)",
data=output,
file_name=f"كشف_{course_name}_{crn_number}.xlsx",
mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
)
else:
st.error("لم يتم العثور على الأعمدة المطلوبة. تأكد أن الملف يحتوي على: (الاسم الأول، الاسم الأخير، اسم المستخدم).")
st.write("الأعمدة الموجودة:", df.columns.tolist())
except Exception as e:
st.error(f"حدث خطأ: {e}")