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("الرجاء رفع الملف للبدء")