تحليل الوضع الحالي + اقتراح شكل وموضع تقسيم الفحوصات داخل البانل — وحدة المختبر LIS
Moon ERP · 2026-05-21طلبك: البانل (مثل CBC) لازم يكون فيه:
جدول ربط أعضاء البانل 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)
sort_order — يعني الترتيب ممكن يتخزّن.عند حفظ بانل، الواجهة بتبعت مصفوفة 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 على الصف — جاهز للرسم | جاهز |
subHeader متظبّط ومرسوم بالفعل (سطر 414 — عنوان وسطّي بخط عريض). لكن باني بيانات التقرير في results.component.ts (سطر 1362) لا يضع subHeader أبداً لأن مفيش بيانات أقسام تغذّيه. يعني الرسم جاهز، البيانات هي الناقصة.
| # | الناقص | الطبقة | مين يعمله |
|---|---|---|---|
| 1 | مفهوم «قسم/عنوان فرعي» داخل البانل (جدول + علاقة) | Backend | أحمد |
| 2 | endpoint حفظ الأعضاء يقبل sort_order + section_id | Backend | أحمد |
| 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 → يظهر كقائمة مسطّحة زي النهارده بالظبط. مفيش أي ترحيل بيانات مطلوب. القسم اختياري — البانل البسيط يفضل بدون أقسام.
كل قسم صندوق قابل للطي، بمقبض سحب لإعادة الترتيب، والأعضاء جواه بمقابض سحب كمان. زر «+ إضافة قسم» تحت.
مكتبة السحب: PrimeNG لا تملك drag-list ناضج — نستخدم @angular/cdk/drag-drop (موجود بالفعل كاعتمادية Angular). سحب على مستويين: الأقسام، والأعضاء داخل القسم.
عنوان القسم يظهر كصف وسطّي بخط عريض بين صفوف الأعضاء — وده مرسوم جاهز في خدمة الـ PDF، محتاج بس البيانات تغذّيه.
نفس الفكرة: صف فاصل بعنوان القسم بين صفوف إدخال الأعضاء. الكود حالياً عنده صف افتراضي isPanelHeader (سطر ~253) — نضيف نوع isSectionHeader على نفس النمط.
lab_panel_sections + section_id
│
├──> محرّر البانل سحب/إعادة ترتيب + إضافة أقسام
│
├──> إدخال النتيجة صف isSectionHeader بين المجموعات
│ (results.component.ts ~253)
│
└──> تقرير PDF subHeader:true عند حدود كل قسم
(results.component.ts:1362 يبني ReportResultRow[])
أي ترتيب يتحدد مرة واحدة في المحرّر → يظهر متطابق في الإدخال والطباعة. مصدر حقيقة واحد.
الـ Backend للقراءة فقط من ناحيتنا. المطلوب تذكرة لأحمد بالبنود التالية:
lab_panel_sections: id, panel_id, name, name_ar, sort_order, timestamps.section_id (nullable FK → lab_panel_sections, nullOnDelete) على lab_investigation_panel_members.section_id = NULL = مجموعة بدون عنوان.تعديل 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: []) كمان لتوافق رجعي.
InvestigationResource يرجّع panel_sections[] وكل قسم جواه members[] مرتّبة بـ sort_order.ungrouped_members[].sort_order و section_id.section_id + sort_order لـ LisPanelMember، وواجهة LisPanelSection جديدة.@angular/cdk/drag-drop — أقسام قابلة للطي + سحب على مستويين + إضافة/تسمية/حذف قسم.updatePanelMembers() تبعت بنية sections الجديدة.isSectionHeader في باني الصفوف المسطّح (سطر ~253).ReportResultRow[] (سطر 1362) يصدّر صف subHeader:true عند بداية كل قسم.