mirror of
https://github.com/Dadechin/XRoomDashboardFront.git
synced 2025-07-03 08:44:35 +00:00
404 lines
9.5 KiB
Vue
404 lines
9.5 KiB
Vue
<template>
|
|
<div v-if="isOpen" class="modal-overlay" @click="handleBackdropClick">
|
|
<div class="modal-content" @click.stop>
|
|
<div class="modal-header">
|
|
<h2>پیشنمایش فایل</h2>
|
|
<button @click="closePreviewDialog">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
width="35"
|
|
height="35"
|
|
viewBox="0 0 32 32"
|
|
fill="none"
|
|
>
|
|
<rect x="0.5" y="0.5" width="31" height="31" rx="7.5" fill="#101010" />
|
|
<rect x="0.5" y="0.5" width="31" height="31" rx="7.5" stroke="#E2DEE9" />
|
|
<path
|
|
d="M21 11L11 21"
|
|
stroke="white"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
/>
|
|
<path
|
|
d="M11 11L21 21"
|
|
stroke="white"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<div class="modal-title">
|
|
<h2>مشاهده فایل</h2>
|
|
<span>پیشنمایش فایل انتخابشده را مشاهده کنید.</span>
|
|
</div>
|
|
<div class="preview-content">
|
|
<!-- Image Preview -->
|
|
<img :src="previewUrl" class="preview-file" v-if="previewType === 'image'" />
|
|
|
|
<!-- PDF Preview -->
|
|
<div class="pdf-preview-container" v-if="previewType === 'pdf'">
|
|
<vue-pdf-embed :source="previewUrl" class="pdf-preview" v-if="previewUrl" />
|
|
</div>
|
|
|
|
<!-- Video Player -->
|
|
<div v-if="previewType === 'video'" class="video-preview-container">
|
|
<vue-plyr :options="plyrOptions">
|
|
<video controls>
|
|
<source :src="previewUrl" type="video/mp4" />
|
|
</video>
|
|
</vue-plyr>
|
|
</div>
|
|
|
|
<!-- 3D Model Preview -->
|
|
<div class="model-preview-container" v-if="previewType === 'glb'">
|
|
<model-viewer
|
|
:src="previewUrl"
|
|
alt="3D Model"
|
|
ar
|
|
ar-modes="webxr scene-viewer quick-look"
|
|
environment-image="neutral"
|
|
auto-rotate
|
|
camera-controls
|
|
class="model-preview"
|
|
></model-viewer>
|
|
</div>
|
|
</div>
|
|
<div class="modal-actions">
|
|
<button class="close-btn" @click="closePreviewDialog">بستن</button>
|
|
<button class="delete-btn" @click="deleteFile" v-if="previewIndex !== null">حذف</button>
|
|
<button class="download-btn" @click="downloadFile">دانلود</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import VuePdfEmbed from 'vue-pdf-embed';
|
|
import VuePlyr from 'vue-plyr';
|
|
import 'vue-plyr/dist/vue-plyr.css';
|
|
import '@google/model-viewer';
|
|
import axios from 'axios';
|
|
|
|
export default {
|
|
name: 'FilePreviewDialog',
|
|
components: {
|
|
VuePdfEmbed,
|
|
VuePlyr,
|
|
},
|
|
props: {
|
|
isOpen: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
previewUrl: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
previewType: {
|
|
type: String,
|
|
default: null,
|
|
},
|
|
previewIndex: {
|
|
type: Number,
|
|
default: null,
|
|
},
|
|
baseUrl: {
|
|
type: String,
|
|
required: true,
|
|
},
|
|
plyrOptions: {
|
|
type: Object,
|
|
default: () => ({
|
|
controls: ['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'settings', 'fullscreen'],
|
|
settings: ['quality', 'speed', 'loop'],
|
|
autoplay: false,
|
|
}),
|
|
},
|
|
},
|
|
watch: {
|
|
isOpen(newVal) {
|
|
if (newVal) {
|
|
document.body.style.overflow = 'hidden';
|
|
} else {
|
|
document.body.style.overflow = '';
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
handleBackdropClick(event) {
|
|
if (event.target.classList.contains('modal-overlay')) {
|
|
this.closePreviewDialog();
|
|
}
|
|
},
|
|
closePreviewDialog() {
|
|
this.$emit('close');
|
|
},
|
|
async downloadFile() {
|
|
// Define Toast configuration with SweetAlert2
|
|
const Toast = this.$swal.mixin({
|
|
toast: true,
|
|
position: 'top-end',
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
didOpen: (toast) => {
|
|
toast.onmouseenter = this.$swal.stopTimer;
|
|
toast.onmouseleave = this.$swal.resumeTimer;
|
|
},
|
|
});
|
|
|
|
try {
|
|
const response = await fetch(this.previewUrl);
|
|
const blob = await response.blob();
|
|
const downloadUrl = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = downloadUrl;
|
|
a.download = `${this.previewType}-${new Date().getTime()}.${this.previewUrl.split('.').pop()}`;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(downloadUrl);
|
|
document.body.removeChild(a);
|
|
|
|
// Show success Toast
|
|
Toast.fire({
|
|
icon: 'success',
|
|
title: 'فایل با موفقیت دانلود شد',
|
|
});
|
|
} catch (error) {
|
|
console.error('Error downloading file:', error);
|
|
|
|
// Show error Toast
|
|
Toast.fire({
|
|
icon: 'error',
|
|
title: 'خطا در دانلود فایل',
|
|
});
|
|
}
|
|
},
|
|
async deleteFile() {
|
|
if (this.previewIndex === null || !this.previewType) return;
|
|
|
|
// Define Toast configuration with SweetAlert2
|
|
const Toast = this.$swal.mixin({
|
|
toast: true,
|
|
position: 'top-end',
|
|
showConfirmButton: false,
|
|
timer: 3000,
|
|
timerProgressBar: true,
|
|
didOpen: (toast) => {
|
|
toast.onmouseenter = this.$swal.stopTimer;
|
|
toast.onmouseleave = this.$swal.resumeTimer;
|
|
},
|
|
});
|
|
|
|
try {
|
|
const token = localStorage.getItem('token');
|
|
const deleteUrl = `${this.baseUrl}/delete${this.previewType.charAt(0).toUpperCase() + this.previewType.slice(1)}/${this.previewIndex}/`;
|
|
|
|
await axios.delete(deleteUrl, {
|
|
headers: {
|
|
'Authorization': `Token ${token}`,
|
|
},
|
|
});
|
|
|
|
this.$emit('delete-success');
|
|
this.closePreviewDialog();
|
|
|
|
// Show success Toast
|
|
Toast.fire({
|
|
icon: 'success',
|
|
title: 'فایل با موفقیت حذف شد',
|
|
});
|
|
} catch (error) {
|
|
console.error('Error deleting file:', error);
|
|
|
|
let errorMessage = 'خطا در حذف فایل';
|
|
if (error.response) {
|
|
if (error.response.status === 401) {
|
|
errorMessage = 'عدم دسترسی: لطفا دوباره وارد شوید.';
|
|
} else if (error.response.status === 400) {
|
|
errorMessage = 'درخواست نامعتبر است.';
|
|
} else {
|
|
errorMessage = error.response.data.message || errorMessage;
|
|
}
|
|
} else if (error.request) {
|
|
errorMessage = 'مشکل در ارتباط با سرور. لطفا دوباره تلاش کنید.';
|
|
}
|
|
|
|
// Show error Toast
|
|
Toast.fire({
|
|
icon: 'error',
|
|
title: errorMessage,
|
|
});
|
|
}
|
|
},
|
|
},
|
|
};
|
|
</script>
|
|
|
|
|
|
<style scoped>
|
|
|
|
:deep(.plyr) {
|
|
width: 100%;
|
|
height: 100%;
|
|
--plyr-color-main: #3a57e8; /* رنگ اصلی کنترلها */
|
|
--plyr-video-background: #000; /* پسزمینه ویدیو */
|
|
}
|
|
|
|
.video-preview-container {
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.modal-overlay {
|
|
position: fixed;
|
|
inset: 0;
|
|
background: rgba(0, 0, 0, 0.5);
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
z-index: 1000;
|
|
}
|
|
|
|
.modal-content {
|
|
background: #F7F5FA;
|
|
border-radius: 20px;
|
|
width: 100%;
|
|
max-width: 700px;
|
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
direction: rtl;
|
|
padding-bottom: 1.5rem;
|
|
max-height: 95vh;
|
|
height: max-content;
|
|
overflow-y: auto;
|
|
scrollbar-width: none;
|
|
-ms-overflow-style: none;
|
|
}
|
|
|
|
.modal-content::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
.modal-header {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
background-color: #101010;
|
|
color: #fff;
|
|
padding: 20px 26px;
|
|
margin-bottom: 1.5rem;
|
|
border-radius: 20px 20px 0 0;
|
|
}
|
|
|
|
.modal-header h2 {
|
|
font-size: 22px;
|
|
}
|
|
|
|
.modal-header button {
|
|
background-color: inherit;
|
|
border: none;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.modal-title {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
padding: 20px 50px 20px 20px;
|
|
}
|
|
|
|
.modal-title h2 {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
color: #101010;
|
|
}
|
|
|
|
.modal-title span {
|
|
font-size: 16px;
|
|
font-weight: 500;
|
|
color: #4F5A69;
|
|
margin-top: 1rem;
|
|
}
|
|
|
|
.preview-content {
|
|
margin: 1rem auto 0;
|
|
padding: 20px;
|
|
background-color: #FFFFFF;
|
|
border-radius: 16px;
|
|
width: 100%;
|
|
max-width: 620px;
|
|
display: block;
|
|
border-radius: 12px;
|
|
}
|
|
|
|
.preview-content img {
|
|
border-radius: 12px;
|
|
object-fit: cover;
|
|
}
|
|
|
|
.preview-file {
|
|
width: 100%;
|
|
max-height: 400px;
|
|
object-fit: contain;
|
|
}
|
|
|
|
.pdf-preview-container,
|
|
.video-preview-container,
|
|
.model-preview-container {
|
|
width: 100%;
|
|
max-height: 400px;
|
|
overflow: auto;
|
|
}
|
|
|
|
.pdf-preview,
|
|
.model-preview {
|
|
width: 580px;
|
|
height: 300px;
|
|
}
|
|
|
|
.video-player {
|
|
width: 100%;
|
|
}
|
|
|
|
.modal-actions {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
padding: 20px 0 0;
|
|
width: 100%;
|
|
max-width: 620px;
|
|
margin: auto;
|
|
gap: 1rem;
|
|
}
|
|
|
|
.download-btn,
|
|
.delete-btn,
|
|
.close-btn {
|
|
border: none;
|
|
border-radius: 8px;
|
|
cursor: pointer;
|
|
height: 50px;
|
|
width: 33%;
|
|
font-weight: 500;
|
|
font-size: 18px;
|
|
text-align: center;
|
|
}
|
|
|
|
.download-btn {
|
|
background-color: #3A57E8;
|
|
color: white;
|
|
}
|
|
|
|
.delete-btn {
|
|
background-color: #B31C51;
|
|
color: white;
|
|
}
|
|
|
|
.close-btn {
|
|
background-color: #EBEEFD;
|
|
color: #101010;
|
|
}
|
|
|
|
|
|
</style> |