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

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

سلام وقت این کد های منه ولی خطا دارم
بخش 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 1 ماه پیش مطرح شد
امیر باقری
تخصص : مدیر عامل
@lordwebiran 3 هفته پیش آپدیت شد
0

سلام وقت بخیر من مشکل مو حل کردم خودم یادم بشه براتون بزارمش اینجا شاید کسی لازم داشت ولی حتما توی گیت هاب میزارمش نمونه پروژه رو بخش آپلود عکس که مشکل داشتم


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

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