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}")