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.markdown("---") # --- القائمة الجانبية للمدخلات --- with st.sidebar: st.header("1. بيانات الترويسة") col_date, col_sem = st.columns(2) semester = col_sem.text_input("الفصل التدريبي", "الفصل الثاني 1446-1447") report_date = col_date.text_input("التاريخ", "2026/02/08") col_crn, col_code = st.columns(2) crn_number = col_crn.text_input("رقم الشعبة", "58471") course_name = col_code.text_input("اسم المقرر", "الجداول الإلكترونية (محسب)") col_inst, col_coll = st.columns(2) college_name = col_coll.text_input("الكلية", "الكلية التقنية بحائل") instructor_name = col_inst.text_input("المدرب", "محمد المحمدي") st.markdown("---") st.header("2. توزيع الدرجات (البنود)") st.info("أضف البنود التي تريد رصدها (مثلاً: عملي، نظري، واجبات)") # إعداد البنود ديناميكياً if 'items' not in st.session_state: st.session_state['items'] = [{"name": "أعمال فصلية", "max": 60}, {"name": "نهائي", "max": 40}] def add_item(): st.session_state['items'].append({"name": "بند جديد", "max": 10}) def remove_item(index): st.session_state['items'].pop(index) for i, item in enumerate(st.session_state['items']): c1, c2, c3 = st.columns([3, 2, 1]) item['name'] = c1.text_input(f"اسم البند {i+1}", item['name'], key=f"n{i}") item['max'] = c2.number_input(f"الدرجة {i+1}", 0, 100, item['max'], key=f"m{i}") if c3.button("❌", key=f"del{i}"): remove_item(i) st.rerun() if st.button("➕ إضافة بند جديد"): add_item() st.rerun() # --- المنطقة الرئيسية: رفع الملف والمعاينة --- st.header("3. رفع ملف رايات") uploaded_file = st.file_uploader("ارفع ملف Excel أو CSV المستخرج من رايات", type=['csv', 'xlsx']) if uploaded_file: try: # قراءة الملف (محاولة التعرف على الامتداد) if uploaded_file.name.endswith('.csv'): df = pd.read_csv(uploaded_file) else: df = pd.read_excel(uploaded_file) # تنظيف البيانات (محاولة إيجاد أعمدة الاسم والرقم) # ملاحظة: رايات عادة تكون أعمدته معقدة، هنا نبحث عن أي عمود فيه "اسم" أو "Name" ورقم "ID" # يمكنك تعديل هذه الجزئية حسب شكل ملف رايات الخام لديك بدقة # افتراضيات بسيطة للبحث عن الأعمدة name_col = None id_col = None for col in df.columns: if "اسم" in str(col) or "Name" in str(col): name_col = col if "رقم" in str(col) or "ID" in str(col) or "تدريبي" in str(col): id_col = col if name_col and id_col: # تجهيز الداتا فريم النهائية students = df[[id_col, name_col]].copy() students.columns = ['الرقم التدريبي', 'اسم المتدرب'] st.success(f"تم استخراج {len(students)} متدرب بنجاح.") # زر التحميل if st.button("💾 تحميل ملف كشف الدرجات (Excel)"): output = io.BytesIO() workbook = xlsxwriter.Workbook(output, {'in_memory': True}) worksheet = workbook.add_worksheet("كشف الدرجات") # --- تنسيقات الإكسل --- worksheet.right_to_left() # اتجاه الصفحة يمين يسار worksheet.set_paper(9) # A4 worksheet.set_landscape() # عرضي worksheet.fit_to_pages(1, 0) # ملاءمة العرض لصفحة واحدة worksheet.set_margins(left=0.5, right=0.5, top=0.5, bottom=0.5) # الأنماط (Styles) header_format = workbook.add_format({ 'bold': True, 'align': 'center', 'valign': 'vcenter', 'font_name': 'Arial', 'font_size': 14, 'color': '#1F4E79' }) # نمط العنوان الرئيسي للأعمدة (خلفية كحلي، نص أبيض) table_header_format = workbook.add_format({ 'bold': True, 'align': 'center', 'valign': 'vcenter', 'bg_color': '#1F4E79', 'font_color': 'white', 'border': 1, 'font_name': 'Arial', 'font_size': 10 }) # نمط الخلايا العادية (الأسماء والأرقام) cell_format = workbook.add_format({ 'align': 'center', 'valign': 'vcenter', 'border': 1, 'font_name': 'Arial', 'font_size': 10 }) # نمط خلايا الدرجات (إدخال يدوي) input_format = workbook.add_format({ 'align': 'center', 'valign': 'vcenter', 'border': 1, 'bg_color': '#FFFFFF', 'font_name': 'Arial', 'font_size': 10 }) # نمط المعادلات (رمادي فاتح) calc_format = workbook.add_format({ 'align': 'center', 'valign': 'vcenter', 'border': 1, 'bg_color': '#F2F2F2', 'bold': True, 'font_name': 'Arial', 'font_size': 10 }) # --- رسم الترويسة --- # الشعار والعنوان worksheet.merge_range('A1:L2', "كشف درجات الشعبة\nTVTC Grades Report", header_format) # بيانات الترويسة (صف 4 و 5) # تنسيق النصوص info_text_format = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'font_name': 'Arial', 'font_size': 11, 'color': '#1F4E79', 'bold': True}) info_val_format = workbook.add_format({'align': 'right', 'valign': 'vcenter', 'font_name': 'Arial', 'font_size': 11}) # السطر الأول من المعلومات worksheet.write_rich_string('K4', info_text_format, "المقرر: ", info_val_format, course_name) worksheet.write_rich_string('F4', info_text_format, "رقم الشعبة: ", info_val_format, crn_number) worksheet.write_rich_string('B4', info_text_format, "الفصل: ", info_val_format, semester) # السطر الثاني من المعلومات worksheet.write_rich_string('K5', info_text_format, "المدرب: ", info_val_format, instructor_name) worksheet.write_rich_string('F5', info_text_format, "الكلية: ", info_val_format, college_name) worksheet.write_rich_string('B5', info_text_format, "التاريخ: ", info_val_format, report_date) # رسم خط فاصل line_format = workbook.add_format({'bottom': 2, 'bottom_color': '#1F4E79'}) worksheet.write_blank('A6', None, line_format) for col in range(1, 12): worksheet.write_blank(5, col, None, line_format) # --- رسم جدول الدرجات --- start_row = 7 # الأعمدة الثابتة headers = ['#', 'الرقم التدريبي', 'اسم المتدرب'] # الأعمدة الديناميكية (البنود) grade_cols = [] for item in st.session_state['items']: headers.append(f"{item['name']}\n({item['max']})") grade_cols.append(item['max']) # أعمدة الحسابات headers.extend(['النهائي', 'المجموع', 'التقدير', 'الحالة']) # كتابة رؤوس الجدول for col_num, header in enumerate(headers): worksheet.write(start_row, col_num, header, table_header_format) # --- تعبئة البيانات والمعادلات --- for i, row in students.iterrows(): row_num = start_row + 1 + i xls_row = row_num + 1 # لأن الإكسل يبدأ من 1 # الرقم التسلسلي والاسم والرقم التدريبي worksheet.write(row_num, 0, i + 1, cell_format) worksheet.write(row_num, 1, row['الرقم التدريبي'], cell_format) worksheet.write(row_num, 2, row['اسم المتدرب'], cell_format) # أعمدة الدرجات (فارغة للكتابة اليدوية) col_idx = 3 first_grade_col_letter = xlsxwriter.utility.xl_col_to_name(3) last_grade_col_letter = xlsxwriter.utility.xl_col_to_name(3 + len(st.session_state['items']) - 1) for _ in st.session_state['items']: worksheet.write(row_num, col_idx, "", input_format) # خلية فارغة col_idx += 1 # عمود "النهائي" (إذا أردت فصله، حالياً سأعتبره من ضمن البنود أو أتركه فارغاً إذا لم يضاف) # بناء على الكود، النهائي مضاف كبند، لكن سأضيف عمود "النهائي" كحقل حسابي للمجموع # معادلة المجموع (SUM) # المجموع يجمع من أول عمود درجات لآخر عمود درجات sum_formula = f"=SUM({first_grade_col_letter}{xls_row}:{last_grade_col_letter}{xls_row})" worksheet.write_formula(row_num, col_idx, sum_formula, calc_format) # عمود المجموع الأول (النهائي في الصورة) # في الصورة يوجد "نهائي" و "مجموع". سأفترض المجموع هو الكلي # سأدمجهم ليكون المجموع الكلي هو آخر عمود رقمي total_cell = f"{xlsxwriter.utility.xl_col_to_name(col_idx)}{xls_row}" col_idx += 1 worksheet.write_formula(row_num, col_idx, f"={total_cell}", calc_format) # تكرار المجموع أو معالجة أخرى total_col_idx = col_idx col_idx += 1 # معادلة التقدير (Grade) باستخدام دالة IF المتداخلة (تعمل على كل نسخ إكسل) # التوزيع القياسي للمؤسسة grade_formula = ( f'=IF({total_cell}>=95,"A+",IF({total_cell}>=90,"A",' f'IF({total_cell}>=85,"B+",IF({total_cell}>=80,"B",' f'IF({total_cell}>=75,"C+",IF({total_cell}>=70,"C",' f'IF({total_cell}>=65,"D+",IF({total_cell}>=60,"D","F"))))))))' ) worksheet.write_formula(row_num, col_idx, grade_formula, calc_format) grade_cell = f"{xlsxwriter.utility.xl_col_to_name(col_idx)}{xls_row}" col_idx += 1 # معادلة الحالة (Status) status_formula = f'=IF({grade_cell}="F","راسب","ناجح")' worksheet.write_formula(row_num, col_idx, status_formula, calc_format) # --- تنسيق عرض الأعمدة --- worksheet.set_column(0, 0, 5) # # worksheet.set_column(1, 1, 15) # الرقم التدريبي worksheet.set_column(2, 2, 35) # اسم المتدرب # أعمدة الدرجات for i in range(len(st.session_state['items'])): worksheet.set_column(3+i, 3+i, 8) workbook.close() output.seek(0) st.download_button( label="📥 حمل الملف الآن", data=output, file_name="كشف_الدرجات_رايات.xlsx", mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" ) else: st.error("لم يتم العثور على أعمدة 'الاسم' و 'الرقم التدريبي' في الملف. الرجاء التأكد من صحة الملف.") st.write("الأعمدة الموجودة في ملفك:", df.columns.tolist()) except Exception as e: st.error(f"حدث خطأ أثناء قراءة الملف: {e}") else: st.info("الرجاء رفع الملف للبدء")