1 الخلاصة التنفيذية
1820تحليل تُرسم كلها في الـ DOM على تبويب «الكل»
×3InputNumber ثقيل لكل صف = آلاف المكوّنات
0virtual scroll — لا يوجد (السبب الرئيسي للبطء)
~15الصفوف اللي المفروض تتعرض فعليًا في الشاشة
جذر البطء: جدول التسعير داخل النافذة مش مُحَزَّن (no virtual scroll) — بيرسم كل الـ 1820 صف دفعة واحدة، وكل صف مُضاف فيه 3 مكوّنات PrimeNG InputNumber (ثقيلة). النتيجة: آلاف المكوّنات في الذاكرة، وكل ضغطة زر على أي خانة بتشغّل Change Detection على الجدول كله → تأخير محسوس.
مشكلة UX موازية: «إضافة قائمة أسعار» بتحشر بيانات القائمة + تسعير 1820 تحليل في نافذة واحدة بارتفاع 350px — مساحة تعديل ضيقة جدًا لمهمة ضخمة.
2 الوضع الحالي (بالأدلة من الكود)
صفحة /lab/price-lists — قائمة بالقوائم + نافذة إضافة/تعديل واحدة فيها كل حاجة:
| الجزء | الوصف | الحالة |
| قائمة القوائم | جدول بالقوائم (نشط/افتراضي) + بحث + نسخ قائمة | جيد |
| بيانات القائمة | الاسم، الكود، العملة، افتراضي، نشط، تواريخ السريان | جيد |
| «ابدأ من قائمة» | نسخ أسعار من قائمة موجودة (وضع الإضافة فقط) | ميزة حلوة |
| تبويبات التسعير | «المُضاف» / «الكل» + بحث + عدّادات | «الكل» يرسم 1820 صف |
| أدوات جماعية | تضمين الكل/المرئي/استبعاد الكل + نسبة %± | موجودة |
| الجريد | لكل صف: تضمين + سعر افتراضي + سعر القائمة + خصم% + TAT (3 InputNumber) | بطيء — بلا تحزين |
| تمبلت / تصدير / استيراد | Excel/CSV — تنزيل قالب، تصدير، استيراد (مطابقة بالكود) | موجود لكن مدفون |
الكود المسبّب: <p-table [value]="filteredPricingRows()" [scrollable]="true" scrollHeight="350px"> — scrollable فقط، مفيش [virtualScroll]="true". وكل صف: <p-inputNumber> ×3 مع (onInput) على كل ضغطة.
3 جذر مشكلة البطء + الحل التقني
| # | السبب | الحل | الأثر |
| 1 | الجدول بلا virtual scroll → 1820 صف في الـ DOM | [virtualScroll]="true" [virtualScrollItemSize]="46" | يرسم ~15 صف بس |
| 2 | 3 PrimeNG InputNumber لكل صف (مكوّن ثقيل جدًا) | إدخال <input type="number"> خفيف للجريد | أخف بمرّات |
| 3 | مفيش dataKey/trackBy → إعادة رسم كاملة عند البحث | dataKey="investigation_id" + trackBy | يحافظ على الصفوف |
| 4 | Change Detection افتراضي رغم استخدام signals | ChangeDetectionStrategy.OnPush | CD محدود |
| 5 | (onInput) يحدّث على كل حرف | تثبيت القيمة عند blur أو ngModelChange مُخفّض | أقل عمليات |
أسرع مكسب فوري: تفعيل virtual scroll + استبدال InputNumber بإدخال HTML خفيف = اختفاء البطء تقريبًا، حتى على تبويب «الكل» بـ 1820 صف.
4 نقد UX/UI — لماذا التجربة مرهِقة؟
- كل شيء في نافذة واحدة: بيانات القائمة + تسعير 1820 تحليل في مودال — مهمتان مختلفتان تمامًا محشورتان معًا.
- مساحة تعديل 350px: تسعير كتالوج ضخم في صندوق صغير — تمرير لا نهائي، تركيز ضائع.
- 3 خانات رقمية في صف ضيق: سعر/خصم/TAT متلاصقة في مودال = أخطاء إدخال.
- الاستيراد/التصدير «مدفون» ضمن شريط أزرار صغير — رغم إنه أسرع طريق فعلي لتسعير 1820 تحليل.
- لا تنقّل بلوحة المفاتيح (Enter/Tab/أسهم) — التسعير المتسلسل بطيء بالماوس.
- لا فلترة بالقسم/الفئة — صعب تسعّر قسم كامل دفعة.
5 التصميم المقترح — افصل المهمتين
المبدأ: «إنشاء القائمة» سريع · «التسعير» مساحة كاملة احترافية
① نافذة سريعة: بيانات القائمة فقط
┌─ New Price List ──────────────┐
Name (EN) * [______________]
Name (AR) [______________]
Code [_____] Currency [SAR ▾]
☑ Active ☐ Default
Valid from [__] to [__]
Start from: [Existing list ▾]
[ Create & price → ] [Cancel]
└───────────────────────────────┘
يحفظ القائمة فورًا ويفتح محرّر الأسعار.
② محرّر أسعار — صفحة كاملة (مش مودال)
Price List: «Madina Lab» · SAR [Export][Import]
[ Added 312 | All 1820 ] Search[___] Section[All ▾]
Bulk: +%[__] −%[__] [Set=default] [Round] [×All]
─────────────────────────────────────────────
✓ Test (code) Def List Disc% Final
─────────────────────────────────────────────
☑ CBC (CBC) 30.00 [35.0] [0 ] 35.00
☑ Glucose (GLU) 12.00 [15.0] [10] 13.50
☑ HbA1c (A1C) 40.00 [45.0] [0 ] 45.00
☐ Vitamin D ... — — — —
▼ virtual scroll — only ~15 rows in DOM ▼
─────────────────────────────────────────────
312 priced · total catalog 1820 [ Save ]
عرض كامل · تمرير محزّن · تنقّل بالكيبورد.
ملامح المحرّر
- Virtual scroll — يرسم الصفوف المرئية فقط (سرعة فورية حتى مع 1820).
- إدخالات خفيفة + عمود «السعر النهائي» محسوب تلقائيًا (سعر − خصم).
- تنقّل بالكيبورد: Enter = الصف التالي، Tab = الخانة التالية، أسهم.
- فلترة بالقسم/الفئة + بحث — تسعّر قسم كامل بضغطة «تضمين المرئي».
- أدوات جماعية أقوى: %± ، «اضبط = الافتراضي»، «تقريب»، «تضمين/استبعاد».
- حفظ تلقائي/صريح مع مؤشر «تم الحفظ».
6 الاستيراد/التصدير — اجعله الطريق الأساسي للجملة
تسعير 1820 تحليل يدويًا غير عملي. Excel هو الأسرع. نرفعه لمكانة أساسية:
Export → فايل Excel فيه: code | name | default | list | disc% | tat
↓ (تعدّل في Excel — مكانك الطبيعي)
Import → معاينة قبل التطبيق:
• 280 سطر هيتغيّر • 12 كود مش متطابق (تتجاهل) • 3 أسعار فاضية
[ Apply 280 changes ] [Cancel]
- معاينة قبل التطبيق (Preview): يبيّن كام سطر هيتغيّر، الأكواد غير المتطابقة، الأسعار الفاضية — قبل ما يكتب أي حاجة.
- قالب واضح بكل الأكواد + أعمدة جاهزة (موجود — نخليه أبرز).
- مطابقة بالكود (موجودة) + تقرير مطابقة بعد الرفع.
7 مراجعة كل ميزة — يفضل / يتعدّل
| الميزة | القرار |
| قائمة القوائم + نشط/افتراضي | تفضل |
| بيانات القائمة في مودال | تتبسّط — مودال سريع للبيانات فقط |
| تسعير 1820 في نفس المودال | يتنقل — لصفحة محرّر كاملة |
| تبويبات المُضاف/الكل | تفضل + virtual scroll |
| «ابدأ من قائمة» | تفضل — قيّمة جدًا |
| أدوات جماعية + %± | تتقوّى (اضبط=الافتراضي، تقريب، فلترة قسم) |
| استيراد/تصدير/قالب | يبرز + معاينة قبل التطبيق |
| نسخ قائمة | تفضل |
8 خطة التنفيذ بالمراحل
المرحلة 1 — حل البطء فورًا (نص يوم)
تفعيل virtual scroll + استبدال InputNumber بإدخال خفيف + dataKey + OnPush.
من غير تغيير شكل — البطء يختفي.
المرحلة 2 — فصل التسعير لصفحة محرّر (يوم–يومين)
مودال البيانات السريع + صفحة
/lab/price-lists/:id/prices بالجريد المحزّن + عمود السعر النهائي + فلترة القسم.
المرحلة 3 — تنقّل كيبورد + أدوات جماعية أقوى (نص يوم)
Enter/Tab/أسهم + اضبط=الافتراضي + تقريب + تضمين المرئي بعد فلترة القسم.
المرحلة 4 — استيراد بمعاينة (نص يوم)
Preview قبل التطبيق + تقرير المطابقة + إبراز القالب/التصدير.
9 قرارات محتاج رأيك فيها
قرار 1 — الأولوية
أبدأ بـ
حل البطء فقط (المرحلة 1) وأسلّمه بسرعة، ولا أعمل إعادة التصميم الكاملة دفعة واحدة؟
(توصيتي: المرحلة 1 فورًا ثم الباقي)
قرار 2 — صفحة محرّر منفصلة
توافق نفصل التسعير في
صفحة كاملة بدل المودال؟
(توصيتي: نعم — أكبر تحسين تجربة)
قرار 3 — عمود السعر النهائي
نضيف عمود «السعر النهائي» المحسوب (سعر − خصم) للوضوح؟
(توصيتي: نعم)
قرار 4 — فلترة بالقسم
نضيف فلتر القسم/الفئة عشان تسعّر قسم كامل دفعة؟
(توصيتي: نعم)
10 الخلاصة
البطء سببه غياب virtual scroll + 3 InputNumber ثقيلة لكل صف — يتحل في نص يوم (المرحلة 1) من غير ما نغيّر الشكل. وبعدها نفصل التسعير في صفحة محرّر كاملة بتنقّل كيبورد وفلترة قسم وعمود سعر نهائي، ونرفع الاستيراد/التصدير بمعاينة كطريق أساسي للجملة. النتيجة: تسعير سريع، واضح، واحترافي.