diff --git a/app/Filament/Components/Forms/PostForm.php b/app/Filament/Components/Forms/PostForm.php index 6220fab..f22e89e 100644 --- a/app/Filament/Components/Forms/PostForm.php +++ b/app/Filament/Components/Forms/PostForm.php @@ -113,14 +113,12 @@ class PostForm ->helperText('Активируйте для публикации в указанное время'), DateTimePicker::make('publish_setting.publish_at') ->label('Дата и время публикации') - ->native(false) ->displayFormat('d/m/Y H:i') ->seconds(false) - ->minutesStep(15) ->helperText('Выберите дату и время публикации') ->required(fn (Forms\Get $get) => $get('publish_setting.publish_after')) ->disabled(fn (Forms\Get $get) => !$get('publish_setting.publish_after')) - ->minDate(now()) + ->native(true) ->maxDate(now()->addMonth()), ]), ]), diff --git a/app/Filament/Resources/PostResource/Pages/CreatePost.php b/app/Filament/Resources/PostResource/Pages/CreatePost.php index 5b2d412..9f973bb 100644 --- a/app/Filament/Resources/PostResource/Pages/CreatePost.php +++ b/app/Filament/Resources/PostResource/Pages/CreatePost.php @@ -41,7 +41,7 @@ class CreatePost extends CreateRecord protected function processPostData(array $data): array { - return (new PostDataProcessor())->process($data); + return (new PostDataProcessor())->process($data, 'create'); } protected function afterCreate(): void diff --git a/app/Filament/Resources/PostResource/Pages/EditPost.php b/app/Filament/Resources/PostResource/Pages/EditPost.php index 7a190c3..de31a58 100644 --- a/app/Filament/Resources/PostResource/Pages/EditPost.php +++ b/app/Filament/Resources/PostResource/Pages/EditPost.php @@ -49,7 +49,7 @@ class EditPost extends EditRecord protected function processPostData(array $data): array { - return (new PostDataProcessor())->process($data); + return (new PostDataProcessor())->process($data, 'edit'); } protected function afterSave(): void diff --git a/app/Http/Controllers/ClientPostController.php b/app/Http/Controllers/ClientPostController.php index 884ddcd..7f5d46b 100644 --- a/app/Http/Controllers/ClientPostController.php +++ b/app/Http/Controllers/ClientPostController.php @@ -68,10 +68,12 @@ class ClientPostController extends Controller return $query->withAnyTags($slugsArray); }) ->orderBy('publish_at', $request->input('sort', 'desc')) - ->paginate(6) - ->withQueryString()); + ->paginate(9) + ->withQueryString() + ); }); + $categories = Cache::remember('categories', now()->addHours(48), function () { return CategoryResource::collection(Category::has('posts')->get()); }); diff --git a/app/Jobs/ImportApiDataPost.php b/app/Jobs/ImportApiDataPost.php index 532d8e5..dd45604 100644 --- a/app/Jobs/ImportApiDataPost.php +++ b/app/Jobs/ImportApiDataPost.php @@ -32,13 +32,13 @@ class ImportApiDataPost implements ShouldQueue { try { // Получаем первую страницу данных - $response = Http::get('https://crawdad-fresh-bream.ngrok-free.app/api/posts')->object(); + $response = Http::get(env('TRANSFER_PROXY_URL') . '/api/posts')->object(); $last_page = $response->last_page; Log::info('Last page: ' . $last_page); // Проходим по всем страницам for ($page = 1; $page <= $last_page; $page++) { - $response = Http::get("https://crawdad-fresh-bream.ngrok-free.app/api/posts?page=$page")->object(); + $response = Http::get(env('TRANSFER_PROXY_URL') . "/api/posts?page=$page")->object(); $results = $response->data; // Обрабатываем каждую запись @@ -70,6 +70,8 @@ class ImportApiDataPost implements ShouldQueue // Обработка контента поста $content = strip_tags($post->DETAIL_TEXT, ''); + + $readingTime = $this->calculateReadingTime($content); $contentData = [ [ 'type' => 'paragraph', @@ -83,22 +85,25 @@ class ImportApiDataPost implements ShouldQueue $slug = $this->generateSlug($post->NAME); // Создание нового поста - Post::create([ - 'id' => $post->ID, - 'title' => $post->NAME, - 'slug' => $slug, - 'preview_text' => strip_tags($post->PREVIEW_TEXT), - 'authors' => ['Без автора'], - 'content' => $contentData, // Преобразуем в JSON - 'status' => 'published', - 'images' => $imagePaths, // Сохраняем пути к изображениям - 'search_data' => $content, // Преобразуем в JSON - 'reading_time' => 2, - 'user_id' => 1, - 'publish_at' => $post->DATE_CREATE, - 'created_at' => $post->DATE_CREATE, - 'updated_at' => $post->DATE_CREATE, - ]); + Post::firstOrCreate( + ['id' => $post->ID], // Условие поиска по ID + [ + 'title' => $post->NAME, + 'slug' => $slug, + 'preview_text' => strip_tags($post->PREVIEW_TEXT), + 'authors' => ['Без автора'], + 'content' => $contentData, // Преобразуем в JSON + 'status' => 'published', + 'images' => $imagePaths, // Сохраняем пути к изображениям + 'preview' => $imagePaths[0], + 'search_data' => strip_tags($content), // Преобразуем в JSON + 'reading_time' => $readingTime, + 'user_id' => 1, + 'publish_at' => $post->DATE_CREATE, + 'created_at' => $post->DATE_CREATE, + 'updated_at' => $post->DATE_CREATE, + ] + ); } catch (\Exception $e) { Log::error('Error importing post ID: ' . $post->ID . ' - ' . $e->getMessage()); } @@ -109,7 +114,7 @@ class ImportApiDataPost implements ShouldQueue } } - private function generateSlug($name) + private function generateSlug($name): string { $slug = Str::slug($name); $originalSlug = $slug; @@ -123,4 +128,11 @@ class ImportApiDataPost implements ShouldQueue return $slug; } + private function calculateReadingTime(string $text): int + { + $wordCount = str_word_count($text, 0, "АаБбВвГгДдЕеЁёЖжЗзИиЙйКкЛлМмНнОоПпРрСсТтУуФфХхЦцЧчШшЩщЪъЫыЬьЭэЮюЯя"); + $wordsPerMinute = 120; // Средняя скорость чтения + return max(1, round($wordCount / $wordsPerMinute)); + } + } diff --git a/app/Services/App/Seo/SeoPageProvider.php b/app/Services/App/Seo/SeoPageProvider.php index 51e3ca1..16d41b0 100644 --- a/app/Services/App/Seo/SeoPageProvider.php +++ b/app/Services/App/Seo/SeoPageProvider.php @@ -14,7 +14,7 @@ class SeoPageProvider { return $model->seo?->toArray(); } - public function getSeoForCurrentPage(): ?array + public function getSeoForCurrentPage(): array|null { $path = $this->getCurrentPath(); @@ -23,8 +23,11 @@ class SeoPageProvider now()->addHours(1), fn() => Page::where('path', $path)->first() ); + if ($page) { + return $page->seo->toArray(); + } - return $page->seo?->toArray(); + return null; } private function getCurrentPath(): string diff --git a/app/Services/Filament/Domain/Posts/PostDataProcessor.php b/app/Services/Filament/Domain/Posts/PostDataProcessor.php index 3d5b747..425d82f 100644 --- a/app/Services/Filament/Domain/Posts/PostDataProcessor.php +++ b/app/Services/Filament/Domain/Posts/PostDataProcessor.php @@ -14,7 +14,7 @@ class PostDataProcessor * @param array $data * @return array */ - public function process(array $data): array + public function process(array $data, $operation): array { // Удаляем ненужные данные unset($data['publication']); @@ -23,7 +23,14 @@ class PostDataProcessor $data['preview_text'] = $this->setPreviewText($data); // Устанавливаем время публикации - $data['publish_at'] = $this->setPublishDateTime($data['publish_setting'], $data['status']); + if ($data['publish_setting']['publish_after'] === true) { + $data['publish_at'] = $this->setPublishDateTimeInFuture($data['publish_setting']); + } + + if (($data['status'] === PostStatus::PUBLISHED->value || PostStatus::PUBLISHED) && $operation === 'create') { + $data['publish_at'] = $this->setPublishDateTime(); + } + unset($data['publish_setting']); // Генерируем данные для поиска @@ -63,21 +70,17 @@ class PostDataProcessor * @param string $status * @return Carbon|null */ - private function setPublishDateTime(array $publishSetting, $status): ?Carbon + private function setPublishDateTime(): ?Carbon + { + return Carbon::now(); + } + + private function setPublishDateTimeInFuture(array $publishSetting): ?Carbon { if ($publishSetting['publish_after'] === true) { return Carbon::parse($publishSetting['publish_at']); } - if ($status === PostStatus::PUBLISHED->value) { - return Carbon::now(); - } - - if ($status === PostStatus::PUBLISHED) { - return Carbon::now(); - } - - return null; } diff --git a/app/Services/Filament/Traits/SeoGenerate.php b/app/Services/Filament/Traits/SeoGenerate.php index 0abf548..c264de2 100644 --- a/app/Services/Filament/Traits/SeoGenerate.php +++ b/app/Services/Filament/Traits/SeoGenerate.php @@ -9,20 +9,21 @@ trait SeoGenerate { public function createSeo($record): void { - $record->seo()->create($this->generateSeo($record)); + $seo = $this->generateSeoData($record); + $record->seo()->create($seo); } public function updateSeo($record): void { if ($record->seo()->exists()) { - $record->seo()->update($this->generateSeo($record)); + $record->seo()->update($this->generateSeoData($record)); } else { $this->createSeo($record); } } - private function generateSeo($record) { + private function generateSeoData($record) { return app(SeoGeneratorService::class)->generate([ 'title' => $record->title, 'content' => $record instanceof SeoDescriptionInterface diff --git a/resources/js/Pages/Client/Posts/Index.vue b/resources/js/Pages/Client/Posts/Index.vue index b92c3e2..628f6d0 100644 --- a/resources/js/Pages/Client/Posts/Index.vue +++ b/resources/js/Pages/Client/Posts/Index.vue @@ -115,7 +115,7 @@ export default { - + diff --git a/resources/js/componentss/shared/paginate/BasicPagination.vue b/resources/js/componentss/shared/paginate/BasicPagination.vue index 0629550..8e0eb93 100644 --- a/resources/js/componentss/shared/paginate/BasicPagination.vue +++ b/resources/js/componentss/shared/paginate/BasicPagination.vue @@ -1,19 +1,21 @@