EGYADMIN commited on
Commit
6370e34
·
verified ·
1 Parent(s): d4f2ca0

Update modules/resources/resources_app.py

Browse files
Files changed (1) hide show
  1. modules/resources/resources_app.py +27 -1362
modules/resources/resources_app.py CHANGED
@@ -43,52 +43,42 @@ class ResourcesApp:
43
  "عماد أيمن", "أيمن رامي", "رامي سمير", "سمير وائل", "وائل مازن"
44
  ]
45
  employee_departments = np.random.choice(["الهندسة", "المشتريات", "المالية", "الموارد البشرية", "تقنية المعلومات", "التسويق", "المبيعات"], n_employees)
46
- employee_positions = np.random.choice(["مدير", "مهندس", "محاسب", "مشرف", "أخصائي", "مساعد", "فني"], n_employees)
47
- employee_skills = [
48
- np.random.choice(["إدارة المشاريع", "التصميم الهندسي", "تحليل البيانات", "إدارة العقود", "التخطيط الاستراتيجي"],
49
- size=np.random.randint(1, 4),
50
- replace=False).tolist()
51
- for _ in range(n_employees)
52
- ]
53
  employee_experiences = np.random.randint(1, 20, n_employees)
54
- employee_costs = np.random.randint(5000, 25000, n_employees)
55
- employee_availabilities = np.random.choice([True, False], n_employees, p=[0.8, 0.2])
56
- employee_ratings = np.random.uniform(3.0, 5.0, n_employees)
57
 
58
  # إنشاء DataFrame للموظفين
59
  employees_data = {
60
  "رقم الموظف": employee_ids,
61
- "اسم الموظف": employee_names,
62
  "القسم": employee_departments,
63
  "المنصب": employee_positions,
64
- "المهارات": employee_skills,
65
  "سنوات الخبرة": employee_experiences,
66
- "التكلفة الشهرية": employee_costs,
67
- "متاح": employee_availabilities,
68
- "التقييم": employee_ratings
69
  }
70
 
71
  # إنشاء بيانات المعدات
72
  n_equipment = 30
73
- equipment_ids = [f"EQ-{i+1:03d}" for i in range(n_equipment)]
74
  equipment_names = [
75
- "حفارة كبيرة", "حفارة صغيرة", "جرافة", "شاحنة نقل", "رافعة كبيرة",
76
- "رافعة متوسطة", "رافعة صغيرة", "خلاطة خرسانة", "مضخة خرسانة", "مولد كهرباء كبير",
77
- "مولد كهرباء متوسط", "مولد كهرباء صغير", "ضاغط هواء", "آلة لحام", "معدات قياس",
78
- "معدات اختبار", "سقالات", "قوالب خرسانية", "معدات سباكة", "معدات كهربائية",
79
- "معدات تكييف", "معدات تدفئة", "معدات إضاءة", "معدات سلامة", "معدات إطفاء",
80
- "سيارة نقل صغيرة", "سيارة نقل متوسطة", "سيارة نقل كبيرة", "معدات حفر يدوية", "معدات بناء يدوية"
81
  ]
82
- equipment_types = np.random.choice(["حفر", "نقل", "رفع", "خرسانة", "كهرباء", "قياس", "بناء", "سلامة"], n_equipment)
83
  equipment_costs = np.random.randint(500, 5000, n_equipment)
84
- equipment_availabilities = np.random.choice([True, False], n_equipment, p=[0.7, 0.3])
85
  equipment_conditions = np.random.choice(["��متاز", "جيد", "متوسط", "سيء"], n_equipment, p=[0.4, 0.3, 0.2, 0.1])
86
- equipment_locations = np.random.choice(["المستودع", "موقع المشروع 1", "موقع المشروع 2", "موقع المشروع 3", "في الصيانة"], n_equipment)
87
 
88
  # إنشاء DataFrame للمعدات
89
  equipment_data = {
90
  "رقم المعدة": equipment_ids,
91
- "اسم المعدة": equipment_names,
92
  "النوع": equipment_types,
93
  "التكلفة اليومية": equipment_costs,
94
  "متاحة": equipment_availabilities,
@@ -202,6 +192,16 @@ class ResourcesApp:
202
  "allocations": pd.DataFrame(allocations_data)
203
  }
204
 
 
 
 
 
 
 
 
 
 
 
205
  def render(self):
206
  """عرض واجهة وحدة الموارد"""
207
 
@@ -368,1339 +368,4 @@ class ResourcesApp:
368
  )
369
 
370
  fig = px.bar(
371
- project_allocations,
372
- x="اسم المشروع",
373
- y="عدد الموارد المخصصة",
374
- title="تخصيص الموارد للمشاريع",
375
- color="الحالة",
376
- text_auto=True,
377
- color_discrete_map={
378
- "قيد التنفيذ": "#3498db",
379
- "مكتمل": "#2ecc71",
380
- "متوقف": "#e74c3c",
381
- "مخطط": "#f39c12"
382
- }
383
- )
384
-
385
- st.plotly_chart(fig, use_container_width=True)
386
-
387
- # عرض توزيع أنواع الموارد المخصصة
388
- st.markdown("#### توزيع أنواع الموارد المخصصة")
389
-
390
- resource_type_counts = allocations_df["نوع المورد"].value_counts().reset_index()
391
- resource_type_counts.columns = ["نوع المورد", "العدد"]
392
-
393
- fig = px.pie(
394
- resource_type_counts,
395
- values="العدد",
396
- names="نوع المورد",
397
- title="توزيع أنواع الموارد المخصصة",
398
- color="نوع المورد",
399
- color_discrete_map={
400
- "موظف": "#3498db",
401
- "معدة": "#2ecc71",
402
- "مادة": "#f39c12"
403
- }
404
- )
405
-
406
- st.plotly_chart(fig, use_container_width=True)
407
-
408
- def _render_human_resources_tab(self):
409
- """عرض تبويب الموارد البشرية"""
410
-
411
- st.markdown("### إدارة الموارد البشرية")
412
-
413
- # استخراج البيانات
414
- employees_df = st.session_state.resources_data["employees"]
415
-
416
- # عرض خيارات التصفية
417
- st.markdown("#### خيارات التصفية")
418
-
419
- col1, col2, col3 = st.columns(3)
420
-
421
- with col1:
422
- selected_departments = st.multiselect(
423
- "القسم",
424
- options=employees_df["القسم"].unique(),
425
- default=employees_df["القسم"].unique()
426
- )
427
-
428
- with col2:
429
- selected_positions = st.multiselect(
430
- "المنصب",
431
- options=employees_df["المنصب"].unique(),
432
- default=employees_df["المنصب"].unique()
433
- )
434
-
435
- with col3:
436
- availability_filter = st.selectbox(
437
- "الإتاحة",
438
- options=["الكل", "متاح فقط", "غير متاح فقط"]
439
- )
440
-
441
- # تطبيق التصفية
442
- filtered_df = employees_df[
443
- employees_df["القسم"].isin(selected_departments) &
444
- employees_df["المنصب"].isin(selected_positions)
445
- ]
446
-
447
- if availability_filter == "متاح فقط":
448
- filtered_df = filtered_df[filtered_df["متاح"] == True]
449
- elif availability_filter == "غير متاح فقط":
450
- filtered_df = filtered_df[filtered_df["متاح"] == False]
451
-
452
- # عرض البيانات المصفاة
453
- st.markdown("#### قائمة الموظفين")
454
-
455
- st.dataframe(
456
- filtered_df,
457
- column_config={
458
- "رقم الموظف": st.column_config.TextColumn("رقم الموظف"),
459
- "اسم الموظف": st.column_config.TextColumn("اسم الموظف"),
460
- "القسم": st.column_config.TextColumn("القسم"),
461
- "المنصب": st.column_config.TextColumn("المنصب"),
462
- "المهارات": st.column_config.ListColumn("المهارات"),
463
- "سنوات الخبرة": st.column_config.NumberColumn("سنوات الخبرة"),
464
- "التكلفة الشهرية": st.column_config.NumberColumn("التكلفة الشهرية", format="%.2f ريال"),
465
- "متاح": st.column_config.CheckboxColumn("متاح"),
466
- "التقييم": st.column_config.ProgressColumn("التقييم", min_value=0, max_value=5)
467
- },
468
- use_container_width=True,
469
- hide_index=True
470
- )
471
-
472
- # عرض إحصائيات الموارد البشرية
473
- st.markdown("#### إحصائيات الموارد البشرية")
474
-
475
- col1, col2, col3, col4 = st.columns(4)
476
-
477
- with col1:
478
- total_employees = len(filtered_df)
479
- st.metric("إجمالي الموظفين", f"{total_employees}")
480
-
481
- with col2:
482
- available_employees = len(filtered_df[filtered_df["متاح"] == True])
483
- availability_rate = available_employees / total_employees * 100 if total_employees > 0 else 0
484
- st.metric("معدل الإتاحة", f"{availability_rate:.1f}%")
485
-
486
- with col3:
487
- avg_experience = filtered_df["سنوات الخبرة"].mean()
488
- st.metric("متوسط سنوات الخبرة", f"{avg_experience:.1f} سنة")
489
-
490
- with col4:
491
- avg_cost = filtered_df["التكلفة الشهرية"].mean()
492
- st.metric("متوسط التكلفة الشهرية", f"{avg_cost:.0f} ريال")
493
-
494
- # عرض توزيع الموظفين حسب القسم
495
- st.markdown("#### توزيع الموظفين حسب القسم")
496
-
497
- dept_counts = filtered_df["القسم"].value_counts().reset_index()
498
- dept_counts.columns = ["القسم", "العدد"]
499
-
500
- fig = px.bar(
501
- dept_counts,
502
- x="القسم",
503
- y="العدد",
504
- title="توزيع الموظفين حسب القسم",
505
- color="القسم",
506
- text_auto=True
507
- )
508
-
509
- st.plotly_chart(fig, use_container_width=True)
510
-
511
- # عرض توزيع الموظفين حسب المنصب
512
- st.markdown("#### توزيع الموظفين حسب المنصب")
513
-
514
- position_counts = filtered_df["المنصب"].value_counts().reset_index()
515
- position_counts.columns = ["المنصب", "العدد"]
516
-
517
- fig = px.pie(
518
- position_counts,
519
- values="العدد",
520
- names="المنصب",
521
- title="توزيع الموظفين حسب المنصب",
522
- color="المنصب"
523
- )
524
-
525
- st.plotly_chart(fig, use_container_width=True)
526
-
527
- # عرض توزيع الموظفين حسب سنوات الخبرة
528
- st.markdown("#### توزيع الموظفين حسب سنوات الخبرة")
529
-
530
- # إنشاء فئات لسنوات الخبرة
531
- experience_bins = [0, 3, 5, 10, 15, 20]
532
- experience_labels = ["أقل من 3 سنوات", "3-5 سنوات", "6-10 سنوات", "11-15 سنة", "أكثر من 15 سنة"]
533
-
534
- filtered_df["فئة الخبرة"] = pd.cut(filtered_df["سنوات الخبرة"], bins=experience_bins, labels=experience_labels, right=False)
535
-
536
- experience_counts = filtered_df["فئة الخبرة"].value_counts().reset_index()
537
- experience_counts.columns = ["فئة الخبرة", "العدد"]
538
-
539
- fig = px.bar(
540
- experience_counts,
541
- x="فئة الخبرة",
542
- y="العدد",
543
- title="توزيع الموظفين حسب سنوات الخبرة",
544
- color="فئة الخبرة",
545
- text_auto=True
546
- )
547
-
548
- st.plotly_chart(fig, use_container_width=True)
549
-
550
- # عرض توزيع المهارات
551
- st.markdown("#### توزيع المهارات")
552
-
553
- # استخراج جميع المهارات
554
- all_skills = []
555
- for skills_list in filtered_df["المهارات"]:
556
- all_skills.extend(skills_list)
557
-
558
- skill_counts = pd.Series(all_skills).value_counts().reset_index()
559
- skill_counts.columns = ["المهارة", "العدد"]
560
-
561
- fig = px.bar(
562
- skill_counts,
563
- x="المهارة",
564
- y="العدد",
565
- title="توزيع المهارات",
566
- color="المهارة",
567
- text_auto=True
568
- )
569
-
570
- st.plotly_chart(fig, use_container_width=True)
571
-
572
- # عرض العلاقة بين سنوات الخبرة والتكلفة
573
- st.markdown("#### العلاقة بين سنوات الخبرة والتكلفة")
574
-
575
- fig = px.scatter(
576
- filtered_df,
577
- x="سنوات الخبرة",
578
- y="التكلفة الشهرية",
579
- color="القسم",
580
- size="التقييم",
581
- hover_name="اسم الموظف",
582
- hover_data=["المنصب", "متاح"],
583
- title="العلاقة بين سنوات الخبرة والتكلفة الشهرية"
584
- )
585
-
586
- st.plotly_chart(fig, use_container_width=True)
587
-
588
- # إضافة موظف جديد
589
- st.markdown("#### إضافة موظف جديد")
590
-
591
- with st.form("add_employee_form"):
592
- col1, col2 = st.columns(2)
593
-
594
- with col1:
595
- new_employee_name = st.text_input("اسم الموظف")
596
- new_employee_department = st.selectbox("القسم", options=employees_df["القسم"].unique())
597
- new_employee_position = st.selectbox("المنصب", options=employees_df["المنصب"].unique())
598
- new_employee_experience = st.number_input("سنوات الخبرة", min_value=0, max_value=40, value=5)
599
-
600
- with col2:
601
- new_employee_skills = st.multiselect(
602
- "المهارات",
603
- options=["إدارة المشاريع", "التصميم الهندسي", "تحليل البيانات", "إدارة العقود", "التخطيط الاستراتيجي", "إدارة الموارد", "إدارة المخاطر", "إدارة الجودة", "إدارة التكاليف", "إدارة الوقت"]
604
- )
605
- new_employee_cost = st.number_input("التكلفة الشهرية", min_value=3000, max_value=50000, value=10000)
606
- new_employee_available = st.checkbox("متاح", value=True)
607
- new_employee_rating = st.slider("التقييم", min_value=1.0, max_value=5.0, value=4.0, step=0.1)
608
-
609
- submit_button = st.form_submit_button("إضافة موظف")
610
-
611
- if submit_button:
612
- if new_employee_name:
613
- # إنشاء رقم موظف جديد
614
- new_employee_id = f"EMP-{len(employees_df) + 1:03d}"
615
-
616
- # إضافة الموظف الجديد
617
- new_employee = pd.DataFrame({
618
- "رقم الموظف": [new_employee_id],
619
- "اسم الموظف": [new_employee_name],
620
- "القسم": [new_employee_department],
621
- "المنصب": [new_employee_position],
622
- "المهارات": [new_employee_skills],
623
- "سنوات الخبرة": [new_employee_experience],
624
- "التكلفة الشهرية": [new_employee_cost],
625
- "متاح": [new_employee_available],
626
- "التقييم": [new_employee_rating]
627
- })
628
-
629
- # تحديث DataFrame الموظفين
630
- st.session_state.resources_data["employees"] = pd.concat([employees_df, new_employee], ignore_index=True)
631
-
632
- st.success(f"تم إضافة الموظف {new_employee_name} بنجاح!")
633
- st.rerun()
634
- else:
635
- st.error("يرجى إدخال اسم الموظف")
636
-
637
- def _render_equipment_tab(self):
638
- """عرض تبويب المعدات"""
639
-
640
- st.markdown("### إدارة المعدات")
641
-
642
- # استخراج البيانات
643
- equipment_df = st.session_state.resources_data["equipment"]
644
-
645
- # عرض خيارات التصفية
646
- st.markdown("#### خيارات التصفية")
647
-
648
- col1, col2, col3 = st.columns(3)
649
-
650
- with col1:
651
- selected_types = st.multiselect(
652
- "النوع",
653
- options=equipment_df["النوع"].unique(),
654
- default=equipment_df["النوع"].unique()
655
- )
656
-
657
- with col2:
658
- selected_conditions = st.multiselect(
659
- "الحالة",
660
- options=equipment_df["الحالة"].unique(),
661
- default=equipment_df["الحالة"].unique()
662
- )
663
-
664
- with col3:
665
- availability_filter = st.selectbox(
666
- "الإتاحة",
667
- options=["الكل", "متاحة فقط", "غير متاحة فقط"],
668
- key="equipment_availability"
669
- )
670
-
671
- # تطبيق التصفية
672
- filtered_df = equipment_df[
673
- equipment_df["النوع"].isin(selected_types) &
674
- equipment_df["الحالة"].isin(selected_conditions)
675
- ]
676
-
677
- if availability_filter == "متاحة فقط":
678
- filtered_df = filtered_df[filtered_df["متاحة"] == True]
679
- elif availability_filter == "غير متاحة فقط":
680
- filtered_df = filtered_df[filtered_df["متاحة"] == False]
681
-
682
- # عرض البيانات المصفاة
683
- st.markdown("#### قائمة المعدات")
684
-
685
- st.dataframe(
686
- filtered_df,
687
- column_config={
688
- "رقم المعدة": st.column_config.TextColumn("رقم المعدة"),
689
- "اسم المعدة": st.column_config.TextColumn("اسم المعدة"),
690
- "النوع": st.column_config.TextColumn("النوع"),
691
- "التكلفة اليومية": st.column_config.NumberColumn("التكلفة اليومية", format="%.2f ريال"),
692
- "متاحة": st.column_config.CheckboxColumn("متاحة"),
693
- "الحالة": st.column_config.TextColumn("الحالة"),
694
- "الموقع": st.column_config.TextColumn("الموقع")
695
- },
696
- use_container_width=True,
697
- hide_index=True
698
- )
699
-
700
- # عرض إحصائيات المعدات
701
- st.markdown("#### إحصائيات المعدات")
702
-
703
- col1, col2, col3, col4 = st.columns(4)
704
-
705
- with col1:
706
- total_equipment = len(filtered_df)
707
- st.metric("إجمالي المعدات", f"{total_equipment}")
708
-
709
- with col2:
710
- available_equipment = len(filtered_df[filtered_df["متاحة"] == True])
711
- availability_rate = available_equipment / total_equipment * 100 if total_equipment > 0 else 0
712
- st.metric("معدل الإتاحة", f"{availability_rate:.1f}%")
713
-
714
- with col3:
715
- good_condition = len(filtered_df[filtered_df["الحالة"].isin(["ممتاز", "جيد"])])
716
- good_condition_rate = good_condition / total_equipment * 100 if total_equipment > 0 else 0
717
- st.metric("معدل الحالة الجيدة", f"{good_condition_rate:.1f}%")
718
-
719
- with col4:
720
- avg_cost = filtered_df["التكلفة اليومية"].mean()
721
- st.metric("متوسط التكلفة اليومية", f"{avg_cost:.0f} ريال")
722
-
723
- # عرض توزيع المعدات حسب النوع
724
- st.markdown("#### توزيع المعدات حسب النوع")
725
-
726
- type_counts = filtered_df["النوع"].value_counts().reset_index()
727
- type_counts.columns = ["النوع", "العدد"]
728
-
729
- fig = px.bar(
730
- type_counts,
731
- x="النوع",
732
- y="العدد",
733
- title="توزيع المعدات حسب النوع",
734
- color="النوع",
735
- text_auto=True
736
- )
737
-
738
- st.plotly_chart(fig, use_container_width=True)
739
-
740
- # عرض توزيع المعدات حسب الحالة
741
- st.markdown("#### توزيع المعدات حسب الحالة")
742
-
743
- condition_counts = filtered_df["الحالة"].value_counts().reset_index()
744
- condition_counts.columns = ["الحالة", "العدد"]
745
-
746
- fig = px.pie(
747
- condition_counts,
748
- values="العدد",
749
- names="الحالة",
750
- title="توزيع المعدات حسب الحالة",
751
- color="الحالة",
752
- color_discrete_map={
753
- "ممتاز": "#2ecc71",
754
- "جيد": "#3498db",
755
- "متوسط": "#f39c12",
756
- "سيء": "#e74c3c"
757
- }
758
- )
759
-
760
- st.plotly_chart(fig, use_container_width=True)
761
-
762
- # عرض توزيع المعدات حسب الموقع
763
- st.markdown("#### توزيع المعدات حسب الموقع")
764
-
765
- location_counts = filtered_df["الموقع"].value_counts().reset_index()
766
- location_counts.columns = ["الموقع", "العدد"]
767
-
768
- fig = px.bar(
769
- location_counts,
770
- x="الموقع",
771
- y="العدد",
772
- title="توزيع المعدات حسب الموقع",
773
- color="الموقع",
774
- text_auto=True
775
- )
776
-
777
- st.plotly_chart(fig, use_container_width=True)
778
-
779
- # عرض العلاقة بين نوع المعدة والتكلفة
780
- st.markdown("#### العلاقة بين نوع المعدة والتكلفة")
781
-
782
- type_cost = filtered_df.groupby("النوع")["التكلفة اليومية"].mean().reset_index()
783
- type_cost.columns = ["النوع", "متوسط التكلفة اليومية"]
784
-
785
- fig = px.bar(
786
- type_cost,
787
- x="النوع",
788
- y="متوسط التكلفة اليومية",
789
- title="متوسط التكلفة اليومية حسب نوع المعدة",
790
- color="النوع",
791
- text_auto=".0f"
792
- )
793
-
794
- st.plotly_chart(fig, use_container_width=True)
795
-
796
- # إضافة معدة جديد��
797
- st.markdown("#### إضافة معدة جديدة")
798
-
799
- with st.form("add_equipment_form"):
800
- col1, col2 = st.columns(2)
801
-
802
- with col1:
803
- new_equipment_name = st.text_input("اسم المعدة")
804
- new_equipment_type = st.selectbox("النوع", options=equipment_df["النوع"].unique())
805
- new_equipment_cost = st.number_input("التكلفة اليومية", min_value=100, max_value=10000, value=1000)
806
-
807
- with col2:
808
- new_equipment_available = st.checkbox("متاحة", value=True)
809
- new_equipment_condition = st.selectbox("الحالة", options=["ممتاز", "جيد", "متوسط", "سيء"])
810
- new_equipment_location = st.selectbox("الموقع", options=equipment_df["الموقع"].unique())
811
-
812
- submit_button = st.form_submit_button("إضافة معدة")
813
-
814
- if submit_button:
815
- if new_equipment_name:
816
- # إنشاء رقم معدة جديد
817
- new_equipment_id = f"EQ-{len(equipment_df) + 1:03d}"
818
-
819
- # إضافة المعدة الجديدة
820
- new_equipment = pd.DataFrame({
821
- "رقم المعدة": [new_equipment_id],
822
- "اسم المعدة": [new_equipment_name],
823
- "النوع": [new_equipment_type],
824
- "التكلفة اليومية": [new_equipment_cost],
825
- "متاحة": [new_equipment_available],
826
- "الحالة": [new_equipment_condition],
827
- "الموقع": [new_equipment_location]
828
- })
829
-
830
- # تحديث DataFrame المعدات
831
- st.session_state.resources_data["equipment"] = pd.concat([equipment_df, new_equipment], ignore_index=True)
832
-
833
- st.success(f"تم إضافة المعدة {new_equipment_name} بنجاح!")
834
- st.rerun()
835
- else:
836
- st.error("يرجى إدخال اسم المعدة")
837
-
838
- def _render_materials_tab(self):
839
- """عرض تبويب المواد"""
840
-
841
- st.markdown("### إدارة المواد")
842
-
843
- # استخراج البيانات
844
- materials_df = st.session_state.resources_data["materials"]
845
-
846
- # عرض خيارات التصفية
847
- st.markdown("#### خيارات التصفية")
848
-
849
- col1, col2, col3 = st.columns(3)
850
-
851
- with col1:
852
- selected_units = st.multiselect(
853
- "الوحدة",
854
- options=materials_df["الوحدة"].unique(),
855
- default=materials_df["الوحدة"].unique()
856
- )
857
-
858
- with col2:
859
- selected_suppliers = st.multiselect(
860
- "المورد",
861
- options=materials_df["المورد"].unique(),
862
- default=materials_df["المورد"].unique()
863
- )
864
-
865
- with col3:
866
- stock_filter = st.selectbox(
867
- "المخزون",
868
- options=["الكل", "منخفض المخزون", "مخزون كافي"]
869
- )
870
-
871
- # تطبيق التصفية
872
- filtered_df = materials_df[
873
- materials_df["الوحدة"].isin(selected_units) &
874
- materials_df["المورد"].isin(selected_suppliers)
875
- ]
876
-
877
- if stock_filter == "منخفض المخزون":
878
- filtered_df = filtered_df[filtered_df["الكمية المتاحة"] < 50]
879
- elif stock_filter == "مخزون كافي":
880
- filtered_df = filtered_df[filtered_df["الكمية المتاحة"] >= 50]
881
-
882
- # عرض البيانات المصفاة
883
- st.markdown("#### قائمة المواد")
884
-
885
- st.dataframe(
886
- filtered_df,
887
- column_config={
888
- "رقم المادة": st.column_config.TextColumn("رقم المادة"),
889
- "اسم المادة": st.column_config.TextColumn("اسم المادة"),
890
- "الوحدة": st.column_config.TextColumn("الوحدة"),
891
- "الكمية المتاحة": st.column_config.NumberColumn("الكمية المتاحة"),
892
- "تكلفة الوحدة": st.column_config.NumberColumn("تكلفة الوحدة", format="%.2f ريال"),
893
- "المورد": st.column_config.TextColumn("المورد"),
894
- "مدة التوريد (يوم)": st.column_config.NumberColumn("مدة التوريد (يوم)")
895
- },
896
- use_container_width=True,
897
- hide_index=True
898
- )
899
-
900
- # عرض إحصائيات المواد
901
- st.markdown("#### إحصائيات المواد")
902
-
903
- col1, col2, col3, col4 = st.columns(4)
904
-
905
- with col1:
906
- total_materials = len(filtered_df)
907
- st.metric("إجمالي المواد", f"{total_materials}")
908
-
909
- with col2:
910
- low_stock_materials = len(filtered_df[filtered_df["الكمية المتاحة"] < 50])
911
- low_stock_rate = low_stock_materials / total_materials * 100 if total_materials > 0 else 0
912
- st.metric("نسبة المواد منخفضة المخزون", f"{low_stock_rate:.1f}%")
913
-
914
- with col3:
915
- avg_lead_time = filtered_df["مدة التوريد (يوم)"].mean()
916
- st.metric("متوسط مدة التوريد", f"{avg_lead_time:.1f} يوم")
917
-
918
- with col4:
919
- total_inventory_value = (filtered_df["الكمية المتاحة"] * filtered_df["تكلفة الوحدة"]).sum()
920
- st.metric("إجمالي قيمة المخزون", f"{total_inventory_value:,.0f} ريال")
921
-
922
- # عرض توزيع المواد حسب المورد
923
- st.markdown("#### توزيع المواد حسب المورد")
924
-
925
- supplier_counts = filtered_df["المورد"].value_counts().reset_index()
926
- supplier_counts.columns = ["المورد", "العدد"]
927
-
928
- fig = px.pie(
929
- supplier_counts,
930
- values="العدد",
931
- names="المورد",
932
- title="توزيع المواد حسب المورد",
933
- color="المورد"
934
- )
935
-
936
- st.plotly_chart(fig, use_container_width=True)
937
-
938
- # عرض توزيع المواد حسب الوحدة
939
- st.markdown("#### توزيع المواد حسب الوحدة")
940
-
941
- unit_counts = filtered_df["الوحدة"].value_counts().reset_index()
942
- unit_counts.columns = ["الوحدة", "العدد"]
943
-
944
- fig = px.bar(
945
- unit_counts,
946
- x="الوحدة",
947
- y="العدد",
948
- title="توزيع المواد حسب الوحدة",
949
- color="الوحدة",
950
- text_auto=True
951
- )
952
-
953
- st.plotly_chart(fig, use_container_width=True)
954
-
955
- # عرض المواد منخفضة المخزون
956
- st.markdown("#### المواد منخفضة المخزون")
957
-
958
- low_stock_df = filtered_df[filtered_df["الكمية المتاحة"] < 50].sort_values("الكمية المتاحة")
959
-
960
- if not low_stock_df.empty:
961
- fig = px.bar(
962
- low_stock_df,
963
- x="اسم المادة",
964
- y="الكمية المتاحة",
965
- title="المواد منخفضة المخزون",
966
- color="الكمية المتاحة",
967
- color_continuous_scale="Reds_r",
968
- text_auto=True
969
- )
970
-
971
- st.plotly_chart(fig, use_container_width=True)
972
- else:
973
- st.info("لا توجد مواد منخفضة المخزون")
974
-
975
- # عرض العلاقة بين مدة التوريد والمورد
976
- st.markdown("#### العلاقة بين مدة التوريد والمورد")
977
-
978
- supplier_lead_time = filtered_df.groupby("المورد")["مدة التوريد (يوم)"].mean().reset_index()
979
- supplier_lead_time.columns = ["المورد", "متوسط مدة التوريد (يوم)"]
980
-
981
- fig = px.bar(
982
- supplier_lead_time,
983
- x="المورد",
984
- y="متوسط مدة التوريد (يوم)",
985
- title="متوسط مدة التوريد حسب المورد",
986
- color="المورد",
987
- text_auto=".1f"
988
- )
989
-
990
- st.plotly_chart(fig, use_container_width=True)
991
-
992
- # إضافة مادة جديدة
993
- st.markdown("#### إضافة مادة جديدة")
994
-
995
- with st.form("add_material_form"):
996
- col1, col2 = st.columns(2)
997
-
998
- with col1:
999
- new_material_name = st.text_input("اسم المادة")
1000
- new_material_unit = st.selectbox("الوحدة", options=materials_df["الوحدة"].unique())
1001
- new_material_quantity = st.number_input("الكمية المتاحة", min_value=0, max_value=10000, value=100)
1002
-
1003
- with col2:
1004
- new_material_cost = st.number_input("تكلفة الوحدة", min_value=1, max_value=10000, value=100)
1005
- new_material_supplier = st.selectbox("المورد", options=materials_df["المورد"].unique())
1006
- new_material_lead_time = st.number_input("مدة التوريد (يوم)", min_value=1, max_value=90, value=7)
1007
-
1008
- submit_button = st.form_submit_button("إضافة مادة")
1009
-
1010
- if submit_button:
1011
- if new_material_name:
1012
- # إنشاء رقم مادة جديد
1013
- new_material_id = f"MAT-{len(materials_df) + 1:03d}"
1014
-
1015
- # إضافة المادة الجديدة
1016
- new_material = pd.DataFrame({
1017
- "رقم المادة": [new_material_id],
1018
- "اسم المادة": [new_material_name],
1019
- "الوحدة": [new_material_unit],
1020
- "الكمية المتاحة": [new_material_quantity],
1021
- "تكلفة الوحدة": [new_material_cost],
1022
- "المورد": [new_material_supplier],
1023
- "مدة التوريد (يوم)": [new_material_lead_time]
1024
- })
1025
-
1026
- # تحديث DataFrame المواد
1027
- st.session_state.resources_data["materials"] = pd.concat([materials_df, new_material], ignore_index=True)
1028
-
1029
- st.success(f"تم إضافة المادة {new_material_name} بنجاح!")
1030
- st.rerun()
1031
- else:
1032
- st.error("يرجى إدخال اسم المادة")
1033
-
1034
- # طلب مواد
1035
- st.markdown("#### طلب مواد")
1036
-
1037
- with st.form("order_materials_form"):
1038
- col1, col2, col3 = st.columns(3)
1039
-
1040
- with col1:
1041
- material_to_order = st.selectbox("المادة", options=materials_df["اسم المادة"].unique())
1042
-
1043
- with col2:
1044
- order_quantity = st.number_input("الكمية المطلوبة", min_value=1, max_value=1000, value=50)
1045
-
1046
- with col3:
1047
- order_date = st.date_input("تاريخ الطلب", value=datetime.now())
1048
-
1049
- submit_button = st.form_submit_button("طلب المادة")
1050
-
1051
- if submit_button:
1052
- # محاكاة طلب المادة
1053
- st.success(f"تم طلب {order_quantity} {materials_df[materials_df['اسم المادة'] == material_to_order]['الوحدة'].values[0]} من {material_to_order} بنجاح!")
1054
-
1055
- # عرض تفاصيل الطلب
1056
- material_info = materials_df[materials_df["اسم المادة"] == material_to_order].iloc[0]
1057
- lead_time = material_info["مدة التوريد (يوم)"]
1058
- expected_delivery = order_date + timedelta(days=lead_time)
1059
-
1060
- st.info(f"تاريخ التسليم المتوقع: {expected_delivery.strftime('%Y-%m-%d')}")
1061
-
1062
- # حساب التكلفة الإجمالية
1063
- unit_cost = material_info["تكلفة الوحدة"]
1064
- total_cost = unit_cost * order_quantity
1065
-
1066
- st.metric("التكلفة الإجمالية", f"{total_cost:,.2f} ريال")
1067
-
1068
- def _render_resource_allocation_tab(self):
1069
- """عرض تبويب تخصيص الموارد"""
1070
-
1071
- st.markdown("### تخصيص الموارد")
1072
-
1073
- # استخراج البيانات
1074
- employees_df = st.session_state.resources_data["employees"]
1075
- equipment_df = st.session_state.resources_data["equipment"]
1076
- materials_df = st.session_state.resources_data["materials"]
1077
- projects_df = st.session_state.resources_data["projects"]
1078
- allocations_df = st.session_state.resources_data["allocations"]
1079
-
1080
- # عرض خيارات التصفية
1081
- st.markdown("#### خيارات التصفية")
1082
-
1083
- col1, col2 = st.columns(2)
1084
-
1085
- with col1:
1086
- selected_projects = st.multiselect(
1087
- "المشروع",
1088
- options=projects_df["اسم المشروع"].unique(),
1089
- default=projects_df["اسم المشروع"].unique()
1090
- )
1091
-
1092
- with col2:
1093
- selected_resource_types = st.multiselect(
1094
- "نوع المورد",
1095
- options=allocations_df["نوع المورد"].unique(),
1096
- default=allocations_df["نوع المورد"].unique()
1097
- )
1098
-
1099
- # تحويل أسماء المشاريع إلى أرقام المشاريع
1100
- selected_project_ids = projects_df[projects_df["اسم المشروع"].isin(selected_projects)]["رقم المشروع"].tolist()
1101
-
1102
- # تطبيق التصفية
1103
- filtered_df = allocations_df[
1104
- allocations_df["رقم المشروع"].isin(selected_project_ids) &
1105
- allocations_df["نوع المورد"].isin(selected_resource_types)
1106
- ]
1107
-
1108
- # دمج البيانات مع بيانات المشاريع
1109
- merged_df = filtered_df.merge(
1110
- projects_df[["رقم المشروع", "اسم المشروع"]],
1111
- on="رقم المشروع",
1112
- how="left"
1113
- )
1114
-
1115
- # إضافة أسماء الموارد
1116
- merged_df["اسم المورد"] = ""
1117
-
1118
- for i, row in merged_df.iterrows():
1119
- if row["نوع المورد"] == "موظف":
1120
- resource_name = employees_df[employees_df["رقم الموظف"] == row["رقم المورد"]]["اسم الموظف"].values
1121
- if len(resource_name) > 0:
1122
- merged_df.at[i, "اسم المورد"] = resource_name[0]
1123
- elif row["نوع المورد"] == "معدة":
1124
- resource_name = equipment_df[equipment_df["رقم المعدة"] == row["رقم المورد"]]["اسم المعدة"].values
1125
- if len(resource_name) > 0:
1126
- merged_df.at[i, "اسم المورد"] = resource_name[0]
1127
- elif row["نوع المورد"] == "مادة":
1128
- resource_name = materials_df[materials_df["رقم المادة"] == row["رقم المورد"]]["اسم المادة"].values
1129
- if len(resource_name) > 0:
1130
- merged_df.at[i, "اسم المورد"] = resource_name[0]
1131
-
1132
- # عرض البيانات المصفاة
1133
- st.markdown("#### قائمة تخصيص الموارد")
1134
-
1135
- display_df = merged_df[["رقم التخصيص", "اسم المشروع", "نوع المورد", "اسم المورد", "تاريخ البدء", "تاريخ الانتهاء", "الكمية", "التكلفة"]]
1136
-
1137
- st.dataframe(
1138
- display_df,
1139
- column_config={
1140
- "رقم التخصيص": st.column_config.TextColumn("رقم التخصيص"),
1141
- "اسم المشروع": st.column_config.TextColumn("اسم المشروع"),
1142
- "نوع المورد": st.column_config.TextColumn("نوع المورد"),
1143
- "اسم المورد": st.column_config.TextColumn("اسم المورد"),
1144
- "تاريخ البدء": st.column_config.DateColumn("تاريخ البدء"),
1145
- "تاريخ الانتهاء": st.column_config.DateColumn("تاريخ الانتهاء"),
1146
- "الكمية": st.column_config.NumberColumn("الكمية"),
1147
- "التكلفة": st.column_config.NumberColumn("التكلفة", format="%.2f ريال")
1148
- },
1149
- use_container_width=True,
1150
- hide_index=True
1151
- )
1152
-
1153
- # عرض إحصائيات تخصيص الموارد
1154
- st.markdown("#### إحصائيات تخصيص الموارد")
1155
-
1156
- col1, col2, col3, col4 = st.columns(4)
1157
-
1158
- with col1:
1159
- total_allocations = len(merged_df)
1160
- st.metric("إجمالي التخصيصات", f"{total_allocations}")
1161
-
1162
- with col2:
1163
- total_cost = merged_df["التكلفة"].sum()
1164
- st.metric("إجمالي التكلفة", f"{total_cost:,.0f} ريال")
1165
-
1166
- with col3:
1167
- avg_duration = (pd.to_datetime(merged_df["تاريخ الانتهاء"]) - pd.to_datetime(merged_df["تاريخ البدء"])).mean().days
1168
- st.metric("متوسط مدة التخصيص", f"{avg_duration:.0f} يوم")
1169
-
1170
- with col4:
1171
- resource_types = merged_df["نوع المورد"].value_counts()
1172
- most_common_type = resource_types.index[0] if not resource_types.empty else ""
1173
- st.metric("أكثر أنواع الموارد تخصيصاً", f"{most_common_type}")
1174
-
1175
- # عرض توزيع تخصيص الموارد حسب المشروع
1176
- st.markdown("#### توزيع تخصيص الموارد حسب المشروع")
1177
-
1178
- project_allocations = merged_df.groupby("اسم المشروع").size().reset_index()
1179
- project_allocations.columns = ["اسم المشروع", "عدد التخصيصات"]
1180
-
1181
- fig = px.bar(
1182
- project_allocations,
1183
- x="اسم المشروع",
1184
- y="عدد التخصيصات",
1185
- title="توزيع تخصيص الموارد حسب المشروع",
1186
- color="اسم المشروع",
1187
- text_auto=True
1188
- )
1189
-
1190
- st.plotly_chart(fig, use_container_width=True)
1191
-
1192
- # عرض توزيع تخصيص الموارد حسب نوع المورد
1193
- st.markdown("#### توزيع تخصيص الموارد حسب نوع المورد")
1194
-
1195
- resource_type_allocations = merged_df.groupby("نوع المورد").size().reset_index()
1196
- resource_type_allocations.columns = ["نوع المورد", "عدد التخصيصات"]
1197
-
1198
- fig = px.pie(
1199
- resource_type_allocations,
1200
- values="عدد التخصيصات",
1201
- names="نوع المورد",
1202
- title="توزيع تخصيص الموارد حسب نوع المورد",
1203
- color="نوع المورد",
1204
- color_discrete_map={
1205
- "موظف": "#3498db",
1206
- "معدة": "#2ecc71",
1207
- "مادة": "#f39c12"
1208
- }
1209
- )
1210
-
1211
- st.plotly_chart(fig, use_container_width=True)
1212
-
1213
- # عرض توزيع تكاليف الم��ارد حسب المشروع
1214
- st.markdown("#### توزيع تكاليف الموارد حسب المشروع")
1215
-
1216
- project_costs = merged_df.groupby("اسم المشروع")["التكلفة"].sum().reset_index()
1217
- project_costs.columns = ["اسم المشروع", "إجمالي التكلفة"]
1218
-
1219
- fig = px.bar(
1220
- project_costs,
1221
- x="اسم المشروع",
1222
- y="إجمالي التكلفة",
1223
- title="توزيع تكاليف الموارد حسب المشروع",
1224
- color="اسم المشروع",
1225
- text_auto=".0f"
1226
- )
1227
-
1228
- st.plotly_chart(fig, use_container_width=True)
1229
-
1230
- # عرض توزيع تكاليف الموارد حسب نوع المورد
1231
- st.markdown("#### توزيع تكاليف الموارد حسب نوع المورد")
1232
-
1233
- resource_type_costs = merged_df.groupby("نوع المورد")["التكلفة"].sum().reset_index()
1234
- resource_type_costs.columns = ["نوع المورد", "إجمالي التكلفة"]
1235
-
1236
- fig = px.pie(
1237
- resource_type_costs,
1238
- values="إجمالي التكلفة",
1239
- names="نوع المورد",
1240
- title="توزيع تكاليف الموارد حسب نوع المورد",
1241
- color="نوع المورد",
1242
- color_discrete_map={
1243
- "موظف": "#3498db",
1244
- "معدة": "#2ecc71",
1245
- "مادة": "#f39c12"
1246
- }
1247
- )
1248
-
1249
- st.plotly_chart(fig, use_container_width=True)
1250
-
1251
- # إضافة تخصيص جديد
1252
- st.markdown("#### إضافة تخصيص جديد")
1253
-
1254
- with st.form("add_allocation_form"):
1255
- col1, col2 = st.columns(2)
1256
-
1257
- with col1:
1258
- new_allocation_project = st.selectbox("المشروع", options=projects_df["اسم المشروع"].unique())
1259
- new_allocation_resource_type = st.selectbox("نوع المورد", options=["موظف", "معدة", "مادة"])
1260
-
1261
- # تحديد خيارات الموارد بناءً على النوع
1262
- if new_allocation_resource_type == "موظف":
1263
- resource_options = employees_df[employees_df["متاح"] == True]["اسم الموظف"].unique()
1264
- elif new_allocation_resource_type == "معدة":
1265
- resource_options = equipment_df[equipment_df["متاحة"] == True]["اسم المعدة"].unique()
1266
- else:
1267
- resource_options = materials_df["اسم المادة"].unique()
1268
-
1269
- new_allocation_resource = st.selectbox("المورد", options=resource_options)
1270
-
1271
- with col2:
1272
- new_allocation_start_date = st.date_input("تاريخ البدء", value=datetime.now())
1273
- new_allocation_end_date = st.date_input("تاريخ الانتهاء", value=datetime.now() + timedelta(days=30))
1274
- new_allocation_quantity = st.number_input("الكمية", min_value=1, max_value=100, value=1)
1275
-
1276
- submit_button = st.form_submit_button("إضافة تخصيص")
1277
-
1278
- if submit_button:
1279
- # التحقق من صحة التواريخ
1280
- if new_allocation_end_date <= new_allocation_start_date:
1281
- st.error("يجب أن يكون تاريخ الانتهاء بعد تاريخ البدء")
1282
- else:
1283
- # الحصول على رقم المشروع
1284
- project_id = projects_df[projects_df["اسم المشروع"] == new_allocation_project]["رقم المشروع"].values[0]
1285
-
1286
- # الحصول على رقم المورد
1287
- if new_allocation_resource_type == "موظف":
1288
- resource_id = employees_df[employees_df["اسم الموظف"] == new_allocation_resource]["رقم الموظف"].values[0]
1289
- # حساب التكلفة
1290
- cost = employees_df[employees_df["رقم الموظف"] == resource_id]["التكلفة الشهرية"].values[0] * new_allocation_quantity
1291
- elif new_allocation_resource_type == "معدة":
1292
- resource_id = equipment_df[equipment_df["اسم المعدة"] == new_allocation_resource]["رقم المعدة"].values[0]
1293
- # حساب التكلفة
1294
- days = (new_allocation_end_date - new_allocation_start_date).days
1295
- cost = equipment_df[equipment_df["رقم المعدة"] == resource_id]["التكلفة اليومية"].values[0] * days * new_allocation_quantity
1296
- else:
1297
- resource_id = materials_df[materials_df["اسم المادة"] == new_allocation_resource]["رقم المادة"].values[0]
1298
- # حساب الت��لفة
1299
- cost = materials_df[materials_df["رقم المادة"] == resource_id]["تكلفة الوحدة"].values[0] * new_allocation_quantity
1300
-
1301
- # إنشاء رقم تخصيص جديد
1302
- new_allocation_id = f"ALLOC-{len(allocations_df) + 1:03d}"
1303
-
1304
- # إضافة التخصيص الجديد
1305
- new_allocation = pd.DataFrame({
1306
- "رقم التخصيص": [new_allocation_id],
1307
- "رقم المشروع": [project_id],
1308
- "نوع المورد": [new_allocation_resource_type],
1309
- "رقم المورد": [resource_id],
1310
- "تاريخ البدء": [new_allocation_start_date.strftime("%Y-%m-%d")],
1311
- "تاريخ الانتهاء": [new_allocation_end_date.strftime("%Y-%m-%d")],
1312
- "الكمية": [new_allocation_quantity],
1313
- "التكلفة": [cost]
1314
- })
1315
-
1316
- # تحديث DataFrame التخصيصات
1317
- st.session_state.resources_data["allocations"] = pd.concat([allocations_df, new_allocation], ignore_index=True)
1318
-
1319
- # تحديث حالة المورد إذا كان موظف أو معدة
1320
- if new_allocation_resource_type == "موظف":
1321
- employees_idx = employees_df[employees_df["رقم الموظف"] == resource_id].index
1322
- st.session_state.resources_data["employees"].at[employees_idx[0], "متاح"] = False
1323
- elif new_allocation_resource_type == "معدة":
1324
- equipment_idx = equipment_df[equipment_df["رقم المعدة"] == resource_id].index
1325
- st.session_state.resources_data["equipment"].at[equipment_idx[0], "متاحة"] = False
1326
- elif new_allocation_resource_type == "مادة":
1327
- materials_idx = materials_df[materials_df["رقم المادة"] == resource_id].index
1328
- current_quantity = st.session_state.resources_data["materials"].at[materials_idx[0], "الكمية المتاحة"]
1329
- st.session_state.resources_data["materials"].at[materials_idx[0], "الكمية المتاحة"] = max(0, current_quantity - new_allocation_quantity)
1330
-
1331
- st.success(f"تم إضافة تخصيص {new_allocation_resource_type} ({new_allocation_resource}) لمشروع {new_allocation_project} بنجاح!")
1332
- st.rerun()
1333
-
1334
- def _render_resource_planning_tab(self):
1335
- """عرض تبويب تخطيط الموارد"""
1336
-
1337
- st.markdown("### تخطيط الموارد")
1338
-
1339
- # استخراج البيانات
1340
- employees_df = st.session_state.resources_data["employees"]
1341
- equipment_df = st.session_state.resources_data["equipment"]
1342
- materials_df = st.session_state.resources_data["materials"]
1343
- projects_df = st.session_state.resources_data["projects"]
1344
- allocations_df = st.session_state.resources_data["allocations"]
1345
-
1346
- # عرض المشاريع القادمة
1347
- st.markdown("#### المشاريع القادمة")
1348
-
1349
- upcoming_projects = projects_df[projects_df["الحالة"] == "مخطط"].sort_values("تاريخ البدء")
1350
-
1351
- if not upcoming_projects.empty:
1352
- st.dataframe(
1353
- upcoming_projects,
1354
- column_config={
1355
- "رقم المشروع": st.column_config.TextColumn("رقم المشروع"),
1356
- "اسم المشروع": st.column_config.TextColumn("اسم المشروع"),
1357
- "الموقع": st.column_config.TextColumn("الموقع"),
1358
- "تاريخ البدء": st.column_config.DateColumn("تاريخ البدء"),
1359
- "تاريخ الانتهاء": st.column_config.DateColumn("تاريخ الانتهاء"),
1360
- "الميزانية": st.column_config.NumberColumn("الميزانية", format="%.2f ريال"),
1361
- "الحالة": st.column_config.TextColumn("الحالة")
1362
- },
1363
- use_container_width=True,
1364
- hide_index=True
1365
- )
1366
- else:
1367
- st.info("لا توجد مشاريع قادمة")
1368
-
1369
- # عرض توافر الموارد
1370
- st.markdown("#### توافر الموارد")
1371
-
1372
- col1, col2, col3 = st.columns(3)
1373
-
1374
- with col1:
1375
- total_employees = len(employees_df)
1376
- available_employees = len(employees_df[employees_df["متاح"] == True])
1377
- availability_rate = available_employees / total_employees * 100 if total_employees > 0 else 0
1378
-
1379
- st.metric("الموظفون المتاحون", f"{available_employees}/{total_employees}", f"{availability_rate:.1f}%")
1380
-
1381
- # عرض توزيع توافر الموظفين
1382
- availability_data = pd.DataFrame({
1383
- "الحالة": ["متاح", "غير متاح"],
1384
- "العدد": [available_employees, total_employees - available_employees]
1385
- })
1386
-
1387
- fig = px.pie(
1388
- availability_data,
1389
- values="العدد",
1390
- names="الحالة",
1391
- title="توافر الموظفين",
1392
- color="الحالة",
1393
- color_discrete_map={
1394
- "متاح": "#2ecc71",
1395
- "غير متاح": "#e74c3c"
1396
- }
1397
- )
1398
-
1399
- st.plotly_chart(fig, use_container_width=True)
1400
-
1401
- with col2:
1402
- total_equipment = len(equipment_df)
1403
- available_equipment = len(equipment_df[equipment_df["متاحة"] == True])
1404
- availability_rate = available_equipment / total_equipment * 100 if total_equipment > 0 else 0
1405
-
1406
- st.metric("المعدات المتاحة", f"{available_equipment}/{total_equipment}", f"{availability_rate:.1f}%")
1407
-
1408
- # عرض توزيع توافر المعدات
1409
- availability_data = pd.DataFrame({
1410
- "الحالة": ["متاحة", "غير متاحة"],
1411
- "العدد": [available_equipment, total_equipment - available_equipment]
1412
- })
1413
-
1414
- fig = px.pie(
1415
- availability_data,
1416
- values="العدد",
1417
- names="الحالة",
1418
- title="توافر المعدات",
1419
- color="الحالة",
1420
- color_discrete_map={
1421
- "متاحة": "#2ecc71",
1422
- "غير متاحة": "#e74c3c"
1423
- }
1424
- )
1425
-
1426
- st.plotly_chart(fig, use_container_width=True)
1427
-
1428
- with col3:
1429
- total_materials = len(materials_df)
1430
- low_stock_materials = len(materials_df[materials_df["الكمية المتاحة"] < 50])
1431
- low_stock_rate = low_stock_materials / total_materials * 100 if total_materials > 0 else 0
1432
-
1433
- st.metric("المواد منخفضة المخزون", f"{low_stock_materials}/{total_materials}", f"{low_stock_rate:.1f}%")
1434
-
1435
- # عرض توزيع حالة المخزون
1436
- stock_data = pd.DataFrame({
1437
- "حالة المخزون": ["مخزون كافي", "مخزون منخفض"],
1438
- "العدد": [total_materials - low_stock_materials, low_stock_materials]
1439
- })
1440
-
1441
- fig = px.pie(
1442
- stock_data,
1443
- values="العدد",
1444
- names="حالة المخزون",
1445
- title="حالة مخزون المواد",
1446
- color="حالة المخزون",
1447
- color_discrete_map={
1448
- "مخزون كافي": "#2ecc71",
1449
- "مخزون منخفض": "#e74c3c"
1450
- }
1451
- )
1452
-
1453
- st.plotly_chart(fig, use_container_width=True)
1454
-
1455
- # عرض جدول زمني للموارد
1456
- st.markdown("#### الجدول الزمني للموارد")
1457
-
1458
- # إنشاء DataFrame للجدول الزمني
1459
- timeline_df = allocations_df.copy()
1460
- timeline_df["تاريخ البدء"] = pd.to_datetime(timeline_df["تاريخ البدء"])
1461
- timeline_df["تاريخ الانتهاء"] = pd.to_datetime(timeline_df["تاريخ الانتهاء"])
1462
-
1463
- # دمج البيانات مع بيانات المشاريع
1464
- timeline_df = timeline_df.merge(
1465
- projects_df[["رقم المشروع", "اسم المشروع"]],
1466
- on="رقم المشروع",
1467
- how="left"
1468
- )
1469
-
1470
- # إضافة أسماء الموارد
1471
- timeline_df["اسم المورد"] = ""
1472
-
1473
- for i, row in timeline_df.iterrows():
1474
- if row["نوع المورد"] == "موظف":
1475
- resource_name = employees_df[employees_df["رقم الموظف"] == row["رقم المورد"]]["اسم الموظف"].values
1476
- if len(resource_name) > 0:
1477
- timeline_df.at[i, "اسم المورد"] = resource_name[0]
1478
- elif row["نوع المورد"] == "معدة":
1479
- resource_name = equipment_df[equipment_df["رقم المعدة"] == row["رقم المورد"]]["اسم المعدة"].values
1480
- if len(resource_name) > 0:
1481
- timeline_df.at[i, "اسم المورد"] = resource_name[0]
1482
- elif row["نوع المورد"] == "مادة":
1483
- resource_name = materials_df[materials_df["رقم المادة"] == row["رقم المورد"]]["اسم المادة"].values
1484
- if len(resource_name) > 0:
1485
- timeline_df.at[i, "اسم المورد"] = resource_name[0]
1486
-
1487
- # إنشاء رسم بياني للجدول الزمني
1488
- fig = px.timeline(
1489
- timeline_df,
1490
- x_start="تاريخ البدء",
1491
- x_end="تاريخ الانتهاء",
1492
- y="اسم المورد",
1493
- color="اسم المشروع",
1494
- hover_name="اسم المشروع",
1495
- hover_data=["نوع المورد", "الكمية", "التكلفة"],
1496
- title="الجدول الزمني لتخصيص الموارد"
1497
- )
1498
-
1499
- fig.update_yaxes(autorange="reversed")
1500
-
1501
- st.plotly_chart(fig, use_container_width=True)
1502
-
1503
- # عرض توقعات الاحتياجات المستقبلية
1504
- st.markdown("#### توقعات الاحتياجات المستقبلية")
1505
-
1506
- # اختيار المشروع للتخطيط
1507
- project_for_planning = st.selectbox("اختر المشروع للتخطيط", options=upcoming_projects["اسم المشروع"] if not upcoming_projects.empty else ["لا توجد مشاريع قادمة"])
1508
-
1509
- if project_for_planning != "لا توجد مشاريع قادمة":
1510
- # الحصول على بيانات المشروع
1511
- project_data = upcoming_projects[upcoming_projects["اسم المشروع"] == project_for_planning].iloc[0]
1512
-
1513
- st.markdown(f"**تاريخ البدء:** {project_data['تاريخ البدء']}")
1514
- st.markdown(f"**تاريخ الانتهاء:** {project_data['تاريخ الانتهاء']}")
1515
- st.markdown(f"**الميزانية:** {project_data['الميزانية']:,.0f} ريال")
1516
-
1517
- # تقدير الاحتياجات بناءً على المشاريع المماثلة
1518
- st.markdown("##### تقدير الاحتياجات بناءً على المشاريع المماثلة")
1519
-
1520
- # محاكاة تقدير الاحتياجات
1521
- estimated_resources = {
1522
- "الموظفون": {
1523
- "مهندس": 5,
1524
- "فني": 10,
1525
- "مشرف": 2,
1526
- "محاسب": 1,
1527
- "مساعد": 3
1528
- },
1529
- "المعدات": {
1530
- "حفارة كبيرة": 1,
1531
- "حفارة صغيرة": 2,
1532
- "شاحنة نقل": 3,
1533
- "رافعة متوسطة": 1,
1534
- "خلاطة خرسانة": 2
1535
- },
1536
- "المواد": {
1537
- "خرسانة جاهزة": 500,
1538
- "حديد تسليح": 200,
1539
- "طابوق": 10000,
1540
- "أسمنت": 1000,
1541
- "رمل": 300
1542
- }
1543
- }
1544
-
1545
- # عرض تقدير الاحتياجات
1546
- col1, col2, col3 = st.columns(3)
1547
-
1548
- with col1:
1549
- st.markdown("**الموظفون المطلوبون:**")
1550
- for position, count in estimated_resources["الموظفون"].items():
1551
- st.markdown(f"- {position}: {count}")
1552
-
1553
- # التحقق من توافر الموظفين
1554
- available_positions = {}
1555
- for position, count in estimated_resources["الموظفون"].items():
1556
- available_count = len(employees_df[(employees_df["المنصب"] == position) & (employees_df["متاح"] == True)])
1557
- available_positions[position] = available_count
1558
-
1559
- if available_count < count:
1560
- st.warning(f"نقص في {position}: متاح {available_count}/{count}")
1561
- else:
1562
- st.success(f"متوفر: {available_count}/{count}")
1563
-
1564
- with col2:
1565
- st.markdown("**المعدات المطلوبة:**")
1566
- for equipment_name, count in estimated_resources["المعدات"].items():
1567
- st.markdown(f"- {equipment_name}: {count}")
1568
-
1569
- # التحقق من توافر المعدات
1570
- available_equipment = {}
1571
- for equipment_name, count in estimated_resources["المعدات"].items():
1572
- available_count = len(equipment_df[(equipment_df["اسم المعدة"] == equipment_name) & (equipment_df["متاحة"] == True)])
1573
- available_equipment[equipment_name] = available_count
1574
-
1575
- if available_count < count:
1576
- st.warning(f"نقص في {equipment_name}: متاح {available_count}/{count}")
1577
- else:
1578
- st.success(f"متوفر: {available_count}/{count}")
1579
-
1580
- with col3:
1581
- st.markdown("**المواد المطلوبة:**")
1582
- for material_name, quantity in estimated_resources["المواد"].items():
1583
- st.markdown(f"- {material_name}: {quantity}")
1584
-
1585
- # التحقق من توافر المواد
1586
- available_materials = {}
1587
- for material_name, quantity in estimated_resources["المواد"].items():
1588
- available_quantity = materials_df[materials_df["اسم المادة"] == material_name]["الكمية المتاحة"].sum()
1589
- available_materials[material_name] = available_quantity
1590
-
1591
- if available_quantity < quantity:
1592
- st.warning(f"نقص في {material_name}: متاح {available_quantity}/{quantity}")
1593
- else:
1594
- st.success(f"متوفر: {available_quantity}/{quantity}")
1595
-
1596
- # عرض تقدير التكاليف
1597
- st.markdown("##### تقدير تكاليف الموارد")
1598
-
1599
- # حساب تكاليف الموظفين
1600
- employee_costs = 0
1601
- for position, count in estimated_resources["الموظفون"].items():
1602
- avg_cost = employees_df[employees_df["المنصب"] == position]["التكلفة الشهرية"].mean()
1603
- # افتراض مدة المشروع 6 أشهر
1604
- employee_costs += avg_cost * count * 6
1605
-
1606
- # حساب تكاليف المعدات
1607
- equipment_costs = 0
1608
- for equipment_name, count in estimated_resources["المعدات"].items():
1609
- avg_cost = equipment_df[equipment_df["اسم المعدة"] == equipment_name]["التكلفة اليومية"].mean()
1610
- # افتراض مدة المشروع 180 يوم
1611
- equipment_costs += avg_cost * count * 180
1612
-
1613
- # حساب تكاليف المواد
1614
- material_costs = 0
1615
- for material_name, quantity in estimated_resources["المواد"].items():
1616
- avg_cost = materials_df[materials_df["اسم المادة"] == material_name]["تكلفة الوحدة"].mean()
1617
- material_costs += avg_cost * quantity
1618
-
1619
- # إجمالي التكاليف
1620
- total_costs = employee_costs + equipment_costs + material_costs
1621
-
1622
- # عرض التكاليف
1623
- col1, col2, col3, col4 = st.columns(4)
1624
-
1625
- with col1:
1626
- st.metric("تكاليف الموظفين", f"{employee_costs:,.0f} ريال")
1627
-
1628
- with col2:
1629
- st.metric("تكاليف المعدات", f"{equipment_costs:,.0f} ريال")
1630
-
1631
- with col3:
1632
- st.metric("تكاليف المواد", f"{material_costs:,.0f} ريال")
1633
-
1634
- with col4:
1635
- st.metric("إجمالي التكاليف", f"{total_costs:,.0f} ريال")
1636
-
1637
- # عرض توزيع التكاليف
1638
- cost_distribution = pd.DataFrame({
1639
- "نوع التكلفة": ["تكاليف الموظفين", "تكاليف المعدات", "تكاليف المواد"],
1640
- "التكلفة": [employee_costs, equipment_costs, material_costs]
1641
- })
1642
-
1643
- fig = px.pie(
1644
- cost_distribution,
1645
- values="التكلفة",
1646
- names="نوع التكلفة",
1647
- title="توزيع تكاليف الموارد",
1648
- color="نوع التكلفة",
1649
- color_discrete_map={
1650
- "تكاليف الموظفين": "#3498db",
1651
- "تكاليف المعدات": "#2ecc71",
1652
- "تكاليف المواد": "#f39c12"
1653
- }
1654
- )
1655
-
1656
- st.plotly_chart(fig, use_container_width=True)
1657
-
1658
- # عرض توصيات لتخطيط الموارد
1659
- st.markdown("##### توصيات لتخطيط الموارد")
1660
-
1661
- recommendations = []
1662
-
1663
- # توصيات للموظفين
1664
- for position, count in estimated_resources["الموظفون"].items():
1665
- available_count = available_positions[position]
1666
- if available_count < count:
1667
- recommendations.append(f"توظيف {count - available_count} {position} إضافي")
1668
-
1669
- # توصيات للمعدات
1670
- for equipment_name, count in estimated_resources["المعدات"].items():
1671
- available_count = available_equipment[equipment_name]
1672
- if available_count < count:
1673
- recommendations.append(f"استئجار {count - available_count} {equipment_name} إضافية")
1674
-
1675
- # توصيات للمواد
1676
- for material_name, quantity in estimated_resources["المواد"].items():
1677
- available_quantity = available_materials[material_name]
1678
- if available_quantity < quantity:
1679
- recommendations.append(f"شراء {quantity - available_quantity} وحدة إضافية من {material_name}")
1680
-
1681
- if recommendations:
1682
- for recommendation in recommendations:
1683
- st.markdown(f"- {recommendation}")
1684
- else:
1685
- st.success("جميع الموارد المطلوبة متوفرة")
1686
-
1687
- # زر لإنشاء خطة الموارد
1688
- if st.button("إنشاء خطة الموارد"):
1689
- st.success("تم إنشاء خطة الموارد بنجاح!")
1690
-
1691
- # عرض ملخص الخطة
1692
- st.markdown("##### ملخص خطة الموارد")
1693
- st.markdown(f"**المشروع:** {project_for_planning}")
1694
- st.markdown(f"**تاريخ البدء:** {project_data['تاريخ البدء']}")
1695
- st.markdown(f"**تاريخ الانتهاء:** {project_data['تاريخ الانتهاء']}")
1696
- st.markdown(f"**إجمالي تكاليف الموارد:** {total_costs:,.0f} ريال")
1697
- st.markdown(f"**نسبة تكاليف الموارد من الميزانية:** {total_costs / project_data['الميزانية'] * 100:.1f}%")
1698
-
1699
- if recommendations:
1700
- st.markdown("**الإجراءات المطلوبة:**")
1701
- for recommendation in recommendations:
1702
- st.markdown(f"- {recommendation}")
1703
- else:
1704
- st.markdown("**الإجراءات المطلوبة:** لا توجد إجراءات مطلوبة، جميع الموارد متوفرة")
1705
- else:
1706
- st.info("لا توجد مشاريع قادمة للتخطيط")
 
43
  "عماد أيمن", "أيمن رامي", "رامي سمير", "سمير وائل", "وائل مازن"
44
  ]
45
  employee_departments = np.random.choice(["الهندسة", "المشتريات", "المالية", "الموارد البشرية", "تقنية المعلومات", "التسويق", "المبيعات"], n_employees)
46
+ employee_positions = np.random.choice(["مدير", "مهندس", "محلل", "مطور", "مصمم", "مشرف", "منسق", "أخصائي", "مساعد"], n_employees)
47
+ employee_salaries = np.random.randint(5000, 25000, n_employees)
 
 
 
 
 
48
  employee_experiences = np.random.randint(1, 20, n_employees)
49
+ employee_availabilities = np.random.choice([True, False], n_employees, p=[0.7, 0.3])
 
 
50
 
51
  # إنشاء DataFrame للموظفين
52
  employees_data = {
53
  "رقم الموظف": employee_ids,
54
+ "الاسم": employee_names,
55
  "القسم": employee_departments,
56
  "المنصب": employee_positions,
57
+ "التكلفة الشهرية": employee_salaries,
58
  "سنوات الخبرة": employee_experiences,
59
+ "متاح": employee_availabilities
 
 
60
  }
61
 
62
  # إنشاء بيانات المعدات
63
  n_equipment = 30
64
+ equipment_ids = [f"EQP-{i+1:03d}" for i in range(n_equipment)]
65
  equipment_names = [
66
+ "حفارة", "جرافة", "شاحنة نقل", "رافعة", "خلاطة خرسانة", "مولد كهرباء", "ضاغط هواء",
67
+ "مضخة مياه", "آلة حفر", "آلة تسوية", "آلة رصف", "آلة تشكيل", "آلة قطع", "آلة لحام",
68
+ "آلة طلاء", "آلة تنظيف", "آلة تعبئة", "آلة تغليف", "آلة فرز", "آلة تجميع",
69
+ "آلة تثقيب", "آلة تجليخ", "آلة تفريز", "آلة خراطة", "آلة تشكيل", "آلة تقطيع",
70
+ "آلة تجفيف", "آلة تبريد", "آلة تسخين", "آلة تهوية"
 
71
  ]
72
+ equipment_types = np.random.choice(["حفر", "نقل", "رفع", "خلط", "توليد", "ضغط", "ضخ", "تشكيل", "قطع", "لحام", "طلاء", "تنظيف", "تعبئة", "تغليف", "فرز", "تجميع", "تثقيب", "تجليخ", "تفريز", "خراطة"], n_equipment)
73
  equipment_costs = np.random.randint(500, 5000, n_equipment)
74
+ equipment_availabilities = np.random.choice([True, False], n_equipment, p=[0.8, 0.2])
75
  equipment_conditions = np.random.choice(["��متاز", "جيد", "متوسط", "سيء"], n_equipment, p=[0.4, 0.3, 0.2, 0.1])
76
+ equipment_locations = np.random.choice(["المستودع", "موقع العمل 1", "موقع العمل 2", "موقع العمل 3", "في الصيانة"], n_equipment)
77
 
78
  # إنشاء DataFrame للمعدات
79
  equipment_data = {
80
  "رقم المعدة": equipment_ids,
81
+ "الاسم": equipment_names,
82
  "النوع": equipment_types,
83
  "التكلفة اليومية": equipment_costs,
84
  "متاحة": equipment_availabilities,
 
192
  "allocations": pd.DataFrame(allocations_data)
193
  }
194
 
195
+ def run(self):
196
+ """
197
+ تشغيل وحدة الموارد
198
+
199
+ هذه الدالة هي نقطة الدخول الرئيسية لوحدة الموارد وتقوم بتهيئة واجهة المستخدم
200
+ وعرض جميع العناصر المطلوبة.
201
+ """
202
+ # استدعاء دالة العرض الرئيسية
203
+ self.render()
204
+
205
  def render(self):
206
  """عرض واجهة وحدة الموارد"""
207
 
 
368
  )
369
 
370
  fig = px.bar(
371
+ (Content truncated due to size limit. Use line ranges to read in chunks)