count(); } public static function getNavigationBadgeColor(): ?string { return 'warning'; } public static function form(Form $form): Form { return $form ->schema([ Forms\Components\Section::make('基本資訊') ->schema([ Forms\Components\TextInput::make('name') ->label('姓名') ->disabled(), Forms\Components\TextInput::make('email') ->label('Email') ->disabled(), Forms\Components\TextInput::make('phone') ->label('電話') ->disabled(), Forms\Components\Placeholder::make('company_label') ->label('組織類型') ->content(fn (ContactSubmission $record): string => FormOptions::getCompanyTypeLabel($record->company) ?? '-' ), Forms\Components\Placeholder::make('country_region_label') ->label('國家/地區') ->content(fn (ContactSubmission $record): string => $record->country_region ?? '-' ), Forms\Components\Placeholder::make('industry_label') ->label('產業別') ->content(fn (ContactSubmission $record): string => FormOptions::getIndustryLabel($record->industry) ?? '-' ), Forms\Components\Placeholder::make('topic_label') ->label('洽詢主題') ->content(fn (ContactSubmission $record): string => FormOptions::getTopicLabel($record->topic) ?? '-' ), Forms\Components\Placeholder::make('status') ->label('狀態') ->content(fn (ContactSubmission $record): string => match ($record->status) { 'new' => '🔵 新訊息', 'handled' => '✅ 已處理', 'spam' => '🚫 垃圾訊息', default => $record->status, }), ]) ->columns(2), Forms\Components\Section::make('訊息內容') ->schema([ Forms\Components\Textarea::make('message') ->label('訊息') ->rows(8) ->disabled() ->columnSpanFull(), ]), Forms\Components\Section::make('系統資訊') ->schema([ Forms\Components\Placeholder::make('created_at') ->label('送出時間') ->content(fn (ContactSubmission $record): string => $record->created_at->format('Y-m-d H:i:s') ), Forms\Components\Placeholder::make('handled_at') ->label('處理時間') ->content(fn (ContactSubmission $record): string => $record->handled_at?->format('Y-m-d H:i:s') ?? '-' ), Forms\Components\Placeholder::make('form_source') ->label('表單來源') ->content(fn (ContactSubmission $record): string => $record->form_source ?? '-' ), Forms\Components\KeyValue::make('meta') ->label('元資料 (Meta)') ->disabled() ->columnSpanFull(), ]) ->columns(2) ->collapsible() ->collapsed(), ]); } public static function table(Table $table): Table { return $table ->columns([ Tables\Columns\BadgeColumn::make('status') ->label('狀態') ->formatStateUsing(fn (string $state): string => match ($state) { 'new' => '新訊息', 'handled' => '已處理', 'spam' => '垃圾訊息', default => $state, }) ->colors([ 'info' => 'new', 'success' => 'handled', 'danger' => 'spam', ]) ->sortable(), Tables\Columns\TextColumn::make('name') ->label('姓名') ->searchable() ->sortable() ->limit(30), Tables\Columns\TextColumn::make('email') ->label('Email') ->searchable() ->copyable() ->limit(40), Tables\Columns\TextColumn::make('topic') ->label('主題') ->formatStateUsing(fn (?string $state): string => FormOptions::getTopicLabel($state) ?? '-' ) ->badge() ->color('primary') ->sortable(), Tables\Columns\TextColumn::make('company') ->label('組織類型') ->formatStateUsing(fn (?string $state): string => FormOptions::getCompanyTypeLabel($state) ?? '-' ) ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('country_region') ->label('國家') ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('industry') ->label('產業') ->formatStateUsing(fn (?string $state): string => FormOptions::getIndustryLabel($state) ?? '-' ) ->toggleable(isToggledHiddenByDefault: true), Tables\Columns\TextColumn::make('created_at') ->label('送出時間') ->dateTime('Y-m-d H:i') ->sortable(), Tables\Columns\TextColumn::make('handled_at') ->label('處理時間') ->dateTime('Y-m-d H:i') ->sortable() ->toggleable(isToggledHiddenByDefault: true), ]) ->filters([ Tables\Filters\SelectFilter::make('status') ->label('狀態') ->options([ 'new' => '新訊息', 'handled' => '已處理', 'spam' => '垃圾訊息', ]), Tables\Filters\SelectFilter::make('topic') ->label('洽詢主題') ->options(FormOptions::getTopics()), Tables\Filters\SelectFilter::make('company') ->label('組織類型') ->options(FormOptions::getCompanyTypes()), Tables\Filters\SelectFilter::make('industry') ->label('產業別') ->options(FormOptions::getIndustries()), Tables\Filters\Filter::make('created_at') ->form([ Forms\Components\DatePicker::make('created_from') ->label('送出日期從'), Forms\Components\DatePicker::make('created_until') ->label('送出日期至'), ]) ->query(function (Builder $query, array $data): Builder { return $query ->when( $data['created_from'], fn (Builder $query, $date): Builder => $query->whereDate('created_at', '>=', $date) ) ->when( $data['created_until'], fn (Builder $query, $date): Builder => $query->whereDate('created_at', '<=', $date) ); }), ]) ->actions([ Tables\Actions\ViewAction::make(), Tables\Actions\Action::make('markAsHandled') ->label('標記為已處理') ->icon('heroicon-o-check-circle') ->color('success') ->requiresConfirmation() ->visible(fn (ContactSubmission $record): bool => $record->status !== 'handled') ->action(fn (ContactSubmission $record) => $record->markAsHandled()) ->successNotificationTitle('已標記為已處理'), Tables\Actions\Action::make('markAsSpam') ->label('標記為垃圾訊息') ->icon('heroicon-o-x-circle') ->color('danger') ->requiresConfirmation() ->visible(fn (ContactSubmission $record): bool => $record->status !== 'spam') ->action(fn (ContactSubmission $record) => $record->markAsSpam()) ->successNotificationTitle('已標記為垃圾訊息'), ]) ->bulkActions([ Tables\Actions\BulkActionGroup::make([ Tables\Actions\BulkAction::make('markAsHandled') ->label('批次標記為已處理') ->icon('heroicon-o-check-circle') ->color('success') ->requiresConfirmation() ->action(fn (Collection $records) => $records->each->markAsHandled()) ->deselectRecordsAfterCompletion() ->successNotificationTitle('已批次標記為已處理'), Tables\Actions\BulkAction::make('markAsSpam') ->label('批次標記為垃圾訊息') ->icon('heroicon-o-x-circle') ->color('danger') ->requiresConfirmation() ->action(fn (Collection $records) => $records->each->markAsSpam()) ->deselectRecordsAfterCompletion() ->successNotificationTitle('已批次標記為垃圾訊息'), Tables\Actions\DeleteBulkAction::make(), ]), ]) ->defaultSort('created_at', 'desc'); } public static function getRelations(): array { return []; } public static function getPages(): array { return [ 'index' => Pages\ListContactSubmissions::route('/'), 'view' => Pages\ViewContactSubmission::route('/{record}'), ]; } public static function canCreate(): bool { return false; } }