Skip to content

مكتبات الواجهة والمعمارية — نظام إدارة المغسلة

معلومات الوثيقة

الحقل القيمة
المشروع نظام إدارة المغسلة
الإصدار 1.0
اللغة العربية
الإطار Angular 19+
نوع الوثيقة دليل مكتبات الواجهة للمطورين

1. هيكل المشروع

frontend/laundry-app/
├── src/app/
│   ├── core/                    # خدمات فردية، حراس، معترضات
│   │   ├── services/            # api-base، auth، print، export، license
│   │   ├── interceptors/        # jwt، client-token، error
│   │   └── guards/              # auth، license، role
│   ├── shared/                  # مكونات وأنابيب وتوجيهات قابلة لإعادة الاستخدام
│   ├── modules/                 # وحدات محملة بتحميل كسول
│   │   ├── dashboard/
│   │   ├── invoices/
│   │   ├── customers/
│   │   ├── payments/
│   │   ├── carpet/
│   │   ├── tailoring/
│   │   ├── inventory/
│   │   ├── reports/
│   │   ├── admin/
│   │   └── wizard/
│   └── layout/                  # هيكل التطبيق، القائمة الجانبية، الرأس
├── assets/
│   ├── i18n/ {ar,en}.json
│   └── styles/ {_variables، _rtl، _print-thermal، _print-a4}.scss
├── src-tauri/                   # Tauri (Rust)
└── {package، angular، tsconfig، jest، eslintrc، prettierrc}.json

2. قائمة حزم npm الكاملة

الحزمة الغرض
@angular/core، @angular/router، @angular/forms الإطار الأساسي
@angular/service-worker PWA / تخزين مؤقت دون اتصال
primeng مكتبة المكونات
primeflex أدوات CSS
primeicons الأيقونات
chart.js الرسوم البيانية (عبر primeng/chart)
@ngx-translate/core + @ngx-translate/http-loader ترجمة AR/EN
rxjs برمجة تفاعلية
xlsx (SheetJS) تصدير Excel
html2canvas + jspdf PDF
jsbarcode باركود
@ngrx/store، @ngrx/effects، @ngrx/entity إدارة الحالة
@ngrx/router-store مزامنة المتجر مع الموجه
@ngrx/store-devtools أدوات تصحيح Redux
@tauri-apps/api + @tauri-apps/cli جسر Tauri
@tauri-apps/plugin-* (8 إضافات) shell، updater، dialog، fs، process، window-state، store، os
jest + jest-preset-angular + @testing-library/angular اختبار
eslint + @angular-eslint/builder تدقيق الكود
prettier + prettier-plugin-organize-imports تنسيق الكود
husky + lint-staged خطافات Git

3. الأنماط المعمارية

نمط Smart/Dumb + Facade

الحاوية (Smart)                  العرض (Dumb)
┌──────────────────────┐         ┌──────────────────┐
│ تحقن Facade           │──@Input──▶│ @Input() فقط      │
│ async pipe            │◀─@Output──│ @Output() فقط     │
│ لا استدعاءات HTTP     │         │ OnPush           │
│ OnPush                │         └──────────────────┘
└──────────────────────┘
    Injectable Facade
    ┌─────────────────┐
    │ لا تستورد NgRx   │  ← المكونات لا تلمس Store مباشرة
    │ dispatch + select│
    └─────────────────┘

تدفق بيانات NgRx

مستخدم ← مكون ← Facade.dispatch(action) ← Action ← Effect ← API
                                            Success/Failure Action
                                                    Reducer
                                     Selector ← حالة ← مكون (عرض)

4. NgRx — إدارة الحالة

تسجيل المتجر

provideStore({
  invoices: invoiceReducer,
  customers: customerReducer,
  payments: paymentReducer,
  carpet: carpetReducer,
  tailoring: tailoringReducer,
  inventory: inventoryReducer,
  reports: reportReducer,
  admin: adminReducer,
  wizard: wizardReducer,
}),
provideEffects([InvoiceEffects, CustomerEffects, ...]),
provideStoreDevtools({ maxAge: 50 }),

الإجراءات (Actions)

export const InvoiceActions = createActionGroup({
  source: 'Invoice',
  events: {
    'Load': emptyProps(),
    'Load Success': props<{ invoices: InvoiceDto[] }>(),
    'Load Failure': props<{ error: string }>(),
    'Create': props<{ dto: CreateInvoiceDto }>(),
    'Create Success': props<{ invoice: InvoiceDto }>(),
  }
});

المخفض (Reducer)

export const invoiceReducer = createReducer(
  initialState,
  on(InvoiceActions.load, (s) => ({ ...s, loading: true })),
  on(InvoiceActions.loadSuccess, (s, { invoices }) =>
    invoiceAdapter.setAll(invoices, { ...s, loading: false })),
);

التأثيرات (Effects)

load$ = createEffect(() => this.actions$.pipe(
  ofType(InvoiceActions.load),
  switchMap(() => this.service.getAll().pipe(
    map(invoices => InvoiceActions.loadSuccess({ invoices })),
    catchError(error => of(InvoiceActions.loadFailure({ error })))
  ))
));

الواجهة (Facade)

@Injectable({ providedIn: 'root' })
export class InvoiceFacade {
  store = inject(Store);
  invoices$ = this.store.select(selectAllInvoices);
  load() { this.store.dispatch(InvoiceActions.load()); }
  create(dto: CreateInvoiceDto) { this.store.dispatch(InvoiceActions.create({ dto })); }
}

5. PrimeNG

providePrimeNG({
  theme: { preset: Aura },
  ripple: true,
});

6. الترجمة (ngx-translate)

provideTranslateService({
  defaultLanguage: 'ar',
  useDefaultLang: true,
});

7. تكامل Tauri

@Injectable({ providedIn: 'root' })
export class TauriBridgeService {
  isTauri = !!(window as any).__TAURI_INTERNALS__;

  async startDockerServices() {
    const { invoke } = await import('@tauri-apps/api/core');
    return invoke('start_docker_services');
  }
  async computeClientToken() {
    const { invoke } = await import('@tauri-apps/api/core');
    return invoke('compute_client_token');
  }
}

8. خدمات الطباعة

printThermalReceipt(element: HTMLElement) {
  const w = window.open('', '_blank', 'width=300');
  w!.document.write(`<html><head><link rel="stylesheet" href="styles/_print-thermal.scss"></head>
    <body>${element.innerHTML}</body></html>`);
  w!.print(); w!.close();
}

9. خدمات التصدير

toExcel(data: any[], filename: string) {
  const ws = XLSX.utils.json_to_sheet(data);
  XLSX.writeFile(XLSX.utils.book_new(ws), `${filename}.xlsx`);
}

async toPDF(element: HTMLElement, filename: string) {
  const canvas = await html2canvas(element, { scale: 2 });
  const pdf = new jsPDF('p', 'mm', 'a4');
  pdf.addImage(canvas.toDataURL(), 'PNG', 0, 0, 210, h);
  pdf.save(`${filename}.pdf`);
}

10. هيكل المسارات

export const routes: Routes = [
  { path: 'login',    loadComponent: () => import('./login/login.component') },
  { path: 'wizard',   loadChildren: () => import('./modules/wizard/routes') },
  { path: '',
    canActivate: [AuthGuard],
    loadComponent: () => import('./layout/app-shell/app-shell.component'),
    children: [
      { path: '', redirectTo: 'dashboard', pathMatch: 'full' },
      { path: 'dashboard',   loadChildren: () => import('./modules/dashboard/routes') },
      { path: 'invoices',    loadChildren: () => import('./modules/invoices/routes') },
      { path: 'customers',   loadChildren: () => import('./modules/customers/routes') },
      { path: 'payments',    loadChildren: () => import('./modules/payments/routes') },
      { path: 'carpet',      loadChildren: () => import('./modules/carpet/routes') },
      { path: 'tailoring',   loadChildren: () => import('./modules/tailoring/routes') },
      { path: 'inventory',   loadChildren: () => import('./modules/inventory/routes') },
      { path: 'reports',     loadChildren: () => import('./modules/reports/routes') },
      { path: 'admin',       loadChildren: () => import('./modules/admin/routes'), canActivate: [RoleGuard] },
    ]
  },
];

11. معترضات HTTP

// jwt: يحقن Authorization: Bearer
// client-token: يحقن X-Laundry-Client-Token (للفروع غير المتصلة فقط)
// error: يعالج أخطاء 4xx/5xx عالمياً
// loading: مؤشر تحميل عالمي

provideHttpClient(withInterceptors([jwt, clientToken, error, loading]))

12. اتفاقيات الكود

الاتفاقية القاعدة
الملفات kebab-case للملفات. PascalCase للصنف.
المكونات الحاويات الذكية تلحق بـ -container. البكماء باسم وصفي.
الخدمات Service لـ API. Facade للتجريد عن المتجر.
النماذج واجهات TypeScript فقط.
التغيير OnPush على جميع المكونات.
مستقل جميع المكونات standalone: true.
الترجمة لا تكتب نصوصاً عربية أو إنجليزية مباشرة. استخدم translate.

13. ESLint + Prettier

// .prettierrc
{ "singleQuote": true, "trailingComma": "all", "printWidth": 100, "tabWidth": 2 }

سجل المراجعة

التاريخ الإصدار المعد التغييرات
2026-05-10 1.0 قائد الواجهة الإصدار الأولي لدليل مكتبات الواجهة