'image|max:4096', // 4MB, можно изменить по желанию ]; public function updatedImages($value, $key) { // После обновления файла, генерируем превью $this->validateOnly('images.*'); if ($this->images[$key]) { $this->imagePreviews[$key] = $this->images[$key]->temporaryUrl(); } } public function startProcessing() { $this->validate(); // Сохраняем изображения $savedImages = []; foreach ($this->images as $uploaded) { $path = $uploaded->store('images', 'public'); $savedImages[] = [ 'path' => $path, 'original_name' => $uploaded->getClientOriginalName() ]; } // Создаём запись в истории $history = ProcessHistories::create([ 'images' => $savedImages, 'started_at' => now(), ]); $this->historyId = $history->id; $this->status = 'processing'; $this->progressMessage = 'Ставим в очередь на обработку...'; // Отправляем задачу в очередь $job = new ProcessImagesJob($history->id); $dispatch = dispatch($job); // Можно при желании сохранить ID задачи, если нужно // $this->queueJobId = ... (в зависимости от драйвера очереди) // Дальше фронт будет периодически обновлять состояние либо // мы можем слушать события Livewire (Broadcasting) по готовности } public function pollStatus() { if ($this->historyId) { $history = ProcessHistories::find($this->historyId); if ($history) { if ($history->finished_at) { $this->status = 'done'; $this->progressMessage = 'Обработка завершена. Файл: ' . $history->step_file_name; } else { // Можно отобразить прогресс, если в историях где-то хранится этап $count = $history->processed_count; $this->progressMessage = "Обработка в процессе... {$count}/3 изображений"; } } } } public function render() { return view('livewire.image-upload'); } }