امیر باقری
16 ساعت پیش توسط امیر باقری مطرح شد
1 پاسخ

آپلود عکس با لاراول صورت پیشرفته

سلام وقت این کد های منه ولی خطا دارم
بخش vue.js

<template>
    <div>
        <!-- Drop Zone -->
        <div
            id="dropZone"
            class="w-60 h-44 bg-picUploadBG border rounded-lg flex flex-col justify-center items-center p-4 text-SMLink cursor-pointer"
            @drop.prevent="handleDrop"
            @dragover.prevent
            @click="triggerFileInput"
        >
            <span class="text-center">
                برای آپلود، تصویر را اینجا بکشید یا کلیک کنید
            </span>
        </div>
        <input
            ref="fileInput"
            type="file"
            multiple
            accept="image/*"
            @change="handleFileChange"
            class="hidden"
        />

        <!-- Preview Section -->
        <div class="grid grid-cols-4 max-sm:grid-cols-1 gap-4 mt-6">
            <div
                v-for="(image, index) in images"
                :key="image.tempId"
                class="relative group rounded-lg overflow-hidden border"
            >
                <!-- Preview Image -->
                <img
                    v-if="image.previewUrl"
                    :src="image.previewUrl"
                    class="w-full h-40 object-cover"
                />

                <!-- Loading Indicator -->
                <div
                    v-if="image.uploading"
                    class="absolute inset-0 bg-black bg-opacity-50 flex items-center justify-center text-white"
                >
                    در حال بارگذاری...
                </div>

                <!-- Progress Bar -->
                <div
                    v-if="image.uploading"
                    class="absolute bottom-0 left-0 w-full"
                >
                    <div
                        class="h-1 bg-blue-600"
                        :style="{ width: image.uploadProgress + '%' }"
                    ></div>
                </div>

                <!-- Delete Button -->
                <div
                    @click="removeImage(index, image.url)"
                    class="absolute top-2 right-2 bg-red-500 text-white p-1 rounded-full cursor-pointer opacity-0 group-hover:opacity-100"
                >
                    <span class="text-xl">X</span>
                </div>

                <!-- Set Main Image -->
                <span
                    v-if="!image.isMain && !image.uploading"
                    @click="setMainImage(index)"
                    class="absolute bottom-2 left-2 bg-blue-600 text-white p-1 rounded-full cursor-pointer opacity-0 group-hover:opacity-100"
                >
                    تصویر اصلی
                </span>
            </div>
        </div>
    </div>
</template>

<script>
export default {
    data() {
        return {
            images: [], // فهرست تصاویر آپلود شده
        };
    },
    methods: {
        // فعال کردن فایل input
        triggerFileInput() {
            this.$refs.fileInput.click();
        },

        // مدیریت تغییرات فایل
        handleFileChange(event) {
            this.addToUploadQueue(event.target.files);
        },

        // مدیریت دراگ و دراپ فایل‌ها
        handleDrop(event) {
            this.addToUploadQueue(event.dataTransfer.files);
        },

        // افزودن تصاویر به صف آپلود
        addToUploadQueue(files) {
            Array.from(files).forEach((file) => {
                const previewUrl = URL.createObjectURL(file);

                const image = {
                    file,
                    previewUrl,
                    uploading: true,
                    uploadProgress: 0,
                    isMain: false,
                    url: null,
                    tempId: Math.random().toString(36).substring(2, 15), // شناسه منحصر به فرد
                };

                this.images.push(image);
                this.uploadImage(image);
            });
        },

        // آپلود تصویر به سرور
        async uploadImage(image) {
            const formData = new FormData();
            formData.append("AdPhote[]", image.file);
            formData.append("tempId", image.tempId); // شناسه منحصر به فرد
            formData.append("isMain", image.isMain); // آیا تصویر اصلی است؟

            try {
                const response = await axios.post(
                    "/Ads/upload-images",
                    formData,
                    {
                        headers: { "Content-Type": "multipart/form-data" },
                        onUploadProgress: (progressEvent) => {
                            if (progressEvent.lengthComputable) {
                                image.uploadProgress = Math.round(
                                    (progressEvent.loaded * 100) /
                                        progressEvent.total
                                );
                            }
                        },
                    }
                );

                console.log("Server Response:", response.data);

                if (response.data.success && response.data.images.length > 0) {
                    response.data.images.forEach((uploadedImage) => {
                        const matchingImage = this.images.find(
                            (img) => img.tempId === uploadedImage.tempId
                        );

                        if (matchingImage) {
                            matchingImage.uploading = false;
                            matchingImage.url = uploadedImage.url;
                            matchingImage.previewUrl = uploadedImage.url;
                            matchingImage.serverId = uploadedImage.serverId;
                        }
                    });
                } else {
                    console.error("Unexpected response format:", response.data);
                    throw new Error("Invalid server response");
                }
            } catch (error) {
                console.error(
                    "Error uploading image:",
                    error.response || error.message
                );
                this.removeImage(this.images.indexOf(image)); // حذف تصویر در صورت خطا
            }
        },

        // حذف تصویر از صف آپلود
        removeImage(index, imageUrl = null) {
            console.log("Deleting image with URL:", imageUrl);

            if (imageUrl) {
                axios
                    .delete("/Ads/delete-image", { data: { imageUrl } })
                    .then((response) => {
                        if (response.data.success) {
                            console.log(
                                "Image successfully deleted from server."
                            );
                        } else {
                            console.error("Image deletion failed on server.");
                        }
                    })
                    .catch((error) => {
                        console.error("Error deleting image:", error);
                    });
            }

            this.images.splice(index, 1); // حذف تصویر از آرایه
        },

        // تنظیم تصویر اصلی
        setMainImage(index) {
            this.images.forEach((image, i) => {
                image.isMain = i === index;
            });
        },
    },
};
</script>

بخش کنترل

public function uploadImages(Request $request)
{
    // بررسی وجود فایل در درخواست
    if (!$request->hasFile('AdPhote')) {
        Log::error('No files uploaded');
        return response()->json(['success' => false, 'message' => 'No files uploaded']);
    }

    // دریافت فایل‌ها از درخواست
    $files = $request->file('AdPhote');

    // بررسی اینکه فایل‌ها در فرمت آرایه باشند
    if (!is_array($files)) {
        Log::error('Files are not in an array format');
        return response()->json(['success' => false, 'message' => 'Invalid file format']);
    }

    // محدودیت تعداد فایل‌ها
    if (count($files) > 10) { // فرضاً محدودیت 10 فایل
        return response()->json(['success' => false, 'message' => 'Too many files']);
    }

    // محدودیت حجم فایل‌ها
    $maxFileSize = 1024 * 1024 * 10; // 10MB
    foreach ($files as $file) {
        if ($file->getSize() > $maxFileSize) {
            return response()->json(['success' => false, 'message' => 'File size exceeds the maximum limit']);
        }
    }

    // فرمت‌های مجاز فایل‌ها
    $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif'];
    foreach ($files as $file) {
        if (!in_array($file->getClientOriginalExtension(), $allowedExtensions)) {
            return response()->json(['success' => false, 'message' => 'Invalid file format']);
        }
    }

    // دریافت داده‌های اضافی از درخواست
    $tempIds = $request->input('tempIds', []);
    $isMains = $request->input('isMains', []);

    // آرایه برای ذخیره اطلاعات فایل‌های آپلود شده
    $uploadedImages = [];

    // حلقه برای آپلود فایل‌ها
    foreach ($files as $index => $file) {
        try {
            // مسیر ذخیره‌سازی فایل
            $path = 'Image/Ad/' . date('Y') . '/' . date('m') . '/' . date('d');
            $fileName = "Z-ad-" . date('Ymd') . "-" . Str::random(10) . "." . $file->getClientOriginalExtension();

            // ذخیره فایل موقت در پوشه 'temp'
            $tempPath = $file->storeAs('temp', $fileName);

            // مسیر فایل در سرور FTP
            $ftpPath = $path . '/' . $fileName;

            // آپلود فایل به سرور FTP
            if (!Storage::disk('ftp')->put($ftpPath, Storage::get($tempPath))) {
                throw new \Exception('FTP upload failed');
            }

            // حذف فایل موقت از سرور
            Storage::delete($tempPath);

            // گرفتن داده‌های اضافی
            $tempId = $tempIds[$index] ?? null;
            $isMain = filter_var($isMains[$index] ?? false, FILTER_VALIDATE_BOOLEAN);

            // ذخیره اطلاعات فایل در آرایه
            $uploadedImages[] = [
                'path' => $ftpPath,
                'fileName' => $fileName,
                'url' => 'https://img.zoomila.com/' . $ftpPath,
                'format' => $file->getClientOriginalExtension(),
                'tempId' => $tempId,
                'isMain' => $isMain,
            ];

        } catch (\Exception $e) {
            // در صورت بروز خطا، لاگ کرده و پیام خطا ارسال می‌شود
            Log::error('Error uploading file: ' . $e->getMessage());
            return response()->json(['success' => false, 'message' => $e->getMessage()]);
        }
    }

    // بازگشت اطلاعات فایل‌های آپلود شده
    return response()->json(['success' => true, 'images' => $uploadedImages]);
}

public function store(Request $request)
{
// اعتبارسنجی داده‌های فرم
$validatedData = $request->validate([
'title' => 'required|string|max:255',
'description' => 'required|string',
'price' => 'required|numeric',
'images' => 'array',
'images.*' => 'image|max:2048', // محدودیت تصویر
]);

DB::beginTransaction();

try {
    // ذخیره اطلاعات اصلی آگهی
    $ad = Ad::create([
        'title' => $validatedData['title'],
        'description' => $validatedData['description'],
        'price' => $validatedData['price'],
    ]);

    // آپلود و ذخیره تصاویر
    $uploadedImages = $this->uploadImages($request);
    $this->saveImageData($uploadedImages, $ad->id);

    DB::commit();

    return response()->json([
        'success' => true,
        'message' => 'آگهی و تصاویر با موفقیت ذخیره شدند.',
        'ad' => $ad,
    ]);

} catch (\Exception $e) {
    DB::rollBack();

    return response()->json([
        'success' => false,
        'message' => 'خطایی در ذخیره‌سازی رخ داده است.',
        'error' => $e->getMessage(),
    ], 500);
}

}


ثبت پرسش جدید
امیر باقری
تخصص : مدیر عامل
@lordwebiran 16 ساعت پیش مطرح شد

برای ارسال پاسخ لازم است وارد شده یا ثبت‌نام کنید

ورود یا ثبت‌نام