248 lines
6.5 KiB
Vue
248 lines
6.5 KiB
Vue
<template>
|
|
<div class="space-y-4">
|
|
<!-- Statut de la conversion -->
|
|
<div class="flex items-center space-x-3">
|
|
<!-- Icône de statut -->
|
|
<div class="flex-shrink-0">
|
|
<ArrowPathIcon
|
|
v-if="isConverting"
|
|
class="w-6 h-6 text-blue-500 animate-spin"
|
|
/>
|
|
<CheckCircleIcon
|
|
v-else-if="isSuccess"
|
|
class="w-6 h-6 text-green-500"
|
|
/>
|
|
<ExclamationTriangleIcon
|
|
v-else-if="hasError"
|
|
class="w-6 h-6 text-red-500"
|
|
/>
|
|
<ClockIcon
|
|
v-else
|
|
class="w-6 h-6 text-gray-400"
|
|
/>
|
|
</div>
|
|
|
|
<!-- Message de statut -->
|
|
<div class="flex-1">
|
|
<p class="text-sm font-medium text-gray-900">
|
|
{{ statusMessage }}
|
|
</p>
|
|
<p v-if="fileName" class="text-xs text-gray-500">
|
|
{{ fileName }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Barre de progression -->
|
|
<div v-if="showProgress" class="space-y-2">
|
|
<div class="flex justify-between text-xs text-gray-600">
|
|
<span>Progression</span>
|
|
<span>{{ Math.round(progress) }}%</span>
|
|
</div>
|
|
<div class="w-full bg-gray-200 rounded-full h-2">
|
|
<div
|
|
class="bg-blue-500 h-2 rounded-full transition-all duration-300 ease-out"
|
|
:style="{ width: `${progress}%` }"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Détails de la conversion -->
|
|
<div v-if="showDetails && (originalSize || convertedSize)" class="text-xs text-gray-500 space-y-1">
|
|
<div v-if="originalSize" class="flex justify-between">
|
|
<span>Taille originale:</span>
|
|
<span>{{ formatFileSize(originalSize) }}</span>
|
|
</div>
|
|
<div v-if="convertedSize" class="flex justify-between">
|
|
<span>Taille convertie:</span>
|
|
<span>{{ formatFileSize(convertedSize) }}</span>
|
|
</div>
|
|
<div v-if="originalSize && convertedSize" class="flex justify-between font-medium">
|
|
<span>Gain d'espace:</span>
|
|
<span :class="spaceSavingClass">{{ spaceSavingText }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div v-if="showActions" class="flex space-x-3">
|
|
<button
|
|
v-if="canDownload"
|
|
@click="$emit('download')"
|
|
class="flex items-center space-x-2 px-4 py-2 bg-green-600 text-white text-sm font-medium rounded-md hover:bg-green-700 focus:outline-none focus:ring-2 focus:ring-green-500 focus:ring-offset-2 transition-colors"
|
|
>
|
|
<ArrowDownTrayIcon class="w-4 h-4" />
|
|
<span>Télécharger CBZ</span>
|
|
</button>
|
|
|
|
<button
|
|
v-if="canReset"
|
|
@click="$emit('reset')"
|
|
class="flex items-center space-x-2 px-4 py-2 border border-gray-300 text-gray-700 text-sm font-medium rounded-md hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
|
|
>
|
|
<ArrowPathIcon class="w-4 h-4" />
|
|
<span>Convertir un autre fichier</span>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Message d'erreur détaillé -->
|
|
<div v-if="hasError && errorMessage" class="p-3 bg-red-50 border border-red-200 rounded-md">
|
|
<div class="flex">
|
|
<ExclamationTriangleIcon class="w-5 h-5 text-red-400 flex-shrink-0" />
|
|
<div class="ml-3">
|
|
<h3 class="text-sm font-medium text-red-800">
|
|
Erreur de conversion
|
|
</h3>
|
|
<p class="mt-1 text-sm text-red-700">
|
|
{{ errorMessage }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import {
|
|
ArrowDownTrayIcon,
|
|
ArrowPathIcon,
|
|
CheckCircleIcon,
|
|
ClockIcon,
|
|
ExclamationTriangleIcon,
|
|
} from '@heroicons/vue/24/outline';
|
|
import { computed } from 'vue';
|
|
|
|
export default {
|
|
name: 'ConversionProgress',
|
|
|
|
components: {
|
|
ArrowPathIcon,
|
|
CheckCircleIcon,
|
|
ExclamationTriangleIcon,
|
|
ClockIcon,
|
|
ArrowDownTrayIcon,
|
|
},
|
|
|
|
props: {
|
|
isConverting: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
progress: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
isSuccess: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
hasError: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
errorMessage: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
fileName: {
|
|
type: String,
|
|
default: '',
|
|
},
|
|
originalSize: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
convertedSize: {
|
|
type: Number,
|
|
default: 0,
|
|
},
|
|
showActions: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
showDetails: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
},
|
|
|
|
emits: ['download', 'reset'],
|
|
|
|
setup(props) {
|
|
// Message de statut calculé
|
|
const statusMessage = computed(() => {
|
|
if (props.isConverting) {
|
|
return 'Conversion en cours...';
|
|
}
|
|
if (props.isSuccess) {
|
|
return 'Conversion terminée avec succès !';
|
|
}
|
|
if (props.hasError) {
|
|
return 'Erreur lors de la conversion';
|
|
}
|
|
return 'En attente de fichier';
|
|
});
|
|
|
|
// Affichage de la barre de progression
|
|
const showProgress = computed(() => {
|
|
return props.isConverting && props.progress > 0;
|
|
});
|
|
|
|
// Actions disponibles
|
|
const canDownload = computed(() => {
|
|
return props.isSuccess && !props.isConverting;
|
|
});
|
|
|
|
const canReset = computed(() => {
|
|
return (props.isSuccess || props.hasError) && !props.isConverting;
|
|
});
|
|
|
|
// Calcul du gain d'espace
|
|
const spaceSaving = computed(() => {
|
|
if (!props.originalSize || !props.convertedSize) return 0;
|
|
return ((props.originalSize - props.convertedSize) / props.originalSize) * 100;
|
|
});
|
|
|
|
const spaceSavingText = computed(() => {
|
|
const saving = spaceSaving.value;
|
|
if (saving > 0) {
|
|
return `-${saving.toFixed(1)}%`;
|
|
} else if (saving < 0) {
|
|
return `+${Math.abs(saving).toFixed(1)}%`;
|
|
}
|
|
return '0%';
|
|
});
|
|
|
|
const spaceSavingClass = computed(() => {
|
|
const saving = spaceSaving.value;
|
|
if (saving > 0) {
|
|
return 'text-green-600';
|
|
} else if (saving < 0) {
|
|
return 'text-red-600';
|
|
}
|
|
return 'text-gray-600';
|
|
});
|
|
|
|
// Formatage de la taille de fichier
|
|
const formatFileSize = (bytes) => {
|
|
if (bytes === 0) return '0 octets';
|
|
|
|
const k = 1024;
|
|
const sizes = ['octets', 'Ko', 'Mo', 'Go'];
|
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
|
|
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
|
|
};
|
|
|
|
return {
|
|
statusMessage,
|
|
showProgress,
|
|
canDownload,
|
|
canReset,
|
|
spaceSavingText,
|
|
spaceSavingClass,
|
|
formatFileSize,
|
|
};
|
|
},
|
|
};
|
|
</script>
|