schema([ Forms\Components\Section::make('جزئیات تغییر نرخ') ->schema([ Forms\Components\TextInput::make('currency_from') ->label('ارز مبدأ') ->disabled(), Forms\Components\TextInput::make('currency_to') ->label('ارز مقصد') ->disabled(), Forms\Components\TextInput::make('old_rate') ->label('نرخ قبلی') ->disabled() ->suffix('ریال'), Forms\Components\TextInput::make('new_rate') ->label('نرخ جدید') ->disabled() ->suffix('ریال'), Forms\Components\TextInput::make('change_percent') ->label('درصد تغییر') ->disabled() ->suffix('%'), Forms\Components\TextInput::make('change_source') ->label('منبع تغییر') ->disabled(), Forms\Components\Select::make('changed_by') ->label('توسط') ->relationship('changedBy', 'name') ->disabled(), Forms\Components\Textarea::make('notes') ->label('یادداشت') ->disabled() ->columnSpanFull(), ])->columns(2), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\TextColumn::make('id') ->label('شناسه') ->sortable() ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('currency_pair') ->label('جفت ارز') ->state(fn ($record) => "{$record->currency_from} → {$record->currency_to}") ->badge() ->color('info'), Tables\Columns\TextColumn::make('old_rate') ->label('نرخ قبلی') ->numeric(0) ->suffix(' ریال') ->color('gray'), Tables\Columns\TextColumn::make('new_rate') ->label('نرخ جدید') ->numeric(0) ->suffix(' ریال') ->weight('bold') ->color('primary'), Tables\Columns\TextColumn::make('change_percent') ->label('تغییر') ->state(fn ($record) => $record->change_percent !== null ? number_format($record->change_percent, 2) . '%' : '—') ->badge() ->color(fn ($record) => match(true) { $record->change_percent > 0 => 'danger', // افزایش قیمت = قرمز $record->change_percent < 0 => 'success', // کاهش قیمت = سبز default => 'gray', }) ->icon(fn ($record) => match(true) { $record->change_percent > 0 => 'heroicon-m-arrow-trending-up', $record->change_percent < 0 => 'heroicon-m-arrow-trending-down', default => null, }), Tables\Columns\TextColumn::make('change_source') ->label('منبع') ->badge() ->formatStateUsing(fn ($state) => $state === 'api' ? 'API خودکار' : 'دستی') ->color(fn ($state) => $state === 'api' ? 'info' : 'warning') ->icon(fn ($state) => $state === 'api' ? 'heroicon-m-cog-6-tooth' : 'heroicon-m-pencil-square'), Tables\Columns\TextColumn::make('changedBy.name') ->label('توسط') ->state(fn ($record) => $record->changedBy?->name ?? ($record->change_source === 'api' ? 'سیستم' : '—')) ->icon('heroicon-m-user'), Tables\Columns\TextColumn::make('created_at') ->label('تاریخ تغییر') ->dateTime('Y/m/d H:i') ->sortable(), ]) ->filters([ Tables\Filters\SelectFilter::make('change_source') ->label('منبع') ->options([ 'api' => 'API خودکار', 'manual' => 'دستی', ]), Tables\Filters\SelectFilter::make('currency_pair') ->label('جفت ارز') ->options([ 'AED_IRR' => 'AED → IRR', 'USD_IRR' => 'USD → IRR', ]) ->query(function ($query, array $data) { if (!$data['value']) return $query; [$from, $to] = explode('_', $data['value']); return $query->where('currency_from', $from) ->where('currency_to', $to); }), Tables\Filters\Filter::make('created_at') ->form([ Forms\Components\DatePicker::make('from')->label('از تاریخ'), Forms\Components\DatePicker::make('until')->label('تا تاریخ'), ]) ->query(function ($query, array $data) { return $query ->when($data['from'], fn ($q, $d) => $q->whereDate('created_at', '>=', $d)) ->when($data['until'], fn ($q, $d) => $q->whereDate('created_at', '<=', $d)); }), ]) ->actions([ Tables\Actions\ViewAction::make()->label('جزئیات'), ]) ->headerActions([ // 🎯 دکمه اصلی: تنظیم نرخ جدید به صورت دستی Action::make('setNewRate') ->label('تنظیم نرخ جدید') ->icon('heroicon-o-pencil-square') ->color('warning') ->form([ Forms\Components\Select::make('currency_pair') ->label('جفت ارز') ->required() ->options([ 'AED_IRR' => 'درهم به ریال (AED → IRR)', 'USD_IRR' => 'دلار به ریال (USD → IRR)', ]) ->default('AED_IRR'), Forms\Components\TextInput::make('new_rate') ->label('نرخ جدید (ریال)') ->required() ->numeric() ->minValue(1) ->prefix('ریال') ->helperText(fn (callable $get) => 'نرخ فعلی: ' . number_format(self::getCurrentRateForPair($get('currency_pair'))) . ' ریال' ), Forms\Components\Textarea::make('notes') ->label('یادداشت (اختیاری)') ->placeholder('دلیل تغییر نرخ...') ->maxLength(500), ]) ->action(function (array $data) { [$from, $to] = explode('_', $data['currency_pair']); $service = app(ExchangeRateService::class); $service->setRate( from: $from, to: $to, newRate: (float) $data['new_rate'], userId: Auth::id(), notes: $data['notes'] ?? null ); Notification::make() ->title('نرخ ارز با موفقیت به‌روز شد') ->body("نرخ {$from}/{$to} به " . number_format($data['new_rate']) . " ریال تغییر یافت") ->success() ->send(); }), // 🔄 دکمه آپدیت از API Action::make('refreshFromApi') ->label('آپدیت از API') ->icon('heroicon-o-arrow-path') ->color('info') ->requiresConfirmation() ->modalHeading('آپدیت نرخ از API') ->modalDescription('آیا مطمئن هستید که می‌خواهید نرخ ارز را از API به‌روزرسانی کنید؟') ->action(function () { try { \Artisan::call('ifnex:update-rates'); Notification::make() ->title('نرخ ارز از API به‌روزرسانی شد') ->success() ->send(); } catch (\Throwable $e) { Notification::make() ->title('خطا در به‌روزرسانی') ->body($e->getMessage()) ->danger() ->send(); } }), ]) ->bulkActions([]) ->defaultSort('created_at', 'desc') ->poll('60s'); // هر ۶۰ ثانیه خودکار refresh می‌شود } // متد کمکی برای نمایش نرخ فعلی در فرم protected static function getCurrentRateForPair(?string $pair): float { if (!$pair) return 0; [$from, $to] = explode('_', $pair); return app(ExchangeRateService::class)->getCurrentRate($from, $to); } public static function getRelations(): array { return []; } public static function getPages(): array { return [ 'index' => Pages\ListExchangeRateHistories::route('/'), 'view' => Pages\ViewExchangeRateHistory::route('/{record}'), ]; } // فقط admin و super_admin دسترسی دارند public static function canViewAny(): bool { $user = Auth::user(); return $user && $user->hasAnyRole(['super_admin', 'admin']); } public static function canCreate(): bool { return false; // ایجاد دستی از فرم ممکن نیست، فقط از Action } public static function canEdit($record): bool { return false; } public static function canDelete($record): bool { return false; } }