fixing bugs in seo generate, fix bug set publish time in post, changes in import posts command, changes in pagination
This commit is contained in:
@@ -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()),
|
||||
]),
|
||||
]),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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());
|
||||
});
|
||||
|
||||
@@ -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, '<a>');
|
||||
|
||||
$readingTime = $this->calculateReadingTime($content);
|
||||
$contentData = [
|
||||
[
|
||||
'type' => 'paragraph',
|
||||
@@ -83,8 +85,9 @@ class ImportApiDataPost implements ShouldQueue
|
||||
$slug = $this->generateSlug($post->NAME);
|
||||
|
||||
// Создание нового поста
|
||||
Post::create([
|
||||
'id' => $post->ID,
|
||||
Post::firstOrCreate(
|
||||
['id' => $post->ID], // Условие поиска по ID
|
||||
[
|
||||
'title' => $post->NAME,
|
||||
'slug' => $slug,
|
||||
'preview_text' => strip_tags($post->PREVIEW_TEXT),
|
||||
@@ -92,13 +95,15 @@ class ImportApiDataPost implements ShouldQueue
|
||||
'content' => $contentData, // Преобразуем в JSON
|
||||
'status' => 'published',
|
||||
'images' => $imagePaths, // Сохраняем пути к изображениям
|
||||
'search_data' => $content, // Преобразуем в JSON
|
||||
'reading_time' => 2,
|
||||
'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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -115,7 +115,7 @@ export default {
|
||||
<PostListItem :post="post" />
|
||||
</template>
|
||||
</div>
|
||||
<BasicPagination :links="posts.links" />
|
||||
<BasicPagination :links="posts.meta" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
<template>
|
||||
<div class="mt-10 flex items-center justify-center">
|
||||
<nav class="isolate inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||
<Link as="button" :href="links.prev" :disabled="links.prev === null"
|
||||
class="relative inline-flex items-center gap-1 rounded-l-md border border-gray-300 bg-white px-3 py-2 pr-4 text-sm font-medium text-gray-500 hover:bg-gray-50 focus:z-20 disabled:pointer-events-none disabled:opacity-40">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" aria-hidden="true" data-slot="icon" class="h-3 w-3">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 19.5 8.25 12l7.5-7.5"></path>
|
||||
<nav class="flex items-center gap-x-1" aria-label="Pagination">
|
||||
<Link :href="links.links[0].url" as="button" class="min-h-9.5 min-w-9.5 py-2 px-2.5 inline-flex justify-center items-center gap-x-2 text-sm rounded-lg border border-transparent text-gray-800 hover:bg-gray-100 focus:outline-hidden focus:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none" aria-label="Previous">
|
||||
<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m15 18-6-6 6-6"></path>
|
||||
</svg>
|
||||
<span>Предыдущая</span></Link>
|
||||
<Link as="button" :href="links.next" :disabled="links.next === null"
|
||||
class="relative inline-flex items-center gap-1 rounded-r-md border border-gray-300 bg-white px-3 py-2 pl-4 text-sm font-medium text-gray-500 hover:bg-gray-50 focus:z-20 disabled:pointer-events-none disabled:opacity-40">
|
||||
<span>Следующая</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5"
|
||||
stroke="currentColor" aria-hidden="true" data-slot="icon" class="h-3 w-3">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m8.25 4.5 7.5 7.5-7.5 7.5"></path>
|
||||
<span class="sr-only">Previous</span>
|
||||
</Link>
|
||||
<div class="flex items-center gap-x-1">
|
||||
<Link v-for="link in getPageLinks(links)" as="button" :href="link.url"
|
||||
:class="link.active ? 'border-gray-200 text-gray-800' : 'border-transparent hover:bg-gray-100'"
|
||||
class="min-h-9.5 min-w-9.5 flex justify-center items-center border py-2 px-3 text-sm rounded-lg focus:outline-hidden focus:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none">{{ link.label }}</Link>
|
||||
</div>
|
||||
<Link :href="links.links.slice(-1).pop().url" as="button" class="min-h-9.5 min-w-9.5 py-2 px-2.5 inline-flex justify-center items-center gap-x-2 text-sm rounded-lg border border-transparent text-gray-800 hover:bg-gray-100 focus:outline-hidden focus:bg-gray-100 disabled:opacity-50 disabled:pointer-events-none" aria-label="Next">
|
||||
<span class="sr-only">Next</span>
|
||||
<svg class="shrink-0 size-3.5" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m9 18 6-6-6-6"></path>
|
||||
</svg>
|
||||
</Link>
|
||||
</nav>
|
||||
@@ -31,6 +33,14 @@ export default {
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getPageLinks(pagination) {
|
||||
return pagination.links.filter(link =>
|
||||
link.label !== 'pagination.previous' &&
|
||||
link.label !== 'pagination.next'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user