feat(ui): implement unified design system and financial reporting
Introduce a comprehensive design system across WordPress and Laravel to ensure visual consistency. Implement new financial reporting capabilities and Excel export functionality within the Filament admin panel. - Add `DESIGN_SYSTEM.md` to define brand colors, typography, and spacing - Implement `FinancialReport` page in Filament for transaction and shipment summaries - Add Excel export support for `ShipmentResource` and `WalletTransactionResource` using Laravel Excel - Refactor WordPress plugin and Filament CSS to utilize the new design system variables - Update project status to reflect new reporting and design milestones
This commit is contained in:
parent
cb55f74cb7
commit
8b0814230c
179
01_Documents/DESIGN_SYSTEM.md
Normal file
179
01_Documents/DESIGN_SYSTEM.md
Normal file
@ -0,0 +1,179 @@
|
||||
# IFNEX Design System
|
||||
|
||||
## 🎨 رنگهای برند
|
||||
|
||||
### رنگهای اصلی
|
||||
| نام | HEX | استفاده |
|
||||
|-----|-----|---------|
|
||||
| Primary Amber | `#f59e0b` | دکمههای اصلی، لینکها، آیکونهای فعال |
|
||||
| Primary Dark | `#d97706` | هاور دکمهها |
|
||||
| Primary Light | `#fbbf24` | زمینههای روشن، هایلایت |
|
||||
| Success Green | `#059669` | عملیات موفق، موجودی مثبت |
|
||||
| Danger Red | `#dc2626` | خطاها، موجودی منفی |
|
||||
| Warning Yellow | `#f59e0b` | هشدارها، در حال پردازش |
|
||||
| Info Blue | `#2563eb` | اطلاعات، لینکها |
|
||||
|
||||
### رنگهای خنثی
|
||||
| نام | HEX | استفاده |
|
||||
|-----|-----|---------|
|
||||
| Gray 900 | `#111827` | متنهای اصلی |
|
||||
| Gray 700 | `#374151` | متنهای ثانویه |
|
||||
| Gray 500 | `#6b7280` | توضیحات، placeholder |
|
||||
| Gray 300 | `#d1d5db` | حاشیهها |
|
||||
| Gray 100 | `#f3f4f6` | پسزمینههای روشن |
|
||||
| White | `#ffffff` | پسزمینه کارتها |
|
||||
|
||||
### رنگهای Sidebar
|
||||
| نام | HEX | استفاده |
|
||||
|-----|-----|---------|
|
||||
| Sidebar Dark | `#1a1a2e` | پسزمینه اصلی سایدبار |
|
||||
| Sidebar Blue | `#16213e` | گرادینت سایدبار |
|
||||
| Sidebar Active | `rgba(245, 158, 11, 0.15)` | آیتم فعال |
|
||||
|
||||
## 📐 فاصلهگذاری (Spacing)
|
||||
|
||||
| نام | مقدار | استفاده |
|
||||
|-----|-------|---------|
|
||||
| xs | 0.25rem (4px) | فاصلههای خیلی کوچک |
|
||||
| sm | 0.5rem (8px) | فاصلههای کوچک |
|
||||
| md | 1rem (16px) | فاصلههای استاندارد |
|
||||
| lg | 1.5rem (24px) | فاصلههای بزرگ |
|
||||
| xl | 2rem (32px) | فاصلههای خیلی بزرگ |
|
||||
| 2xl | 3rem (48px) | فاصلههای بخشها |
|
||||
|
||||
## 🔤 تایپوگرافی
|
||||
|
||||
### فونت اصلی
|
||||
- **فامیلی:** Vazirmatn, IranYekan, ui-sans-serif, system-ui, sans-serif
|
||||
- **سایز پایه:** 14px
|
||||
- **خط:** 1.6
|
||||
|
||||
### سایزهای فونت
|
||||
| نام | اندازه | وزن | استفاده |
|
||||
|-----|--------|-----|---------|
|
||||
| xs | 0.75rem (12px) | 400 | توضیحات، watermark |
|
||||
| sm | 0.875rem (14px) | 400 | متنهای استاندارد |
|
||||
| base | 1rem (16px) | 400 | متنهای اصلی |
|
||||
| lg | 1.125rem (18px) | 500 | زیرعنوانها |
|
||||
| xl | 1.25rem (20px) | 600 | عنوانهای صفحه |
|
||||
| 2xl | 1.5rem (24px) | 700 | عنوانهای اصلی |
|
||||
| 3xl | 1.875rem (30px) | 700 | Hero text |
|
||||
|
||||
## 📦 کارتها و کادرها
|
||||
|
||||
### استایل کارت
|
||||
- **Border Radius:** 0.75rem (12px)
|
||||
- **Border:** 1px solid #e5e7eb
|
||||
- **Shadow:** 0 1px 3px rgba(0, 0, 0, 0.05)
|
||||
- **Padding:** 1.25rem
|
||||
- **Background:** #ffffff
|
||||
|
||||
### استایل کارت statistic
|
||||
- **Border Radius:** 0.75rem (12px)
|
||||
- **Padding:** 1.25rem
|
||||
- **Title:** 0.875rem, weight 500, color #6b7280
|
||||
- **Value:** 1.5rem, weight 700, color #111827
|
||||
|
||||
## 🔘 دکمهها
|
||||
|
||||
### Primary Button
|
||||
- **Background:** #f59e0b
|
||||
- **Border:** #f59e0b
|
||||
- **Color:** #ffffff
|
||||
- **Border Radius:** 0.5rem (8px)
|
||||
- **Padding:** 0.625rem 1.25rem
|
||||
- **Font Size:** 0.875rem
|
||||
- **Hover:** #d97706, translateY(-1px), shadow
|
||||
|
||||
### Secondary Button
|
||||
- **Background:** #ffffff
|
||||
- **Border:** #d1d5db
|
||||
- **Color:** #374151
|
||||
- **Hover:** #f9fafb
|
||||
|
||||
## 📊 جداول
|
||||
|
||||
### Header
|
||||
- **Background:** #f9fafb
|
||||
- **Font Size:** 0.875rem
|
||||
- **Font Weight:** 600
|
||||
- **Text Transform:** uppercase
|
||||
- **Letter Spacing:** 0.025em
|
||||
- **Color:** #374151
|
||||
- **Padding:** 0.75rem 1rem
|
||||
|
||||
### Cell
|
||||
- **Padding:** 0.75rem 1rem
|
||||
- **Font Size:** 0.875rem
|
||||
- **Color:** #374151
|
||||
- **Border Bottom:** 1px solid #f3f4f6
|
||||
|
||||
### Hover
|
||||
- **Background:** #fffbeb
|
||||
|
||||
## 📱 رسپانسیو
|
||||
|
||||
### Breakpoints
|
||||
- **Mobile:** < 768px
|
||||
- **Tablet:** 768px - 1024px
|
||||
- **Desktop:** > 1024px
|
||||
|
||||
### Mobile Adjustments
|
||||
- **Font Size:** 13px
|
||||
- **Padding:** 0.75rem
|
||||
- **Grid:** 1 column
|
||||
- **Cards:** Full width
|
||||
|
||||
### Tablet Adjustments
|
||||
- **Grid:** 2 columns
|
||||
- **Padding:** 1rem
|
||||
|
||||
## 🎯 چیدوبندی (Layout)
|
||||
|
||||
### Container
|
||||
- **Max Width:** 1400px
|
||||
- **Padding:** 1.5rem
|
||||
- **Margin:** 0 auto
|
||||
|
||||
### Grid System
|
||||
- **Gap:** 1rem
|
||||
- **Columns:** auto-fit, minmax(240px, 1fr)
|
||||
|
||||
## 🌙 حالت تاریک (Dark Mode)
|
||||
|
||||
### در حال توسعه...
|
||||
- پسزمینه: #0f172a
|
||||
- متن: #f1f5f9
|
||||
- کارت: #1e293b
|
||||
- حاشیه: #334155
|
||||
|
||||
---
|
||||
|
||||
## 📋 پیادهسازی در Filament
|
||||
|
||||
```php
|
||||
// AdminPanelProvider.php
|
||||
->colors([
|
||||
'primary' => Color::Amber, // #f59e0b
|
||||
])
|
||||
->sidebarWidth('18rem')
|
||||
->maxContentWidth('xl')
|
||||
```
|
||||
|
||||
## 📋 پیادهسازی در WordPress
|
||||
|
||||
```css
|
||||
/* استفاده از متغیرهای CSS */
|
||||
:root {
|
||||
--ifnex-primary: #f59e0b;
|
||||
--ifnex-primary-dark: #d97706;
|
||||
--ifnex-success: #059669;
|
||||
--ifnex-danger: #dc2626;
|
||||
--ifnex-gray-900: #111827;
|
||||
--ifnex-gray-700: #374151;
|
||||
--ifnex-gray-500: #6b7280;
|
||||
--ifnex-gray-300: #d1d5db;
|
||||
--ifnex-gray-100: #f3f4f6;
|
||||
--ifnex-white: #ffffff;
|
||||
}
|
||||
```
|
||||
@ -552,6 +552,11 @@ IFNEX-Logistics/
|
||||
- ساخت دستور Artisan `ifnex:sync-wp-users` برای یکسازی کاربران وردپرس ↔ لاراول
|
||||
- تست زنده پلاگین وردپرس — همه APIها با موفقیت تست شدند
|
||||
- پاکسازی فایلهای تست و اضافی از ریشه پروژه
|
||||
- افزودن خروجی Excel برای تراکنشها و مرسولات در Filament
|
||||
- ساخت صفحه گزارشگیری مالی در Filament: خلاصه مالی، تراکنشها، مرسولات
|
||||
- ساخت Design System یکپارچه IFNEX برای استفاده در Filament و وردپرس
|
||||
- بهروزرسانی استایلهای Filament مطابق با Design System
|
||||
- بهروزرسانی استایلهای پلاگین وردپرس مطابق با Design System
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,384 +1,450 @@
|
||||
/**
|
||||
* IFNEX Bridge Styles
|
||||
* استایلهای پلاگین IFNEX Logistics Bridge
|
||||
* بر اساس IFNEX Design System
|
||||
*/
|
||||
|
||||
/* Wallet Balance */
|
||||
:root {
|
||||
--ifnex-primary: #f59e0b;
|
||||
--ifnex-primary-dark: #d97706;
|
||||
--ifnex-primary-light: #fbbf24;
|
||||
--ifnex-success: #059669;
|
||||
--ifnex-success-light: #d1fae5;
|
||||
--ifnex-danger: #dc2626;
|
||||
--ifnex-danger-light: #fee2e2;
|
||||
--ifnex-warning: #f59e0b;
|
||||
--ifnex-warning-light: #fef3c7;
|
||||
--ifnex-info: #2563eb;
|
||||
--ifnex-info-light: #dbeafe;
|
||||
--ifnex-gray-900: #111827;
|
||||
--ifnex-gray-700: #374151;
|
||||
--ifnex-gray-600: #4b5563;
|
||||
--ifnex-gray-500: #6b7280;
|
||||
--ifnex-gray-400: #9ca3af;
|
||||
--ifnex-gray-300: #d1d5db;
|
||||
--ifnex-gray-200: #e5e7eb;
|
||||
--ifnex-gray-100: #f3f4f6;
|
||||
--ifnex-gray-50: #f9fafb;
|
||||
--ifnex-white: #ffffff;
|
||||
--ifnex-font-family: 'Vazirmatn', 'IranYekan', ui-sans-serif, system-ui, sans-serif;
|
||||
--ifnex-radius-sm: 0.375rem;
|
||||
--ifnex-radius-md: 0.5rem;
|
||||
--ifnex-radius-lg: 0.75rem;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
GLOBAL
|
||||
============================================ */
|
||||
.ifnex-widget,
|
||||
.ifnex-tracking-container,
|
||||
.ifnex-tracking-result,
|
||||
.ifnex-transactions,
|
||||
.ifnex-wallet-balance {
|
||||
background: #f9fafb;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
margin: 15px 0;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
font-family: var(--ifnex-font-family) !important;
|
||||
direction: rtl !important;
|
||||
text-align: right !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
WALLET BALANCE
|
||||
============================================ */
|
||||
.ifnex-wallet-balance {
|
||||
background: var(--ifnex-white) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
padding: 1.25rem !important;
|
||||
margin: 1rem 0 !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-main {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e5e7eb;
|
||||
display: flex !important;
|
||||
justify-content: space-between !important;
|
||||
align-items: center !important;
|
||||
margin-bottom: 1rem !important;
|
||||
padding-bottom: 1rem !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-label {
|
||||
font-size: 14px;
|
||||
color: #6b7280;
|
||||
font-weight: 500;
|
||||
font-size: 0.875rem !important;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-amount {
|
||||
font-size: 24px;
|
||||
font-weight: 700;
|
||||
color: #059669;
|
||||
font-size: 1.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-details {
|
||||
margin-top: 10px;
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-details p {
|
||||
margin: 5px 0;
|
||||
font-size: 14px;
|
||||
color: #374151;
|
||||
margin: 0.5rem 0 !important;
|
||||
font-size: 0.875rem !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-details strong {
|
||||
color: #6b7280;
|
||||
margin-left: 8px;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
margin-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
.ifnex-wallet-frozen {
|
||||
color: #dc2626;
|
||||
font-weight: 600;
|
||||
margin-top: 10px;
|
||||
padding: 8px 12px;
|
||||
background: #fee2e2;
|
||||
border-radius: 6px;
|
||||
border-right: 3px solid #dc2626;
|
||||
color: var(--ifnex-danger) !important;
|
||||
font-weight: 600 !important;
|
||||
margin-top: 1rem !important;
|
||||
padding: 0.75rem 1rem !important;
|
||||
background: var(--ifnex-danger-light) !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
border-right: 3px solid var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
/* Transactions */
|
||||
/* ============================================
|
||||
TRANSACTIONS
|
||||
============================================ */
|
||||
.ifnex-transactions {
|
||||
margin: 15px 0;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
margin: 1rem 0 !important;
|
||||
}
|
||||
|
||||
.ifnex-transactions h3 {
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #f59e0b;
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin-bottom: 1rem !important;
|
||||
padding-bottom: 0.5rem !important;
|
||||
border-bottom: 2px solid var(--ifnex-primary) !important;
|
||||
}
|
||||
|
||||
.ifnex-transactions-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 0.75rem !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-item {
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 10px;
|
||||
padding: 16px;
|
||||
transition: all 0.2s ease;
|
||||
background: var(--ifnex-white) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
padding: 1rem !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-item:hover {
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
border-color: #f59e0b;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05) !important;
|
||||
border-color: var(--ifnex-primary-light) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 8px;
|
||||
display: flex !important;
|
||||
justify-content: space-between !important;
|
||||
align-items: center !important;
|
||||
margin-bottom: 0.5rem !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type {
|
||||
display: inline-block;
|
||||
padding: 4px 10px;
|
||||
border-radius: 6px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
text-transform: uppercase;
|
||||
background: #dbeafe;
|
||||
color: #1e40af;
|
||||
display: inline-block !important;
|
||||
padding: 0.25rem 0.75rem !important;
|
||||
border-radius: var(--ifnex-radius-sm) !important;
|
||||
font-size: 0.75rem !important;
|
||||
font-weight: 500 !important;
|
||||
text-transform: uppercase !important;
|
||||
background: var(--ifnex-info-light) !important;
|
||||
color: var(--ifnex-info) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.deposit {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.withdrawal {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
background: var(--ifnex-success-light) !important;
|
||||
color: var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.withdrawal,
|
||||
.ifnex-transaction-type.order_payment {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: var(--ifnex-danger-light) !important;
|
||||
color: var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-type.refund {
|
||||
background: #e0e7ff;
|
||||
color: #3730a3;
|
||||
background: var(--ifnex-info-light) !important;
|
||||
color: var(--ifnex-info) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
font-family: 'Vazirmatn', 'IranYekan', sans-serif;
|
||||
font-size: 1rem !important;
|
||||
font-weight: 700 !important;
|
||||
font-family: var(--ifnex-font-family) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount.positive {
|
||||
color: #059669;
|
||||
color: var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-amount.negative {
|
||||
color: #dc2626;
|
||||
color: var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-details {
|
||||
margin-top: 8px;
|
||||
margin-top: 0.5rem !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-description {
|
||||
color: #4b5563;
|
||||
font-size: 14px;
|
||||
margin: 0 0 6px 0;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
font-size: 0.875rem !important;
|
||||
margin: 0 0 0.5rem 0 !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-meta {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
display: flex !important;
|
||||
gap: 0.75rem !important;
|
||||
font-size: 0.75rem !important;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
font-size: 11px;
|
||||
display: inline-block !important;
|
||||
padding: 0.125rem 0.5rem !important;
|
||||
border-radius: var(--ifnex-radius-sm) !important;
|
||||
background: var(--ifnex-gray-100) !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
font-size: 0.75rem !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.completed {
|
||||
background: #d1fae5;
|
||||
color: #065f46;
|
||||
background: var(--ifnex-success-light) !important;
|
||||
color: var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.pending {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
background: var(--ifnex-warning-light) !important;
|
||||
color: #92400e !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-status.failed {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
background: var(--ifnex-danger-light) !important;
|
||||
color: var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-ref {
|
||||
margin-top: 6px;
|
||||
font-size: 12px;
|
||||
color: #6b7280;
|
||||
font-family: monospace;
|
||||
margin-top: 0.5rem !important;
|
||||
font-size: 0.75rem !important;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
font-family: monospace !important;
|
||||
}
|
||||
|
||||
/* Tracking Status */
|
||||
/* ============================================
|
||||
TRACKING FORM
|
||||
============================================ */
|
||||
.ifnex-tracking-container {
|
||||
max-width: 700px;
|
||||
margin: 20px auto;
|
||||
padding: 24px;
|
||||
background: #ffffff;
|
||||
border: 1px solid #e5e7eb;
|
||||
border-radius: 12px;
|
||||
font-family: inherit;
|
||||
direction: rtl;
|
||||
text-align: right;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
||||
max-width: 700px !important;
|
||||
margin: 1.5rem auto !important;
|
||||
padding: 1.5rem !important;
|
||||
background: var(--ifnex-white) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-container h2 {
|
||||
font-size: 20px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-bottom: 16px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 2px solid #f59e0b;
|
||||
font-size: 1.25rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin-bottom: 1rem !important;
|
||||
padding-bottom: 0.5rem !important;
|
||||
border-bottom: 2px solid var(--ifnex-primary) !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-form {
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: 1.5rem !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
display: flex !important;
|
||||
gap: 0.75rem !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group input {
|
||||
flex: 1;
|
||||
padding: 12px 16px;
|
||||
border: 1px solid #d1d5db;
|
||||
border-radius: 8px;
|
||||
font-size: 15px;
|
||||
font-family: inherit;
|
||||
transition: border-color 0.2s ease;
|
||||
flex: 1 !important;
|
||||
padding: 0.75rem 1rem !important;
|
||||
border: 1px solid var(--ifnex-gray-300) !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
font-size: 0.9375rem !important;
|
||||
font-family: var(--ifnex-font-family) !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group input:focus {
|
||||
outline: none;
|
||||
border-color: #f59e0b;
|
||||
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1);
|
||||
outline: none !important;
|
||||
border-color: var(--ifnex-primary) !important;
|
||||
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group button {
|
||||
padding: 12px 24px;
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
font-family: inherit;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0.75rem 1.5rem !important;
|
||||
background: var(--ifnex-primary) !important;
|
||||
color: var(--ifnex-white) !important;
|
||||
border: none !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
cursor: pointer !important;
|
||||
font-size: 0.9375rem !important;
|
||||
font-weight: 600 !important;
|
||||
font-family: var(--ifnex-font-family) !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group button:hover {
|
||||
background: #d97706;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
background: var(--ifnex-primary-dark) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: var(--ifnex-shadow-md) !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group button:disabled {
|
||||
background: #9ca3af;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
background: var(--ifnex-gray-400) !important;
|
||||
cursor: not-allowed !important;
|
||||
transform: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-result {
|
||||
margin-top: 20px;
|
||||
padding: 20px;
|
||||
background: #f9fafb;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #e5e7eb;
|
||||
margin-top: 1.5rem !important;
|
||||
padding: 1.25rem !important;
|
||||
background: var(--ifnex-gray-50) !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.ifnex-error {
|
||||
color: #dc2626;
|
||||
font-weight: 500;
|
||||
padding: 10px;
|
||||
background: #fee2e2;
|
||||
border-radius: 6px;
|
||||
border-right: 3px solid #dc2626;
|
||||
color: var(--ifnex-danger) !important;
|
||||
font-weight: 500 !important;
|
||||
padding: 0.75rem 1rem !important;
|
||||
background: var(--ifnex-danger-light) !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
border-right: 3px solid var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-status h3 {
|
||||
margin-top: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: #111827;
|
||||
margin-top: 0 !important;
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
.ifnex-status-badge {
|
||||
display: inline-block;
|
||||
padding: 6px 14px;
|
||||
background: #f59e0b;
|
||||
color: white;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 12px;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
display: inline-block !important;
|
||||
padding: 0.375rem 0.875rem !important;
|
||||
background: var(--ifnex-primary) !important;
|
||||
color: var(--ifnex-white) !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
margin-bottom: 0.75rem !important;
|
||||
font-weight: 600 !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.delivered {
|
||||
background: #059669;
|
||||
background: var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.failed {
|
||||
background: #dc2626;
|
||||
background: var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
.ifnex-status-badge.in_transit {
|
||||
background: #2563eb;
|
||||
background: var(--ifnex-info) !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details {
|
||||
margin-top: 12px;
|
||||
margin-top: 1rem !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details p {
|
||||
margin: 6px 0;
|
||||
font-size: 14px;
|
||||
color: #4b5563;
|
||||
margin: 0.5rem 0 !important;
|
||||
font-size: 0.875rem !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
}
|
||||
|
||||
.ifnex-tracking-details strong {
|
||||
color: #374151;
|
||||
margin-left: 8px;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
margin-left: 0.5rem !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline {
|
||||
margin-top: 20px;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
margin-top: 1.5rem !important;
|
||||
padding-top: 1rem !important;
|
||||
border-top: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: #111827;
|
||||
margin-bottom: 12px;
|
||||
font-size: 1rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin-bottom: 0.75rem !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
list-style: none !important;
|
||||
padding: 0 !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline li {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid #f3f4f6;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
font-size: 14px;
|
||||
padding: 0.75rem !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-100) !important;
|
||||
display: flex !important;
|
||||
gap: 0.75rem !important;
|
||||
align-items: flex-start !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline li:last-child {
|
||||
border-bottom: none;
|
||||
border-bottom: none !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline li strong {
|
||||
color: #f59e0b;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
min-width: 100px;
|
||||
color: var(--ifnex-primary) !important;
|
||||
font-weight: 600 !important;
|
||||
white-space: nowrap !important;
|
||||
min-width: 100px !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline li span {
|
||||
color: #4b5563;
|
||||
flex: 1;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
flex: 1 !important;
|
||||
}
|
||||
|
||||
.ifnex-timeline li small {
|
||||
color: #9ca3af;
|
||||
font-size: 12px;
|
||||
white-space: nowrap;
|
||||
color: var(--ifnex-gray-400) !important;
|
||||
font-size: 0.75rem !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
RESPONSIVE
|
||||
============================================ */
|
||||
@media (max-width: 768px) {
|
||||
.ifnex-tracking-container {
|
||||
max-width: 100% !important;
|
||||
padding: 1rem !important;
|
||||
margin: 1rem 0 !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group {
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.ifnex-form-group button {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.ifnex-balance-amount {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
|
||||
.ifnex-transaction-header {
|
||||
flex-direction: column !important;
|
||||
align-items: flex-start !important;
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1 +1 @@
|
||||
{"version":2,"defects":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":5,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":7,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":8,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":7,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":8,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":8},"times":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":0.052,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":0.05,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":0.008,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.005,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.064,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":0.096,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":0.059,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_invalid_discount_code":0.05,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_expired_discount_code":0.05,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_code_below_minimum_order_amount":0.05,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_calculates_fixed_discount_correctly":0.048,"Tests\\Feature\\Api\\PaymentControllerTest::it_redirects_to_gateway_for_payment":0.081,"Tests\\Feature\\Api\\PaymentControllerTest::it_validates_minimum_deposit_amount":0.059,"Tests\\Feature\\Api\\PaymentControllerTest::it_prevents_payment_for_frozen_wallet":0.049,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":0.073,"Tests\\Feature\\Api\\PaymentControllerTest::it_checks_transaction_status":0.062,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":0.007,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":0.007,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":0.002,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":0.001,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":0.006}}
|
||||
{"version":2,"defects":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":5,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":7,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":8,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":8,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":7,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":8,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":8,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":8,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":7,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":8},"times":{"Tests\\Feature\\Api\\PricingControllerTest::it_can_calculate_pricing_with_valid_data":0.058,"Tests\\Feature\\Api\\PricingControllerTest::it_returns_validation_errors_for_invalid_data":0.06,"Tests\\Feature\\Services\\PriceCalculatorServiceTest::it_calculates_price_correctly_for_standard_package":0.012,"Tests\\Unit\\ExampleTest::test_that_true_is_true":0.008,"Tests\\Feature\\ExampleTest::test_the_application_returns_a_successful_response":0.081,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_returns_active_discount_codes":0.109,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_validates_discount_code_successfully":0.112,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_invalid_discount_code":0.059,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_expired_discount_code":0.071,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_rejects_code_below_minimum_order_amount":0.059,"Tests\\Feature\\Api\\DiscountCodeControllerTest::it_calculates_fixed_discount_correctly":0.053,"Tests\\Feature\\Api\\PaymentControllerTest::it_redirects_to_gateway_for_payment":0.079,"Tests\\Feature\\Api\\PaymentControllerTest::it_validates_minimum_deposit_amount":0.054,"Tests\\Feature\\Api\\PaymentControllerTest::it_prevents_payment_for_frozen_wallet":0.053,"Tests\\Feature\\Api\\PaymentControllerTest::it_completes_mock_payment_successfully":0.093,"Tests\\Feature\\Api\\PaymentControllerTest::it_checks_transaction_status":0.057,"Tests\\Feature\\Services\\WalletServiceTest::it_creates_deposit_transaction":0.005,"Tests\\Feature\\Services\\WalletServiceTest::it_completes_deposit_and_updates_balance":0.01,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_deposit":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_manual_withdrawal":0.004,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_withdrawal_when_balance_is_insufficient":0.002,"Tests\\Feature\\Services\\WalletServiceTest::it_processes_order_payment":0.003,"Tests\\Feature\\Services\\WalletServiceTest::it_prevents_order_payment_when_balance_is_insufficient":0.001,"Tests\\Feature\\Services\\WalletServiceTest::it_fails_transaction":0.003}}
|
||||
113
04_Laravel/app/Exports/ShipmentsExport.php
Normal file
113
04_Laravel/app/Exports/ShipmentsExport.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\Shipment;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
|
||||
class ShipmentsExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize
|
||||
{
|
||||
protected $filters;
|
||||
|
||||
public function __construct(array $filters = [])
|
||||
{
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
public function query()
|
||||
{
|
||||
$query = Shipment::query()
|
||||
->with(['fromCountry', 'toCountry', 'carrierMappings', 'items'])
|
||||
->orderByDesc('created_at');
|
||||
|
||||
if (!empty($this->filters['status'])) {
|
||||
$query->where('status', $this->filters['status']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['type'])) {
|
||||
$query->where('type', $this->filters['type']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['direction'])) {
|
||||
$query->where('direction', $this->filters['direction']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['from_date'])) {
|
||||
$query->where('created_at', '>=', $this->filters['from_date']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['to_date'])) {
|
||||
$query->where('created_at', '<=', $this->filters['to_date']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'AWB No.',
|
||||
'جهت',
|
||||
'نوع',
|
||||
'وضعیت',
|
||||
'کشور مبدا',
|
||||
'کشور مقصد',
|
||||
'وزن واقعی (kg)',
|
||||
'وزن حجمی (kg)',
|
||||
'وزن قابل پرداخت (kg)',
|
||||
'قیمت حمل (درهم)',
|
||||
'خدمات اضافی (درهم)',
|
||||
'هزینه بستهبندی (ریال)',
|
||||
'دریافت داخلی (ریال)',
|
||||
'تحویل داخلی (ریال)',
|
||||
'هزینه انبار (ریال)',
|
||||
'تخفیف (ریال)',
|
||||
'هزینه کل (ریال)',
|
||||
'فرستنده',
|
||||
'تلفن فرستنده',
|
||||
'گیرنده',
|
||||
'تلفن گیرنده',
|
||||
'تاریخ ایجاد',
|
||||
];
|
||||
}
|
||||
|
||||
public function map($shipment): array
|
||||
{
|
||||
return [
|
||||
$shipment->awb_no,
|
||||
$shipment->direction->label(),
|
||||
$shipment->type->label(),
|
||||
$shipment->status->label(),
|
||||
$shipment->fromCountry->name ?? '-',
|
||||
$shipment->toCountry->name ?? '-',
|
||||
$shipment->weight ?? 0,
|
||||
$shipment->volumetric_weight ?? 0,
|
||||
$shipment->chargeable_weight ?? 0,
|
||||
$shipment->shipping_price ?? 0,
|
||||
$shipment->extra_service ?? 0,
|
||||
$shipment->packing_cost ?? 0,
|
||||
$shipment->domestic_pickup ?? 0,
|
||||
$shipment->domestic_delivery ?? 0,
|
||||
$shipment->warehousing_cost ?? 0,
|
||||
$shipment->discount ?? 0,
|
||||
$shipment->total_fee ?? 0,
|
||||
$shipment->sender_name ?? '-',
|
||||
$shipment->sender_phone ?? '-',
|
||||
$shipment->receiver_name ?? '-',
|
||||
$shipment->receiver_phone ?? '-',
|
||||
$shipment->created_at?->format('Y/m/d H:i'),
|
||||
];
|
||||
}
|
||||
|
||||
public function styles(Worksheet $sheet)
|
||||
{
|
||||
return [
|
||||
1 => ['font' => ['bold' => true, 'size' => 12]],
|
||||
];
|
||||
}
|
||||
}
|
||||
99
04_Laravel/app/Exports/WalletTransactionsExport.php
Normal file
99
04_Laravel/app/Exports/WalletTransactionsExport.php
Normal file
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace App\Exports;
|
||||
|
||||
use App\Models\WalletTransaction;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithStyles;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class WalletTransactionsExport implements FromQuery, WithHeadings, WithMapping, WithStyles, ShouldAutoSize
|
||||
{
|
||||
protected $filters;
|
||||
|
||||
public function __construct(array $filters = [])
|
||||
{
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
public function query()
|
||||
{
|
||||
$query = WalletTransaction::query()
|
||||
->with(['wallet.user', 'creator', 'approver'])
|
||||
->orderByDesc('created_at');
|
||||
|
||||
if (!empty($this->filters['type'])) {
|
||||
$query->where('type', $this->filters['type']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['status'])) {
|
||||
$query->where('status', $this->filters['status']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['gateway'])) {
|
||||
$query->where('gateway', $this->filters['gateway']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['from_date'])) {
|
||||
$query->where('created_at', '>=', $this->filters['from_date']);
|
||||
}
|
||||
|
||||
if (!empty($this->filters['to_date'])) {
|
||||
$query->where('created_at', '<=', $this->filters['to_date']);
|
||||
}
|
||||
|
||||
return $query;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'شناسه',
|
||||
'کاربر',
|
||||
'ایمیل',
|
||||
'مبلغ (ریال)',
|
||||
'نوع',
|
||||
'وضعیت',
|
||||
'درگاه',
|
||||
'کد پیگیری',
|
||||
'توضیحات',
|
||||
'یادداشت ادمین',
|
||||
'موجودی قبل',
|
||||
'موجودی بعد',
|
||||
'تاریخ ایجاد',
|
||||
'تایید کننده',
|
||||
];
|
||||
}
|
||||
|
||||
public function map($transaction): array
|
||||
{
|
||||
return [
|
||||
$transaction->id,
|
||||
$transaction->wallet->user->name ?? 'نامشخص',
|
||||
$transaction->wallet->user->email ?? 'نامشخص',
|
||||
$transaction->amount,
|
||||
$transaction->type->label(),
|
||||
$transaction->status->label(),
|
||||
$transaction->gateway?->label() ?? '-',
|
||||
$transaction->gateway_reference_id ?? '-',
|
||||
$transaction->description ?? '-',
|
||||
$transaction->admin_notes ?? '-',
|
||||
$transaction->balance_before ?? 0,
|
||||
$transaction->balance_after ?? 0,
|
||||
$transaction->created_at?->format('Y/m/d H:i'),
|
||||
$transaction->approver?->name ?? '-',
|
||||
];
|
||||
}
|
||||
|
||||
public function styles(Worksheet $sheet)
|
||||
{
|
||||
return [
|
||||
// First row as bold text.
|
||||
1 => ['font' => ['bold' => true, 'size' => 12]],
|
||||
];
|
||||
}
|
||||
}
|
||||
278
04_Laravel/app/Filament/Pages/Reports/FinancialReport.php
Normal file
278
04_Laravel/app/Filament/Pages/Reports/FinancialReport.php
Normal file
@ -0,0 +1,278 @@
|
||||
<?php
|
||||
|
||||
namespace App\Filament\Pages\Reports;
|
||||
|
||||
use App\Exports\ShipmentsExport;
|
||||
use App\Exports\WalletTransactionsExport;
|
||||
use Filament\Forms;
|
||||
use Filament\Forms\Form;
|
||||
use Filament\Pages\Page;
|
||||
use Filament\Notifications\Notification;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class FinancialReport extends Page
|
||||
{
|
||||
protected static ?string $navigationIcon = 'heroicon-o-chart-bar';
|
||||
protected static ?string $navigationLabel = 'گزارش مالی';
|
||||
protected static ?string $navigationGroup = 'مالی';
|
||||
protected static ?int $navigationSort = 5;
|
||||
protected static ?string $slug = 'financial-report';
|
||||
protected static string $view = 'filament.pages.reports.financial-report';
|
||||
|
||||
public ?array $data = [];
|
||||
public ?array $reportData = null;
|
||||
|
||||
public function mount(): void
|
||||
{
|
||||
$this->form->fill();
|
||||
}
|
||||
|
||||
public function form(Form $form): Form
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
Forms\Components\Section::make('فیلترهای گزارش')
|
||||
->schema([
|
||||
Forms\Components\Select::make('report_type')
|
||||
->label('نوع گزارش')
|
||||
->options([
|
||||
'transactions' => 'تراکنشهای کیف پول',
|
||||
'shipments' => 'مرسولات',
|
||||
'financial_summary' => 'خلاصه مالی',
|
||||
])
|
||||
->required()
|
||||
->reactive()
|
||||
->default('transactions'),
|
||||
|
||||
Forms\Components\DatePicker::make('from_date')
|
||||
->label('از تاریخ')
|
||||
->required()
|
||||
->default(now()->subMonth()),
|
||||
|
||||
Forms\Components\DatePicker::make('to_date')
|
||||
->label('تا تاریخ')
|
||||
->required()
|
||||
->default(now()),
|
||||
|
||||
Forms\Components\Select::make('transaction_type')
|
||||
->label('نوع تراکنش')
|
||||
->options([
|
||||
'deposit' => 'واریزی',
|
||||
'withdrawal' => 'برداشت',
|
||||
'order_payment' => 'پرداخت سفارش',
|
||||
'refund' => 'بازگشت وجه',
|
||||
])
|
||||
->visible(fn ($get) => $get('report_type') === 'transactions')
|
||||
->placeholder('همه'),
|
||||
|
||||
Forms\Components\Select::make('shipment_status')
|
||||
->label('وضعیت مرسوله')
|
||||
->options([
|
||||
'processed' => 'ثبت شده',
|
||||
'picked_up' => 'تحویل به پست',
|
||||
'in_transit' => 'در حال حمل',
|
||||
'out_for_delivery' => 'آماده تحویل',
|
||||
'delivered' => 'تحویل داده شده',
|
||||
'failed' => 'ناموفق',
|
||||
'returned' => 'بازگشته',
|
||||
])
|
||||
->visible(fn ($get) => $get('report_type') === 'shipments')
|
||||
->placeholder('همه'),
|
||||
])
|
||||
->columns(2),
|
||||
|
||||
Forms\Components\Section::make('عملیات')
|
||||
->schema([
|
||||
Forms\Components\Actions::make([
|
||||
Forms\Components\Actions\Action::make('generate')
|
||||
->label('تولید گزارش')
|
||||
->icon('heroicon-o-eye')
|
||||
->color('primary')
|
||||
->action('generateReport'),
|
||||
|
||||
Forms\Components\Actions\Action::make('export_excel')
|
||||
->label('خروجی Excel')
|
||||
->icon('heroicon-o-arrow-down-tray')
|
||||
->color('success')
|
||||
->action('exportExcel')
|
||||
->visible(fn ($get) => $get('report_type') !== 'financial_summary'),
|
||||
])
|
||||
->fullWidth(),
|
||||
]),
|
||||
])
|
||||
->statePath('data');
|
||||
}
|
||||
|
||||
public function generateReport(): void
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$type = $this->data['report_type'];
|
||||
$fromDate = $this->data['from_date'];
|
||||
$toDate = $this->data['to_date'];
|
||||
|
||||
switch ($type) {
|
||||
case 'transactions':
|
||||
$this->generateTransactionsReport($fromDate, $toDate);
|
||||
break;
|
||||
case 'shipments':
|
||||
$this->generateShipmentsReport($fromDate, $toDate);
|
||||
break;
|
||||
case 'financial_summary':
|
||||
$this->generateFinancialSummary($fromDate, $toDate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private function generateTransactionsReport($fromDate, $toDate): void
|
||||
{
|
||||
$query = DB::table('wallet_transactions')
|
||||
->join('wallets', 'wallet_transactions.wallet_id', '=', 'wallets.id')
|
||||
->join('users', 'wallets.user_id', '=', 'users.id')
|
||||
->select(
|
||||
'wallet_transactions.id',
|
||||
'users.name as user_name',
|
||||
'users.email as user_email',
|
||||
'wallet_transactions.amount',
|
||||
'wallet_transactions.type',
|
||||
'wallet_transactions.status',
|
||||
'wallet_transactions.gateway',
|
||||
'wallet_transactions.description',
|
||||
'wallet_transactions.created_at'
|
||||
)
|
||||
->whereBetween('wallet_transactions.created_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->orderByDesc('wallet_transactions.created_at');
|
||||
|
||||
if (!empty($this->data['transaction_type'])) {
|
||||
$query->where('wallet_transactions.type', $this->data['transaction_type']);
|
||||
}
|
||||
|
||||
$this->reportData = [
|
||||
'type' => 'transactions',
|
||||
'data' => $query->get(),
|
||||
'summary' => [
|
||||
'total_count' => $query->count(),
|
||||
'total_amount' => $query->sum('amount'),
|
||||
'deposits' => $query->where('type', 'deposit')->sum('amount'),
|
||||
'withdrawals' => $query->whereIn('type', ['withdrawal', 'order_payment'])->sum('amount'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function generateShipmentsReport($fromDate, $toDate): void
|
||||
{
|
||||
$query = DB::table('shipments')
|
||||
->join('countries as from_country', 'shipments.from_country_id', '=', 'from_country.id')
|
||||
->join('countries as to_country', 'shipments.to_country_id', '=', 'to_country.id')
|
||||
->select(
|
||||
'shipments.awb_no',
|
||||
'shipments.direction',
|
||||
'shipments.type',
|
||||
'shipments.status',
|
||||
'from_country.name as from_country',
|
||||
'to_country.name as to_country',
|
||||
'shipments.weight',
|
||||
'shipments.chargeable_weight',
|
||||
'shipments.shipping_price',
|
||||
'shipments.total_fee',
|
||||
'shipments.sender_name',
|
||||
'shipments.receiver_name',
|
||||
'shipments.created_at'
|
||||
)
|
||||
->whereBetween('shipments.created_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->orderByDesc('shipments.created_at');
|
||||
|
||||
if (!empty($this->data['shipment_status'])) {
|
||||
$query->where('shipments.status', $this->data['shipment_status']);
|
||||
}
|
||||
|
||||
$this->reportData = [
|
||||
'type' => 'shipments',
|
||||
'data' => $query->get(),
|
||||
'summary' => [
|
||||
'total_count' => $query->count(),
|
||||
'total_fee' => $query->sum('total_fee'),
|
||||
'total_weight' => $query->sum('chargeable_weight'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
private function generateFinancialSummary($fromDate, $toDate): void
|
||||
{
|
||||
// Total deposits
|
||||
$deposits = DB::table('wallet_transactions')
|
||||
->where('type', 'deposit')
|
||||
->where('status', 'completed')
|
||||
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->sum('amount');
|
||||
|
||||
// Total withdrawals/order payments
|
||||
$withdrawals = DB::table('wallet_transactions')
|
||||
->whereIn('type', ['withdrawal', 'order_payment'])
|
||||
->where('status', 'completed')
|
||||
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->sum('amount');
|
||||
|
||||
// Total shipments revenue
|
||||
$shipmentsRevenue = DB::table('shipments')
|
||||
->whereBetween('created_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->sum('total_fee');
|
||||
|
||||
// Total discount codes used
|
||||
$discounts = DB::table('discount_codes')
|
||||
->where('is_active', true)
|
||||
->whereBetween('updated_at', [$fromDate, $toDate . ' 23:59:59'])
|
||||
->sum('used_count');
|
||||
|
||||
// Wallet balances
|
||||
$totalBalance = DB::table('wallets')->sum('balance');
|
||||
$totalDeposited = DB::table('wallets')->sum('total_deposited');
|
||||
$totalWithdrawn = DB::table('wallets')->sum('total_withdrawn');
|
||||
|
||||
$this->reportData = [
|
||||
'type' => 'financial_summary',
|
||||
'summary' => [
|
||||
'deposits' => $deposits,
|
||||
'withdrawals' => abs($withdrawals),
|
||||
'shipments_revenue' => $shipmentsRevenue,
|
||||
'discounts_used' => $discounts,
|
||||
'total_balance' => $totalBalance,
|
||||
'total_deposited' => $totalDeposited,
|
||||
'total_withdrawn' => $totalWithdrawn,
|
||||
'net_profit' => $shipmentsRevenue - $withdrawals,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function exportExcel(): \Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
{
|
||||
$this->validate();
|
||||
|
||||
$type = $this->data['report_type'];
|
||||
$filters = [
|
||||
'from_date' => $this->data['from_date'],
|
||||
'to_date' => $this->data['to_date'],
|
||||
];
|
||||
|
||||
if ($type === 'transactions') {
|
||||
$filters['type'] = $this->data['transaction_type'] ?? null;
|
||||
$export = new WalletTransactionsExport($filters);
|
||||
$fileName = 'transactions_' . now()->format('Y-m-d_H-i') . '.xlsx';
|
||||
} elseif ($type === 'shipments') {
|
||||
$filters['status'] = $this->data['shipment_status'] ?? null;
|
||||
$export = new ShipmentsExport($filters);
|
||||
$fileName = 'shipments_' . now()->format('Y-m-d_H-i') . '.xlsx';
|
||||
} else {
|
||||
Notification::make()
|
||||
->title('خطا')
|
||||
->body('برای خلاصه مالی خروجی Excel موجود نیست.')
|
||||
->danger()
|
||||
->send();
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
return Excel::download($export, $fileName);
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,8 @@ use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use App\Exports\ShipmentsExport;
|
||||
use Filament\Tables\Actions\ExportAction;
|
||||
|
||||
class ShipmentResource extends Resource
|
||||
{
|
||||
@ -196,6 +198,18 @@ class ShipmentResource extends Resource
|
||||
Tables\Actions\ViewAction::make(),
|
||||
Tables\Actions\EditAction::make(),
|
||||
])
|
||||
->headerActions([
|
||||
ExportAction::make()
|
||||
->label('خروجی Excel')
|
||||
->icon('heroicon-o-arrow-down-tray')
|
||||
->color('success')
|
||||
->export(fn ($query) => new ShipmentsExport([
|
||||
'status' => request()->input('filters.status'),
|
||||
'type' => request()->input('filters.type'),
|
||||
'direction' => request()->input('filters.direction'),
|
||||
]))
|
||||
->fileName('shipments_' . now()->format('Y-m-d_H-i')),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
|
||||
@ -12,6 +12,9 @@ use Filament\Forms\Form;
|
||||
use Filament\Resources\Resource;
|
||||
use Filament\Tables;
|
||||
use Filament\Tables\Table;
|
||||
use App\Exports\WalletTransactionsExport;
|
||||
use Filament\Tables\Actions\ExportAction;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class WalletTransactionResource extends Resource
|
||||
{
|
||||
@ -133,6 +136,18 @@ class WalletTransactionResource extends Resource
|
||||
->actions([
|
||||
Tables\Actions\ViewAction::make(),
|
||||
])
|
||||
->headerActions([
|
||||
ExportAction::make()
|
||||
->label('خروجی Excel')
|
||||
->icon('heroicon-o-arrow-down-tray')
|
||||
->color('success')
|
||||
->export(fn ($query) => new WalletTransactionsExport([
|
||||
'type' => request()->input('filters.type'),
|
||||
'status' => request()->input('filters.status'),
|
||||
'gateway' => request()->input('filters.gateway'),
|
||||
]))
|
||||
->fileName('transactions_' . now()->format('Y-m-d_H-i')),
|
||||
])
|
||||
->bulkActions([
|
||||
Tables\Actions\BulkActionGroup::make([
|
||||
Tables\Actions\DeleteBulkAction::make(),
|
||||
|
||||
@ -29,6 +29,7 @@ class AdminPanelProvider extends PanelProvider
|
||||
->discoverPages(in: app_path('Filament/Pages'), for: 'App\\Filament\\Pages')
|
||||
->pages([
|
||||
Dashboard::class,
|
||||
\App\Filament\Pages\Reports\FinancialReport::class,
|
||||
])
|
||||
->discoverWidgets(in: app_path('Filament/Widgets'), for: 'App\\Filament\\Widgets')
|
||||
->widgets([
|
||||
|
||||
@ -1,8 +1,71 @@
|
||||
@import 'tailwindcss';
|
||||
:root {
|
||||
/* IFNEX Brand Colors */
|
||||
--ifnex-primary: #f59e0b;
|
||||
--ifnex-primary-dark: #d97706;
|
||||
--ifnex-primary-light: #fbbf24;
|
||||
--ifnex-success: #059669;
|
||||
--ifnex-success-light: #d1fae5;
|
||||
--ifnex-danger: #dc2626;
|
||||
--ifnex-danger-light: #fee2e2;
|
||||
--ifnex-warning: #f59e0b;
|
||||
--ifnex-warning-light: #fef3c7;
|
||||
--ifnex-info: #2563eb;
|
||||
--ifnex-info-light: #dbeafe;
|
||||
|
||||
/* Custom IFNEX Filament Theme */
|
||||
/* Neutral Colors */
|
||||
--ifnex-gray-900: #111827;
|
||||
--ifnex-gray-700: #374151;
|
||||
--ifnex-gray-600: #4b5563;
|
||||
--ifnex-gray-500: #6b7280;
|
||||
--ifnex-gray-400: #9ca3af;
|
||||
--ifnex-gray-300: #d1d5db;
|
||||
--ifnex-gray-200: #e5e7eb;
|
||||
--ifnex-gray-100: #f3f4f6;
|
||||
--ifnex-gray-50: #f9fafb;
|
||||
--ifnex-white: #ffffff;
|
||||
|
||||
/* Sidebar Styling */
|
||||
/* Typography */
|
||||
--ifnex-font-family: 'Vazirmatn', 'IranYekan', ui-sans-serif, system-ui, sans-serif;
|
||||
--ifnex-font-size-base: 14px;
|
||||
--ifnex-line-height: 1.6;
|
||||
|
||||
/* Spacing */
|
||||
--ifnex-spacing-xs: 0.25rem;
|
||||
--ifnex-spacing-sm: 0.5rem;
|
||||
--ifnex-spacing-md: 1rem;
|
||||
--ifnex-spacing-lg: 1.5rem;
|
||||
--ifnex-spacing-xl: 2rem;
|
||||
--ifnex-spacing-2xl: 3rem;
|
||||
|
||||
/* Border Radius */
|
||||
--ifnex-radius-sm: 0.375rem;
|
||||
--ifnex-radius-md: 0.5rem;
|
||||
--ifnex-radius-lg: 0.75rem;
|
||||
|
||||
/* Shadows */
|
||||
--ifnex-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
||||
--ifnex-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
|
||||
--ifnex-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
|
||||
|
||||
/* Transitions */
|
||||
--ifnex-transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* Global Reset */
|
||||
* {
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--ifnex-font-family) !important;
|
||||
font-size: var(--ifnex-font-size-base) !important;
|
||||
line-height: var(--ifnex-line-height) !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SIDEBAR
|
||||
============================================ */
|
||||
.fi-sidebar {
|
||||
background: linear-gradient(180deg, #1a1a2e 0%, #16213e 100%) !important;
|
||||
border-left: 1px solid rgba(245, 158, 11, 0.2) !important;
|
||||
@ -18,39 +81,32 @@
|
||||
padding: 0.75rem !important;
|
||||
}
|
||||
|
||||
/* Navigation Groups */
|
||||
.fi-sidebar-nav-group {
|
||||
margin-bottom: 0.5rem !important;
|
||||
border-radius: 0.5rem !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-group-header {
|
||||
background: rgba(245, 158, 11, 0.08) !important;
|
||||
border-bottom: 1px solid rgba(245, 158, 11, 0.1) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
color: rgba(255, 255, 255, 0.7) !important;
|
||||
font-weight: 500 !important;
|
||||
font-size: 0.75rem !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 0.05em !important;
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-group-header:hover {
|
||||
background: rgba(245, 158, 11, 0.15) !important;
|
||||
color: var(--ifnex-primary-light) !important;
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-group-item {
|
||||
padding: 0.5rem 0.75rem !important;
|
||||
font-weight: 500 !important;
|
||||
color: rgba(255, 255, 255, 0.7) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-group-item:hover {
|
||||
color: #fbbf24 !important;
|
||||
}
|
||||
|
||||
/* Navigation Items */
|
||||
.fi-sidebar-nav-item {
|
||||
margin: 0.15rem 0 !important;
|
||||
border-radius: 0.5rem !important;
|
||||
transition: all 0.2s ease !important;
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
position: relative !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
@ -63,7 +119,7 @@
|
||||
transform: translateY(-50%) !important;
|
||||
width: 3px !important;
|
||||
height: 0 !important;
|
||||
background: #fbbf24 !important;
|
||||
background: var(--ifnex-primary) !important;
|
||||
border-radius: 3px 0 0 3px !important;
|
||||
transition: height 0.2s ease !important;
|
||||
}
|
||||
@ -83,11 +139,10 @@
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-item.active .fi-sidebar-nav-item-label {
|
||||
color: #fbbf24 !important;
|
||||
color: var(--ifnex-primary-light) !important;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
|
||||
/* Icons */
|
||||
.fi-sidebar-nav-item-icon {
|
||||
color: rgba(255, 255, 255, 0.6) !important;
|
||||
transition: color 0.2s ease !important;
|
||||
@ -95,193 +150,417 @@
|
||||
|
||||
.fi-sidebar-nav-item:hover .fi-sidebar-nav-item-icon,
|
||||
.fi-sidebar-nav-item.active .fi-sidebar-nav-item-icon {
|
||||
color: #fbbf24 !important;
|
||||
color: var(--ifnex-primary) !important;
|
||||
}
|
||||
|
||||
/* Labels */
|
||||
.fi-sidebar-nav-item-label {
|
||||
color: rgba(255, 255, 255, 0.85) !important;
|
||||
font-size: 0.875rem !important;
|
||||
transition: color 0.2s ease !important;
|
||||
}
|
||||
|
||||
.fi-sidebar-nav-group-item {
|
||||
color: rgba(255, 255, 255, 0.5) !important;
|
||||
font-size: 0.75rem !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 0.05em !important;
|
||||
/* ============================================
|
||||
MAIN CONTENT
|
||||
============================================ */
|
||||
.fi-main {
|
||||
max-width: 1400px !important;
|
||||
margin: 0 auto !important;
|
||||
padding: var(--ifnex-spacing-lg) !important;
|
||||
}
|
||||
|
||||
/* Badges */
|
||||
.fi-badge {
|
||||
font-weight: 600 !important;
|
||||
border-radius: 9999px !important;
|
||||
font-size: 0.75rem !important;
|
||||
padding: 0.125rem 0.5rem !important;
|
||||
@media (max-width: 1024px) {
|
||||
.fi-main {
|
||||
padding: var(--ifnex-spacing-md) !important;
|
||||
max-width: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cards and Panels */
|
||||
@media (max-width: 768px) {
|
||||
.fi-main {
|
||||
padding: var(--ifnex-spacing-sm) !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
PAGE HEADER
|
||||
============================================ */
|
||||
.fi-page-header {
|
||||
margin-bottom: var(--ifnex-spacing-lg) !important;
|
||||
padding-bottom: var(--ifnex-spacing-md) !important;
|
||||
border-bottom: 2px solid var(--ifnex-primary) !important;
|
||||
}
|
||||
|
||||
.fi-page-header h1 {
|
||||
font-size: 1.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.fi-page-header h1 {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
CARDS
|
||||
============================================ */
|
||||
.fi-card {
|
||||
border-radius: 0.75rem !important;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05) !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.fi-card:hover {
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.fi-btn {
|
||||
border-radius: 0.5rem !important;
|
||||
font-weight: 500 !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.fi-btn-primary {
|
||||
background: #f59e0b !important;
|
||||
border-color: #f59e0b !important;
|
||||
}
|
||||
|
||||
.fi-btn-primary:hover {
|
||||
background: #d97706 !important;
|
||||
border-color: #d97706 !important;
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: 0 4px 6px -1px rgba(245, 158, 11, 0.3) !important;
|
||||
}
|
||||
|
||||
/* Tables */
|
||||
.fi-ta-table {
|
||||
border-radius: 0.75rem !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
box-shadow: var(--ifnex-shadow-sm) !important;
|
||||
margin-bottom: var(--ifnex-spacing-md) !important;
|
||||
overflow: hidden !important;
|
||||
background: var(--ifnex-white) !important;
|
||||
}
|
||||
|
||||
.fi-card-header {
|
||||
background: var(--ifnex-gray-50) !important;
|
||||
padding: 1rem 1.25rem !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.fi-card-header h2 {
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
.fi-card-body {
|
||||
padding: 1.25rem !important;
|
||||
background: var(--ifnex-white) !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
STATS WIDGET
|
||||
============================================ */
|
||||
.fi-wi-stats-overview {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)) !important;
|
||||
gap: var(--ifnex-spacing-md) !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card {
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
padding: 1.25rem !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
background: var(--ifnex-white) !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card:hover {
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: var(--ifnex-shadow-md) !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card h3 {
|
||||
font-size: 0.875rem !important;
|
||||
font-weight: 500 !important;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
margin: 0 0 0.5rem 0 !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card p {
|
||||
font-size: 1.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin: 0 !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.fi-wi-stats-overview {
|
||||
grid-template-columns: 1fr !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card p {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
TABLES
|
||||
============================================ */
|
||||
.fi-ta-table {
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
overflow: hidden !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.fi-ta-header-cell {
|
||||
background: #f9fafb !important;
|
||||
background: var(--ifnex-gray-50) !important;
|
||||
font-weight: 600 !important;
|
||||
color: #374151 !important;
|
||||
font-size: 0.75rem !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
font-size: 0.875rem !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 0.05em !important;
|
||||
letter-spacing: 0.025em !important;
|
||||
padding: 0.75rem 1rem !important;
|
||||
}
|
||||
|
||||
.fi-ta-row {
|
||||
transition: background-color 0.15s ease !important;
|
||||
.fi-ta-cell {
|
||||
padding: 0.75rem 1rem !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
font-size: 0.875rem !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-100) !important;
|
||||
}
|
||||
|
||||
.fi-ta-row:hover {
|
||||
background-color: #fffbeb !important;
|
||||
}
|
||||
|
||||
/* Forms */
|
||||
.fi-input {
|
||||
border-radius: 0.5rem !important;
|
||||
border-color: #d1d5db !important;
|
||||
transition: all 0.2s ease !important;
|
||||
/* ============================================
|
||||
FORMS
|
||||
============================================ */
|
||||
.fi-input,
|
||||
.fi-select,
|
||||
.fi-textarea {
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
border-color: var(--ifnex-gray-300) !important;
|
||||
font-size: 0.875rem !important;
|
||||
padding: 0.625rem 0.875rem !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
width: 100% !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
.fi-input:focus {
|
||||
border-color: #fbbf24 !important;
|
||||
.fi-input:focus,
|
||||
.fi-select:focus,
|
||||
.fi-textarea:focus {
|
||||
border-color: var(--ifnex-primary) !important;
|
||||
box-shadow: 0 0 0 3px rgba(245, 158, 11, 0.1) !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.fi-select {
|
||||
border-radius: 0.5rem !important;
|
||||
.fi-label {
|
||||
font-weight: 500 !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
margin-bottom: 0.375rem !important;
|
||||
display: block !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
/* Widgets */
|
||||
.fi-wi-stats-overview {
|
||||
gap: 1rem !important;
|
||||
/* ============================================
|
||||
BUTTONS
|
||||
============================================ */
|
||||
.fi-btn {
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
font-weight: 500 !important;
|
||||
font-size: 0.875rem !important;
|
||||
padding: 0.625rem 1.25rem !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
display: inline-flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 0.5rem !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card {
|
||||
border-radius: 0.75rem !important;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
transition: all 0.2s ease !important;
|
||||
.fi-btn-primary {
|
||||
background: var(--ifnex-primary) !important;
|
||||
border-color: var(--ifnex-primary) !important;
|
||||
color: var(--ifnex-white) !important;
|
||||
}
|
||||
|
||||
.fi-wi-stats-overview-card:hover {
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1) !important;
|
||||
.fi-btn-primary:hover {
|
||||
background: var(--ifnex-primary-dark) !important;
|
||||
border-color: var(--ifnex-primary-dark) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
box-shadow: var(--ifnex-shadow-md) !important;
|
||||
}
|
||||
|
||||
/* Dashboard */
|
||||
.fi-page-header {
|
||||
border-bottom: 2px solid #fbbf24 !important;
|
||||
margin-bottom: 1.5rem !important;
|
||||
padding-bottom: 1rem !important;
|
||||
/* ============================================
|
||||
REPORTS PAGE
|
||||
============================================ */
|
||||
.ifnex-report-page {
|
||||
max-width: 1200px !important;
|
||||
margin: 0 auto !important;
|
||||
padding: var(--ifnex-spacing-lg) !important;
|
||||
}
|
||||
|
||||
/* Top Navigation */
|
||||
.fi-topbar {
|
||||
border-bottom: 1px solid #f3f4f6 !important;
|
||||
background: #ffffff !important;
|
||||
.ifnex-report-container {
|
||||
background: var(--ifnex-white) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
padding: var(--ifnex-spacing-lg) !important;
|
||||
box-shadow: var(--ifnex-shadow-sm) !important;
|
||||
}
|
||||
|
||||
/* Notifications */
|
||||
.fi-notification {
|
||||
border-radius: 0.75rem !important;
|
||||
border-right: 4px solid #fbbf24 !important;
|
||||
}
|
||||
|
||||
/* Modals */
|
||||
.fi-modal {
|
||||
border-radius: 0.75rem !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
/* Dropdowns */
|
||||
.fi-dropdown {
|
||||
border-radius: 0.5rem !important;
|
||||
border: 1px solid #e5e7eb !important;
|
||||
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1) !important;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.fi-tabs {
|
||||
border-bottom: 2px solid #f3f4f6 !important;
|
||||
}
|
||||
|
||||
.fi-tab {
|
||||
border-bottom: 2px solid transparent !important;
|
||||
margin-bottom: -2px !important;
|
||||
transition: all 0.2s ease !important;
|
||||
}
|
||||
|
||||
.fi-tab:hover {
|
||||
border-bottom-color: #fbbf24 !important;
|
||||
color: #d97706 !important;
|
||||
}
|
||||
|
||||
.fi-tab.active {
|
||||
border-bottom-color: #fbbf24 !important;
|
||||
color: #d97706 !important;
|
||||
.section-title {
|
||||
font-size: 1.125rem !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
margin: var(--ifnex-spacing-lg) 0 var(--ifnex-spacing-md) 0 !important;
|
||||
padding-bottom: var(--ifnex-spacing-sm) !important;
|
||||
border-bottom: 2px solid var(--ifnex-primary) !important;
|
||||
}
|
||||
|
||||
/* Scrollbar */
|
||||
.report-summary-grid {
|
||||
display: grid !important;
|
||||
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) !important;
|
||||
gap: var(--ifnex-spacing-md) !important;
|
||||
margin: var(--ifnex-spacing-md) 0 !important;
|
||||
}
|
||||
|
||||
.report-card {
|
||||
background: var(--ifnex-white) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
padding: 1.25rem !important;
|
||||
text-align: center !important;
|
||||
transition: var(--ifnex-transition) !important;
|
||||
}
|
||||
|
||||
.report-card:hover {
|
||||
box-shadow: var(--ifnex-shadow-sm) !important;
|
||||
transform: translateY(-1px) !important;
|
||||
}
|
||||
|
||||
.report-card-title {
|
||||
font-size: 0.875rem !important;
|
||||
font-weight: 500 !important;
|
||||
color: var(--ifnex-gray-500) !important;
|
||||
margin-bottom: var(--ifnex-spacing-sm) !important;
|
||||
}
|
||||
|
||||
.report-card-value {
|
||||
font-size: 1.5rem !important;
|
||||
font-weight: 700 !important;
|
||||
color: var(--ifnex-gray-900) !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.report-summary-grid {
|
||||
grid-template-columns: 1fr !important;
|
||||
}
|
||||
|
||||
.report-card-value {
|
||||
font-size: 1.25rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
REPORT TABLES
|
||||
============================================ */
|
||||
.report-table-container {
|
||||
overflow-x: auto !important;
|
||||
margin-top: var(--ifnex-spacing-lg) !important;
|
||||
border-radius: var(--ifnex-radius-lg) !important;
|
||||
border: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.report-table {
|
||||
width: 100% !important;
|
||||
border-collapse: collapse !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.report-table thead {
|
||||
background: var(--ifnex-gray-50) !important;
|
||||
}
|
||||
|
||||
.report-table th {
|
||||
padding: 0.75rem 1rem !important;
|
||||
text-align: right !important;
|
||||
font-weight: 600 !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
font-size: 0.875rem !important;
|
||||
text-transform: uppercase !important;
|
||||
letter-spacing: 0.025em !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-200) !important;
|
||||
}
|
||||
|
||||
.report-table td {
|
||||
padding: 0.75rem 1rem !important;
|
||||
color: var(--ifnex-gray-700) !important;
|
||||
border-bottom: 1px solid var(--ifnex-gray-100) !important;
|
||||
}
|
||||
|
||||
.report-table tbody tr:hover {
|
||||
background-color: #fffbeb !important;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.report-table {
|
||||
font-size: 0.8125rem !important;
|
||||
}
|
||||
|
||||
.report-table th,
|
||||
.report-table td {
|
||||
padding: 0.5rem !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
ALERTS
|
||||
============================================ */
|
||||
.fi-alert {
|
||||
border-radius: var(--ifnex-radius-md) !important;
|
||||
padding: var(--ifnex-spacing-md) var(--ifnex-spacing-lg) !important;
|
||||
margin-bottom: var(--ifnex-spacing-md) !important;
|
||||
font-size: 0.875rem !important;
|
||||
}
|
||||
|
||||
.fi-alert-success {
|
||||
background: var(--ifnex-success-light) !important;
|
||||
color: var(--ifnex-success) !important;
|
||||
border-right: 4px solid var(--ifnex-success) !important;
|
||||
}
|
||||
|
||||
.fi-alert-danger {
|
||||
background: var(--ifnex-danger-light) !important;
|
||||
color: var(--ifnex-danger) !important;
|
||||
border-right: 4px solid var(--ifnex-danger) !important;
|
||||
}
|
||||
|
||||
/* ============================================
|
||||
SCROLLBAR
|
||||
============================================ */
|
||||
::-webkit-scrollbar {
|
||||
width: 8px !important;
|
||||
height: 8px !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-track {
|
||||
background: #f1f5f9 !important;
|
||||
background: var(--ifnex-gray-100) !important;
|
||||
border-radius: var(--ifnex-radius-sm) !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #cbd5e1 !important;
|
||||
border-radius: 4px !important;
|
||||
background: var(--ifnex-gray-300) !important;
|
||||
border-radius: var(--ifnex-radius-sm) !important;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #94a3b8 !important;
|
||||
background: var(--ifnex-gray-400) !important;
|
||||
}
|
||||
|
||||
/* Dark mode adjustments */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.fi-sidebar {
|
||||
background: linear-gradient(180deg, #0f172a 0%, #1e293b 100%) !important;
|
||||
}
|
||||
}
|
||||
/* ============================================
|
||||
TEXT COLORS
|
||||
============================================ */
|
||||
.text-gray-900 { color: var(--ifnex-gray-900) !important; }
|
||||
.text-gray-700 { color: var(--ifnex-gray-700) !important; }
|
||||
.text-gray-600 { color: var(--ifnex-gray-600) !important; }
|
||||
.text-gray-500 { color: var(--ifnex-gray-500) !important; }
|
||||
.text-white { color: var(--ifnex-white) !important; }
|
||||
.text-green-700 { color: var(--ifnex-success) !important; }
|
||||
.text-red-700 { color: var(--ifnex-danger) !important; }
|
||||
.text-blue-700 { color: var(--ifnex-info) !important; }
|
||||
|
||||
/* ============================================
|
||||
BACKGROUNDS
|
||||
============================================ */
|
||||
.bg-white { background-color: var(--ifnex-white) !important; }
|
||||
.bg-gray-50 { background-color: var(--ifnex-gray-50) !important; }
|
||||
.bg-gray-100 { background-color: var(--ifnex-gray-100) !important; }
|
||||
.bg-green-50 { background-color: var(--ifnex-success-light) !important; }
|
||||
.bg-red-50 { background-color: var(--ifnex-danger-light) !important; }
|
||||
.bg-yellow-50 { background-color: var(--ifnex-warning-light) !important; }
|
||||
.bg-blue-50 { background-color: var(--ifnex-info-light) !important; }
|
||||
|
||||
/* ============================================
|
||||
BORDERS
|
||||
============================================ */
|
||||
.border-gray-200 { border-color: var(--ifnex-gray-200) !important; }
|
||||
.border-gray-300 { border-color: var(--ifnex-gray-300) !important; }
|
||||
|
||||
@ -0,0 +1,164 @@
|
||||
<x-filament-panels::page>
|
||||
<div class="ifnex-report-page">
|
||||
{{ $this->form }}
|
||||
|
||||
@if ($reportData)
|
||||
<div class="ifnex-report-container">
|
||||
<h2 class="section-title">نتیجه گزارش</h2>
|
||||
|
||||
@if ($reportData['type'] === 'financial_summary')
|
||||
<div class="report-summary-grid">
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">کل واریزیها</p>
|
||||
<p class="report-card-value text-green-700">
|
||||
{{ number_format($reportData['summary']['deposits']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">کل برداشتها</p>
|
||||
<p class="report-card-value text-red-700">
|
||||
{{ number_format($reportData['summary']['withdrawals']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">درآمد از مرسولات</p>
|
||||
<p class="report-card-value text-blue-700">
|
||||
{{ number_format($reportData['summary']['shipments_revenue']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">سود خالص</p>
|
||||
<p class="report-card-value text-purple-700">
|
||||
{{ number_format($reportData['summary']['net_profit']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="report-summary-grid">
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">موجودی کل کیف پولها</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_balance']) }} ریال</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">کل واریزیهای ثبت شده</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_deposited']) }} ریال</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">کل برداشتهای ثبت شده</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_withdrawn']) }} ریال</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($reportData['summary']['discounts_used'] > 0)
|
||||
<div class="report-card" style="background: var(--ifnex-warning-light); border-color: var(--ifnex-primary-light);">
|
||||
<p class="report-card-title">تخفیفهای استفاده شده</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['discounts_used']) }} بار</p>
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if ($reportData['type'] === 'transactions' && $reportData['data']->count() > 0)
|
||||
<div class="report-summary-grid">
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">تعداد تراکنشها</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_count']) }}</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">مجموع واریزیها</p>
|
||||
<p class="report-card-value text-green-700">
|
||||
{{ number_format($reportData['summary']['deposits']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">مجموع برداشتها</p>
|
||||
<p class="report-card-value text-red-700">
|
||||
{{ number_format($reportData['summary']['withdrawals']) }} ریال
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="report-table-container">
|
||||
<table class="report-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>شناسه</th>
|
||||
<th>کاربر</th>
|
||||
<th>مبلغ</th>
|
||||
<th>نوع</th>
|
||||
<th>وضعیت</th>
|
||||
<th>تاریخ</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($reportData['data'] as $item)
|
||||
<tr>
|
||||
<td>{{ $item->id }}</td>
|
||||
<td>{{ $item->user_name }}</td>
|
||||
<td class="{{ $item->amount >= 0 ? 'text-green-700' : 'text-red-700' }}" style="font-weight: 600;">
|
||||
{{ number_format($item->amount) }} ریال
|
||||
</td>
|
||||
<td>{{ $item->type }}</td>
|
||||
<td>{{ $item->status }}</td>
|
||||
<td>{{ \Morilog\Jalali\Jalalian::fromCarbon(\Carbon\Carbon::parse($item->created_at))->format('Y/m/d H:i') }}</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($reportData['type'] === 'shipments' && $reportData['data']->count() > 0)
|
||||
<div class="report-summary-grid">
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">تعداد مرسولات</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_count']) }}</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">هزینه کل مرسولات</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_fee']) }} ریال</p>
|
||||
</div>
|
||||
<div class="report-card">
|
||||
<p class="report-card-title">وزن کل (kg)</p>
|
||||
<p class="report-card-value">{{ number_format($reportData['summary']['total_weight'], 2) }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="report-table-container">
|
||||
<table class="report-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>AWB</th>
|
||||
<th>جهت</th>
|
||||
<th>نوع</th>
|
||||
<th>وضعیت</th>
|
||||
<th>مبدا</th>
|
||||
<th>مقصد</th>
|
||||
<th>هزینه کل</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach ($reportData['data'] as $item)
|
||||
<tr>
|
||||
<td style="font-family: monospace;">{{ $item->awb_no }}</td>
|
||||
<td>{{ $item->direction }}</td>
|
||||
<td>{{ $item->type }}</td>
|
||||
<td>{{ $item->status }}</td>
|
||||
<td>{{ $item->from_country }}</td>
|
||||
<td>{{ $item->to_country }}</td>
|
||||
<td style="font-weight: 600;">{{ number_format($item->total_fee) }} ریال</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($reportData['data']->count() === 0)
|
||||
<div class="report-card" style="text-align: center; padding: 3rem;">
|
||||
<p style="color: var(--ifnex-gray-500); font-size: 1rem;">هیچ دادهای برای این بازه زمانی یافت نشد.</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</x-filament-panels::page>
|
||||
Loading…
Reference in New Issue
Block a user