🧬 ترتيب البانل وعناوينه الفرعية

تحليل الوضع الحالي + اقتراح شكل وموضع تقسيم الفحوصات داخل البانل — وحدة المختبر LIS

Moon ERP · 2026-05-21

① الخلاصة السريعة

طلبك: البانل (مثل CBC) لازم يكون فيه:

  1. ترتيب ثابت للفحوصات — تظهر بنفس الترتيب في إدخال النتيجة وفي التقرير المطبوع.
  2. عناوين فرعية تجمّع مجموعة فحوصات تحت اسم واحد (مثل: «صورة الدم الحمراء» / «التفاضلي للكرات البيضاء»).
جزئي
الترتيب — العمود موجود بالـ DB بس مفيش UI ولا بيتبعت
غير موجود
العناوين الفرعية — لا في الـ DB ولا الواجهة
جاهز
التقرير PDF — بيدعم subHeader فعلاً، مستني البيانات بس
الحكم: المطلوب تعديل بسيط في الـ Backend (جدول واحد جديد + عمود) — والباقي كله شغل واجهة نعمله إحنا. مفيش أي إعادة هيكلة.

② الوضع الحالي — إيه المعمول فعلاً

أ) قاعدة البيانات

جدول ربط أعضاء البانل lab_investigation_panel_members:

// الموجود حالياً
panel_id     FK → lab_investigations
member_id    FK → lab_investigations
sort_order   unsignedInteger default 0  ← موجود لكن مهمَل
timestamps
unique(panel_id, member_id)

ب) إنشاء وتعديل البانل (الواجهة)

عند حفظ بانل، الواجهة بتبعت مصفوفة IDs فقط — من غير ترتيب ولا أقسام:

// lis-investigations.component.ts — saveCreatePanel()
panel_members: this.selectedInvestigations.map(inv => inv.id)
// → [12, 23, 24, 25, ...]   مجرد IDs

// الخدمة updatePanelMembers() بتبعت
{ member_ids: [12, 23, 24] }   ← مفيش sort_order إطلاقاً
ثغرة قائمة فعلاً: حتى من غير موضوع العناوين الفرعية — الترتيب نفسه مكسور النهارده. عمود sort_order موجود بالجدول بس الواجهة لا بتبعته ولا فيه شاشة لإعادة الترتيب. ترتيب ظهور الفحوصات حالياً = ترتيب اختيارهم بالصدفة.

ج) عرض أعضاء البانل

المكانالشكل الحاليالحالة
تفاصيل الفحص (investigations)قائمة مرقّمة مسطّحة 1،2،3…مسطّح
إدخال النتيجة (results)صف عنوان للبانل ثم صفوف الأعضاء (isPanelHeader)بانل واحد بس
تقرير PDF (lis-report-pdf)الكود فيه subHeader?: boolean على الصف — جاهز للرسمجاهز
مهم: خدمة الـ PDF فيها subHeader متظبّط ومرسوم بالفعل (سطر 414 — عنوان وسطّي بخط عريض). لكن باني بيانات التقرير في results.component.ts (سطر 1362) لا يضع subHeader أبداً لأن مفيش بيانات أقسام تغذّيه. يعني الرسم جاهز، البيانات هي الناقصة.

③ الناقص بالضبط

#الناقصالطبقةمين يعمله
1مفهوم «قسم/عنوان فرعي» داخل البانل (جدول + علاقة)Backendأحمد
2endpoint حفظ الأعضاء يقبل sort_order + section_idBackendأحمد
3الـ Resource يرجّع الأعضاء مجمّعة/مرتّبةBackendأحمد
4شاشة محرّر البانل: سحب لإعادة الترتيب + إضافة/تسمية أقسامFrontendإحنا
5إدخال النتيجة: صف فاصل بعنوان القسم بين المجموعاتFrontendإحنا
6تغذية subHeader في باني بيانات التقريرFrontendإحنا

④ التصميم المقترح — الشكل والموضع

أ) نموذج البيانات — جدول أقسام مستقل

أفضل من إضافة عمود نص group_label على كل صف عضو، للأسباب التالية: إعادة تسمية القسم = تعديل صف واحد بدل N صفوف، الاسم ثنائي اللغة بدون تكرار، وترتيب الأقسام صريح وثابت.

// جدول جديد
lab_panel_sections
  id, panel_id FK→lab_investigations,
  name, name_ar,
  sort_order, timestamps

// تعديل جدول الربط الموجود
lab_investigation_panel_members
  + section_id  FK→lab_panel_sections  nullable
  sort_order    ← يصبح "ترتيب داخل القسم"
توافق رجعي كامل: أي بانل قديم → كل أعضائه section_id = NULL → يظهر كقائمة مسطّحة زي النهارده بالظبط. مفيش أي ترحيل بيانات مطلوب. القسم اختياري — البانل البسيط يفضل بدون أقسام.

ب) شكل محرّر البانل — في شاشة تفاصيل الفحص

كل قسم صندوق قابل للطي، بمقبض سحب لإعادة الترتيب، والأعضاء جواه بمقابض سحب كمان. زر «+ إضافة قسم» تحت.

محرّر بانل CBC — أعضاء + أقسام
صورة الدم الحمراء — RBC Parameters ✎ 🗑
1RBC Count10⁶/µL
2Hemoglobing/dL
3Hematocrit%
4MCV · MCH · MCHC
التفاضلي للكرات البيضاء — WBC Differential ✎ 🗑
1Neutrophils %%
2Lymphocytes %%
3Monocytes %%
+ إضافة قسم جديد

مكتبة السحب: PrimeNG لا تملك drag-list ناضج — نستخدم @angular/cdk/drag-drop (موجود بالفعل كاعتمادية Angular). سحب على مستويين: الأقسام، والأعضاء داخل القسم.

ج) شكل التقرير المطبوع

عنوان القسم يظهر كصف وسطّي بخط عريض بين صفوف الأعضاء — وده مرسوم جاهز في خدمة الـ PDF، محتاج بس البيانات تغذّيه.

تقرير CBC — الناتج المطبوع
Complete Blood Count (CBC)
TestResultReference
▸ صورة الدم الحمراء — RBC Parameters
RBC Count5.14.5–5.9
Hemoglobin14.213–17
Hematocrit4240–50
▸ التفاضلي للكرات البيضاء — WBC Differential
Neutrophils %6040–70
Lymphocytes %3220–40

د) شكل إدخال النتيجة

نفس الفكرة: صف فاصل بعنوان القسم بين صفوف إدخال الأعضاء. الكود حالياً عنده صف افتراضي isPanelHeader (سطر ~253) — نضيف نوع isSectionHeader على نفس النمط.

إدخال نتيجة — بانل CBC
▾ CBC — Complete Blood Count
صورة الدم الحمراء — RBC Parameters
RBC Count 5.1
Hemoglobin 14.2
التفاضلي للكرات البيضاء — WBC Differential
Neutrophils % 60

⑤ مسار البيانات — البانل بيغذّي 3 شاشات

lab_panel_sections + section_id
        │
        ├──> محرّر البانل        سحب/إعادة ترتيب + إضافة أقسام
        │
        ├──> إدخال النتيجة      صف isSectionHeader بين المجموعات
        │     (results.component.ts ~253)
        │
        └──> تقرير PDF          subHeader:true عند حدود كل قسم
              (results.component.ts:1362 يبني ReportResultRow[])

أي ترتيب يتحدد مرة واحدة في المحرّر → يظهر متطابق في الإدخال والطباعة. مصدر حقيقة واحد.

⑥ المطلوب من Backend — تذكرة أحمد

الـ Backend للقراءة فقط من ناحيتنا. المطلوب تذكرة لأحمد بالبنود التالية:

1. Migration

2. endpoint حفظ أعضاء البانل

تعديل PUT /lis/investigations/{id}/panel-members ليقبل بنية غنية بدل مصفوفة IDs:

{
  "sections": [
    { "name":"RBC Parameters", "name_ar":"صورة الدم الحمراء", "sort_order":1,
      "members": [ {"member_id":23,"sort_order":1}, {"member_id":24,"sort_order":2} ] }
  ],
  "ungrouped": [ {"member_id":30,"sort_order":1} ]
}

يفضّل قبول الشكل القديم (member_ids: []) كمان لتوافق رجعي.

3. الـ Resource

معايير القبول

⑦ خطة الواجهة — شغلنا إحنا (بعد الـ Backend)

  1. الموديل: إضافة section_id + sort_order لـ LisPanelMember، وواجهة LisPanelSection جديدة.
  2. محرّر البانل: مكوّن جديد بـ @angular/cdk/drag-drop — أقسام قابلة للطي + سحب على مستويين + إضافة/تسمية/حذف قسم.
  3. الخدمة: updatePanelMembers() تبعت بنية sections الجديدة.
  4. إدخال النتيجة: صف isSectionHeader في باني الصفوف المسطّح (سطر ~253).
  5. التقرير: باني ReportResultRow[] (سطر 1362) يصدّر صف subHeader:true عند بداية كل قسم.
  6. عرض التفاصيل: أعضاء البانل في شاشة الفحص تتجمّع تحت عناوين الأقسام.
التقدير: ~15% تعديل Backend (تذكرة أحمد) · ~85% واجهة نعملها إحنا. لا إعادة هيكلة — كله إضافات اختيارية فوق الموجود.