feat: Composables pour la gestion des données
- useApi.js : Service API générique avec gestion d'erreurs - useSites.js : Gestion des sites industriels - useMachines.js : Gestion des machines et création depuis types - useMachineTypes.js : Gestion des types de machines - useMachineTypesApi.js : API pour les types de machines - useComposants.js : Gestion des composants hiérarchiques - usePieces.js : Gestion des pièces de machines - useCustomFields.js : Gestion des champs personnalisés - useToast.js : Système de notifications toast
This commit is contained in:
75
app/composables/useApi.js
Normal file
75
app/composables/useApi.js
Normal file
@@ -0,0 +1,75 @@
|
||||
import { useToast } from './useToast'
|
||||
|
||||
export function useApi() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const API_BASE_URL = process.env.NUXT_PUBLIC_API_BASE_URL || 'http://localhost:3000/api'
|
||||
const API_TIMEOUT = parseInt(process.env.NUXT_PUBLIC_API_TIMEOUT || '30000')
|
||||
|
||||
const apiCall = async (endpoint, options = {}) => {
|
||||
const url = `${API_BASE_URL}${endpoint}`
|
||||
const defaultOptions = {
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
}
|
||||
|
||||
// Ajouter un timeout à la requête
|
||||
const controller = new AbortController()
|
||||
const timeoutId = setTimeout(() => controller.abort(), API_TIMEOUT)
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...defaultOptions,
|
||||
...options,
|
||||
signal: controller.signal
|
||||
})
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.json()
|
||||
return { success: true, data }
|
||||
} else {
|
||||
const errorData = await response.json().catch(() => ({}))
|
||||
const errorMessage = errorData.message || `Erreur ${response.status}: ${response.statusText}`
|
||||
showError(errorMessage)
|
||||
return { success: false, error: errorMessage, status: response.status }
|
||||
}
|
||||
} catch (error) {
|
||||
clearTimeout(timeoutId)
|
||||
const errorMessage = error.name === 'AbortError' ? 'Timeout de la requête' : error.message || 'Erreur réseau'
|
||||
showError(`Erreur réseau: ${errorMessage}`)
|
||||
return { success: false, error: errorMessage }
|
||||
}
|
||||
}
|
||||
|
||||
const get = async (endpoint) => {
|
||||
return apiCall(endpoint, { method: 'GET' })
|
||||
}
|
||||
|
||||
const post = async (endpoint, data) => {
|
||||
return apiCall(endpoint, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
const patch = async (endpoint, data) => {
|
||||
return apiCall(endpoint, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data)
|
||||
})
|
||||
}
|
||||
|
||||
const del = async (endpoint) => {
|
||||
return apiCall(endpoint, { method: 'DELETE' })
|
||||
}
|
||||
|
||||
return {
|
||||
apiCall,
|
||||
get,
|
||||
post,
|
||||
patch,
|
||||
delete: del
|
||||
}
|
||||
}
|
||||
134
app/composables/useComposants.js
Normal file
134
app/composables/useComposants.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
const composants = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
export function useComposants() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadComposants = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/composants')
|
||||
if (result.success) {
|
||||
composants.value = result.data
|
||||
showInfo(`Chargement de ${composants.value.length} composant(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des composants:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getComposantsByMachine = async (machineId) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get(`/composants/machine/${machineId}`)
|
||||
if (result.success) {
|
||||
return { success: true, data: result.data }
|
||||
}
|
||||
return { success: false, error: result.error }
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des composants:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getComposantHierarchy = async (machineId) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get(`/composants/hierarchy/${machineId}`)
|
||||
if (result.success) {
|
||||
return { success: true, data: result.data }
|
||||
}
|
||||
return { success: false, error: result.error }
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement de la hiérarchie:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createComposant = async (composantData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/composants', composantData)
|
||||
if (result.success) {
|
||||
composants.value.push(result.data)
|
||||
showSuccess(`Composant "${composantData.name}" créé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création du composant:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateComposantData = async (id, composantData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/composants/${id}`, composantData)
|
||||
if (result.success) {
|
||||
const index = composants.value.findIndex(comp => comp.id === id)
|
||||
if (index !== -1) {
|
||||
composants.value[index] = result.data
|
||||
}
|
||||
showSuccess(`Composant "${composantData.name}" mis à jour avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour du composant:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteComposant = async (id) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/composants/${id}`)
|
||||
if (result.success) {
|
||||
const deletedComposant = composants.value.find(comp => comp.id === id)
|
||||
composants.value = composants.value.filter(comp => comp.id !== id)
|
||||
showSuccess(`Composant "${deletedComposant?.name || 'inconnu'}" supprimé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression du composant:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getComposantById = (id) => {
|
||||
return composants.value.find(comp => comp.id === id)
|
||||
}
|
||||
|
||||
const getComposants = () => composants.value
|
||||
const isLoading = () => loading.value
|
||||
|
||||
return {
|
||||
composants,
|
||||
loading,
|
||||
loadComposants,
|
||||
getComposantsByMachine,
|
||||
getComposantHierarchy,
|
||||
createComposant,
|
||||
updateComposant: updateComposantData,
|
||||
deleteComposant,
|
||||
getComposantById,
|
||||
getComposants,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
97
app/composables/useCustomFields.js
Normal file
97
app/composables/useCustomFields.js
Normal file
@@ -0,0 +1,97 @@
|
||||
import { ref } from 'vue'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
export function useCustomFields() {
|
||||
const { apiCall } = useApi()
|
||||
const customFieldValues = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
// Créer une valeur de champ personnalisé
|
||||
const createCustomFieldValue = async (customFieldValueData) => {
|
||||
try {
|
||||
const result = await apiCall('/custom-fields/values', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(customFieldValueData)
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
// Obtenir les valeurs de champs personnalisés pour une entité
|
||||
const getCustomFieldValuesByEntity = async (entityType, entityId) => {
|
||||
try {
|
||||
loading.value = true
|
||||
const result = await apiCall(`/custom-fields/values/${entityType}/${entityId}`, {
|
||||
method: 'GET'
|
||||
})
|
||||
if (result.success) {
|
||||
customFieldValues.value = result.data
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération des valeurs de champs personnalisés:', error)
|
||||
return { success: false, error }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// Mettre à jour une valeur de champ personnalisé
|
||||
const updateCustomFieldValue = async (id, updateData) => {
|
||||
try {
|
||||
const result = await apiCall(`/custom-fields/values/${id}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(updateData)
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
// Créer ou mettre à jour une valeur de champ personnalisé
|
||||
const upsertCustomFieldValue = async (customFieldId, entityType, entityId, value) => {
|
||||
try {
|
||||
const result = await apiCall('/custom-fields/values/upsert', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
customFieldId,
|
||||
entityType,
|
||||
entityId,
|
||||
value
|
||||
})
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création/mise à jour de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
// Supprimer une valeur de champ personnalisé
|
||||
const deleteCustomFieldValue = async (id) => {
|
||||
try {
|
||||
const result = await apiCall(`/custom-fields/values/${id}`, {
|
||||
method: 'DELETE'
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression de la valeur de champ personnalisé:', error)
|
||||
return { success: false, error }
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
customFieldValues,
|
||||
loading,
|
||||
createCustomFieldValue,
|
||||
getCustomFieldValuesByEntity,
|
||||
updateCustomFieldValue,
|
||||
upsertCustomFieldValue,
|
||||
deleteCustomFieldValue
|
||||
}
|
||||
}
|
||||
654
app/composables/useMachineTypes.js
Normal file
654
app/composables/useMachineTypes.js
Normal file
@@ -0,0 +1,654 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
// Types de machines prédéfinis avec structure hiérarchique
|
||||
const machineTypes = ref([
|
||||
// Machines de production
|
||||
{
|
||||
id: 1,
|
||||
name: 'Presse hydraulique',
|
||||
category: 'Production',
|
||||
description: 'Machine de formage par compression hydraulique',
|
||||
maintenanceFrequency: 'Mensuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Système hydraulique',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Pompe hydraulique',
|
||||
subComponents: [
|
||||
{ name: 'Rotor' },
|
||||
{ name: 'Stator' },
|
||||
{ name: 'Joint d\'étanchéité' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Cylindre principal',
|
||||
subComponents: [
|
||||
{ name: 'Piston' },
|
||||
{ name: 'Tige' },
|
||||
{ name: 'Joint de piston' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Soupapes de sécurité',
|
||||
subComponents: [
|
||||
{ name: 'Soupape de surpression' },
|
||||
{ name: 'Soupape de décharge' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système mécanique',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Banc de machine',
|
||||
subComponents: [
|
||||
{ name: 'Poutre supérieure' },
|
||||
{ name: 'Poutre inférieure' },
|
||||
{ name: 'Colonnes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de guidage',
|
||||
subComponents: [
|
||||
{ name: 'Rails de guidage' },
|
||||
{ name: 'Patins' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Pompe hydraulique', 'Cylindre principal', 'Soupapes de sécurité'],
|
||||
specifications: {
|
||||
force: '100-5000 tonnes',
|
||||
course: '100-800 mm',
|
||||
vitesse: '5-50 mm/s'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Convoyeur à bande',
|
||||
category: 'Production',
|
||||
description: 'Système de transport continu de matériaux',
|
||||
maintenanceFrequency: 'Hebdomadaire',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de transport',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Bande transporteuse',
|
||||
subComponents: [
|
||||
{ name: 'Carcasse' },
|
||||
{ name: 'Revêtement' },
|
||||
{ name: 'Armature' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Rouleaux',
|
||||
subComponents: [
|
||||
{ name: 'Rouleaux porteurs' },
|
||||
{ name: 'Rouleaux de retour' },
|
||||
{ name: 'Rouleaux d\'impact' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système d\'entraînement',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Moteur d\'entraînement',
|
||||
subComponents: [
|
||||
{ name: 'Rotor' },
|
||||
{ name: 'Stator' },
|
||||
{ name: 'Roulements' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Réducteur',
|
||||
subComponents: [
|
||||
{ name: 'Engrenages' },
|
||||
{ name: 'Arbre de sortie' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Bande transporteuse', 'Rouleaux', 'Moteur d\'entraînement'],
|
||||
specifications: {
|
||||
longueur: '5-100 m',
|
||||
largeur: '400-2000 mm',
|
||||
vitesse: '0.5-3 m/s'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Robot de soudage',
|
||||
category: 'Production',
|
||||
description: 'Robot industriel pour opérations de soudage automatisé',
|
||||
maintenanceFrequency: 'Trimestrielle',
|
||||
components: [
|
||||
{
|
||||
name: 'Bras robotique',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Base rotative',
|
||||
subComponents: [
|
||||
{ name: 'Moteur de rotation' },
|
||||
{ name: 'Réducteur' },
|
||||
{ name: 'Capteur de position' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Bras articulé',
|
||||
subComponents: [
|
||||
{ name: 'Joint 1' },
|
||||
{ name: 'Joint 2' },
|
||||
{ name: 'Joint 3' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de soudage',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Torche de soudage',
|
||||
subComponents: [
|
||||
{ name: 'Électrode' },
|
||||
{ name: 'Gainage' },
|
||||
{ name: 'Conduit de gaz' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Alimentation électrique',
|
||||
subComponents: [
|
||||
{ name: 'Transformateur' },
|
||||
{ name: 'Régulateur de courant' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Bras robotique', 'Torche de soudage', 'Contrôleur'],
|
||||
specifications: {
|
||||
portée: '1.5-3 m',
|
||||
charge: '5-200 kg',
|
||||
précision: '±0.1 mm'
|
||||
}
|
||||
},
|
||||
|
||||
// Machines de transformation
|
||||
{
|
||||
id: 4,
|
||||
name: 'Tour CNC',
|
||||
category: 'Transformation',
|
||||
description: 'Machine-outil pour usinage de pièces cylindriques',
|
||||
maintenanceFrequency: 'Mensuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Banc de machine',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Banc principal',
|
||||
subComponents: [
|
||||
{ name: 'Poutre' },
|
||||
{ name: 'Guidages' },
|
||||
{ name: 'Vis à billes' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de broche',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Broche principale',
|
||||
subComponents: [
|
||||
{ name: 'Arbre de broche' },
|
||||
{ name: 'Roulements' },
|
||||
{ name: 'Moteur de broche' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Contre-pointe',
|
||||
subComponents: [
|
||||
{ name: 'Pointe' },
|
||||
{ name: 'Cylindre' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Banc de machine', 'Broche', 'Contre-pointe'],
|
||||
specifications: {
|
||||
diamètre: '200-1000 mm',
|
||||
longueur: '500-3000 mm',
|
||||
puissance: '5-50 kW'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Fraiseuse',
|
||||
category: 'Transformation',
|
||||
description: 'Machine-outil pour usinage par enlèvement de copeaux',
|
||||
maintenanceFrequency: 'Mensuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Table de travail',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Table X',
|
||||
subComponents: [
|
||||
{ name: 'Guidages X' },
|
||||
{ name: 'Vis à billes X' },
|
||||
{ name: 'Moteur X' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Table Y',
|
||||
subComponents: [
|
||||
{ name: 'Guidages Y' },
|
||||
{ name: 'Vis à billes Y' },
|
||||
{ name: 'Moteur Y' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de broche',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Broche verticale',
|
||||
subComponents: [
|
||||
{ name: 'Arbre de broche' },
|
||||
{ name: 'Roulements' },
|
||||
{ name: 'Moteur de broche' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Table de travail', 'Broche', 'Guidages'],
|
||||
specifications: {
|
||||
courseX: '400-2000 mm',
|
||||
courseY: '300-1500 mm',
|
||||
courseZ: '200-800 mm'
|
||||
}
|
||||
},
|
||||
|
||||
// Machines de manutention
|
||||
{
|
||||
id: 6,
|
||||
name: 'Pont roulant',
|
||||
category: 'Manutention',
|
||||
description: 'Système de levage et transport de charges lourdes',
|
||||
maintenanceFrequency: 'Mensuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Poutre principale',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Poutre de roulement',
|
||||
subComponents: [
|
||||
{ name: 'Profilé principal' },
|
||||
{ name: 'Rails de roulement' },
|
||||
{ name: 'Renforts' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de palans',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Palans',
|
||||
subComponents: [
|
||||
{ name: 'Moteur de levage' },
|
||||
{ name: 'Treuil' },
|
||||
{ name: 'Crochet' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de translation',
|
||||
subComponents: [
|
||||
{ name: 'Moteur de translation' },
|
||||
{ name: 'Roues de roulement' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Poutre principale', 'Palans', 'Rails de guidage'],
|
||||
specifications: {
|
||||
capacité: '1-500 tonnes',
|
||||
portée: '5-50 m',
|
||||
hauteur: '3-20 m'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Chariot élévateur',
|
||||
category: 'Manutention',
|
||||
description: 'Véhicule de manutention pour charges palettisées',
|
||||
maintenanceFrequency: 'Hebdomadaire',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de levage',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Mast',
|
||||
subComponents: [
|
||||
{ name: 'Mât extérieur' },
|
||||
{ name: 'Mât intérieur' },
|
||||
{ name: 'Cylindres de levage' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Fourches',
|
||||
subComponents: [
|
||||
{ name: 'Fourche gauche' },
|
||||
{ name: 'Fourche droite' },
|
||||
{ name: 'Système de réglage' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Groupe motopropulseur',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Moteur',
|
||||
subComponents: [
|
||||
{ name: 'Bloc moteur' },
|
||||
{ name: 'Système d\'injection' },
|
||||
{ name: 'Système de refroidissement' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Transmission',
|
||||
subComponents: [
|
||||
{ name: 'Boîte de vitesses' },
|
||||
{ name: 'Arbre de transmission' },
|
||||
{ name: 'Pont arrière' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Mast', 'Fourches', 'Moteur'],
|
||||
specifications: {
|
||||
capacité: '1-10 tonnes',
|
||||
hauteur: '3-6 m',
|
||||
type: 'Électrique/Diesel/Gaz'
|
||||
}
|
||||
},
|
||||
|
||||
// Machines de traitement
|
||||
{
|
||||
id: 8,
|
||||
name: 'Compresseur d\'air',
|
||||
category: 'Traitement',
|
||||
description: 'Générateur d\'air comprimé pour applications industrielles',
|
||||
maintenanceFrequency: 'Hebdomadaire',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de compression',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Compresseur',
|
||||
subComponents: [
|
||||
{ name: 'Pistons' },
|
||||
{ name: 'Cylindres' },
|
||||
{ name: 'Soupapes' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Réservoir',
|
||||
subComponents: [
|
||||
{ name: 'Cuve' },
|
||||
{ name: 'Soupape de sécurité' },
|
||||
{ name: 'Manomètre' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de filtration',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Filtres',
|
||||
subComponents: [
|
||||
{ name: 'Filtre à air' },
|
||||
{ name: 'Filtre à huile' },
|
||||
{ name: 'Séparateur d\'eau' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Compresseur', 'Réservoir', 'Filtres'],
|
||||
specifications: {
|
||||
débit: '100-10000 L/min',
|
||||
pression: '7-10 bar',
|
||||
puissance: '5-500 kW'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
name: 'Pompe hydraulique',
|
||||
category: 'Traitement',
|
||||
description: 'Pompe pour circuits hydrauliques industriels',
|
||||
maintenanceFrequency: 'Mensuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de pompage',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Rotor',
|
||||
subComponents: [
|
||||
{ name: 'Ailettes' },
|
||||
{ name: 'Arbre' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Stator',
|
||||
subComponents: [
|
||||
{ name: 'Corps' },
|
||||
{ name: 'Chambres' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système d\'étanchéité',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Joint d\'étanchéité',
|
||||
subComponents: [
|
||||
{ name: 'Joint radial' },
|
||||
{ name: 'Joint axial' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Rotor', 'Stator', 'Joint d\'étanchéité'],
|
||||
specifications: {
|
||||
débit: '10-500 L/min',
|
||||
pression: '50-350 bar',
|
||||
type: 'Piston/Palette/Engrenage'
|
||||
}
|
||||
},
|
||||
|
||||
// Machines de contrôle
|
||||
{
|
||||
id: 10,
|
||||
name: 'Capteur de température',
|
||||
category: 'Contrôle',
|
||||
description: 'Instrument de mesure de température industrielle',
|
||||
maintenanceFrequency: 'Annuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de mesure',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Élément sensible',
|
||||
subComponents: [
|
||||
{ name: 'Fil de platine' },
|
||||
{ name: 'Isolation' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Câblage',
|
||||
subComponents: [
|
||||
{ name: 'Fils de connexion' },
|
||||
{ name: 'Gaine de protection' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de transmission',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Transmetteur',
|
||||
subComponents: [
|
||||
{ name: 'Circuit électronique' },
|
||||
{ name: 'Affichage' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Élément sensible', 'Câblage', 'Transmetteur'],
|
||||
specifications: {
|
||||
plage: '-50 à +500°C',
|
||||
précision: '±0.5°C',
|
||||
type: 'PT100/PT1000/Thermocouple'
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
name: 'Manomètre',
|
||||
category: 'Contrôle',
|
||||
description: 'Instrument de mesure de pression',
|
||||
maintenanceFrequency: 'Annuelle',
|
||||
components: [
|
||||
{
|
||||
name: 'Système de mesure',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Tube de Bourdon',
|
||||
subComponents: [
|
||||
{ name: 'Tube' },
|
||||
{ name: 'Extrémité fixe' },
|
||||
{ name: 'Extrémité mobile' }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Cadran',
|
||||
subComponents: [
|
||||
{ name: 'Échelle' },
|
||||
{ name: 'Aiguille' }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Système de connexion',
|
||||
subComponents: [
|
||||
{
|
||||
name: 'Joint',
|
||||
subComponents: [
|
||||
{ name: 'Joint d\'étanchéité' },
|
||||
{ name: 'Filetage' }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
criticalParts: ['Tube de Bourdon', 'Cadran', 'Joint'],
|
||||
specifications: {
|
||||
plage: '0-600 bar',
|
||||
précision: '±1%',
|
||||
type: 'Analogique/Numérique'
|
||||
}
|
||||
}
|
||||
])
|
||||
|
||||
// Catégories disponibles
|
||||
const categories = ref([
|
||||
'Production',
|
||||
'Transformation',
|
||||
'Manutention',
|
||||
'Traitement',
|
||||
'Contrôle'
|
||||
])
|
||||
|
||||
export function useMachineTypes() {
|
||||
const getTypes = () => machineTypes.value
|
||||
|
||||
const getTypeById = (id) => {
|
||||
return machineTypes.value.find(type => type.id === id)
|
||||
}
|
||||
|
||||
const getTypesByCategory = (category) => {
|
||||
return machineTypes.value.filter(type => type.category === category)
|
||||
}
|
||||
|
||||
const getCategories = () => categories.value
|
||||
|
||||
const addType = (newType) => {
|
||||
const id = Math.max(...machineTypes.value.map(t => t.id)) + 1
|
||||
machineTypes.value.push({
|
||||
id,
|
||||
...newType
|
||||
})
|
||||
}
|
||||
|
||||
const updateType = (id, updatedType) => {
|
||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||
if (index !== -1) {
|
||||
machineTypes.value[index] = { ...machineTypes.value[index], ...updatedType }
|
||||
}
|
||||
}
|
||||
|
||||
const deleteType = (id) => {
|
||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||
if (index !== -1) {
|
||||
machineTypes.value.splice(index, 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Méthodes pour la hiérarchie
|
||||
const flattenComponents = (components, level = 0) => {
|
||||
let flat = []
|
||||
components.forEach(comp => {
|
||||
flat.push({ ...comp, level })
|
||||
if (comp.subComponents && comp.subComponents.length > 0) {
|
||||
flat = flat.concat(flattenComponents(comp.subComponents, level + 1))
|
||||
}
|
||||
})
|
||||
return flat
|
||||
}
|
||||
|
||||
const getComponentHierarchy = (typeId) => {
|
||||
const type = getTypeById(typeId)
|
||||
if (!type || !type.components) return []
|
||||
return flattenComponents(type.components)
|
||||
}
|
||||
|
||||
return {
|
||||
getTypes,
|
||||
getTypeById,
|
||||
getTypesByCategory,
|
||||
getCategories,
|
||||
addType,
|
||||
updateType,
|
||||
deleteType,
|
||||
flattenComponents,
|
||||
getComponentHierarchy
|
||||
}
|
||||
}
|
||||
117
app/composables/useMachineTypesApi.js
Normal file
117
app/composables/useMachineTypesApi.js
Normal file
@@ -0,0 +1,117 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
const machineTypes = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
export function useMachineTypesApi() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadMachineTypes = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/types/machines')
|
||||
if (result.success) {
|
||||
machineTypes.value = result.data
|
||||
showInfo(`Chargement de ${machineTypes.value.length} type(s) de machine réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des types de machines:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createMachineType = async (typeData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/types/machines', typeData)
|
||||
if (result.success) {
|
||||
machineTypes.value.push(result.data)
|
||||
showSuccess(`Type de machine "${typeData.name}" créé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateMachineType = async (id, typeData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/types/machines/${id}`, typeData)
|
||||
if (result.success) {
|
||||
const index = machineTypes.value.findIndex(type => type.id === id)
|
||||
if (index !== -1) {
|
||||
machineTypes.value[index] = result.data
|
||||
}
|
||||
showSuccess(`Type de machine "${typeData.name}" mis à jour avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMachineType = async (id) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/types/machines/${id}`)
|
||||
if (result.success) {
|
||||
const deletedType = machineTypes.value.find(type => type.id === id)
|
||||
machineTypes.value = machineTypes.value.filter(type => type.id !== id)
|
||||
showSuccess(`Type de machine "${deletedType?.name || 'inconnu'}" supprimé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineTypeById = async (id) => {
|
||||
// D'abord chercher dans le cache local
|
||||
const localType = machineTypes.value.find(type => type.id === id)
|
||||
if (localType) {
|
||||
return { success: true, data: localType }
|
||||
}
|
||||
|
||||
// Si pas trouvé localement, récupérer depuis l'API
|
||||
try {
|
||||
const result = await get(`/types/machines/${id}`)
|
||||
if (result.success) {
|
||||
// Ajouter au cache local
|
||||
machineTypes.value.push(result.data)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la récupération du type de machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineTypes = () => machineTypes.value
|
||||
const isLoading = () => loading.value
|
||||
|
||||
return {
|
||||
machineTypes,
|
||||
loading,
|
||||
loadMachineTypes,
|
||||
createMachineType,
|
||||
updateMachineType,
|
||||
deleteMachineType,
|
||||
getMachineTypeById,
|
||||
getMachineTypes,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
123
app/composables/useMachines.js
Normal file
123
app/composables/useMachines.js
Normal file
@@ -0,0 +1,123 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
const machines = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
export function useMachines() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadMachines = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/machines')
|
||||
if (result.success) {
|
||||
machines.value = result.data
|
||||
showInfo(`Chargement de ${machines.value.length} machine(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des machines:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createMachine = async (machineData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/machines', machineData)
|
||||
if (result.success) {
|
||||
machines.value.push(result.data)
|
||||
showSuccess(`Machine "${machineData.name}" créée avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createMachineFromType = async (machineData, typeMachine) => {
|
||||
// Créer la machine avec la structure héritée du type
|
||||
const machineWithStructure = {
|
||||
...machineData,
|
||||
typeMachineId: typeMachine.id,
|
||||
// La structure sera automatiquement héritée du type
|
||||
// Les composants et pièces seront créés automatiquement
|
||||
}
|
||||
|
||||
return await createMachine(machineWithStructure)
|
||||
}
|
||||
|
||||
const updateMachineData = async (id, machineData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/machines/${id}`, machineData)
|
||||
if (result.success) {
|
||||
const index = machines.value.findIndex(machine => machine.id === id)
|
||||
if (index !== -1) {
|
||||
machines.value[index] = result.data
|
||||
}
|
||||
showSuccess(`Machine "${machineData.name}" mise à jour avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteMachine = async (id) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/machines/${id}`)
|
||||
if (result.success) {
|
||||
const deletedMachine = machines.value.find(machine => machine.id === id)
|
||||
machines.value = machines.value.filter(machine => machine.id !== id)
|
||||
showSuccess(`Machine "${deletedMachine?.name || 'inconnu'}" supprimée avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression de la machine:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getMachineById = (id) => {
|
||||
return machines.value.find(machine => machine.id === id)
|
||||
}
|
||||
|
||||
const getMachinesBySite = (siteId) => {
|
||||
return machines.value.filter(machine => machine.siteId === siteId)
|
||||
}
|
||||
|
||||
const getMachinesByType = (typeMachineId) => {
|
||||
return machines.value.filter(machine => machine.typeMachineId === typeMachineId)
|
||||
}
|
||||
|
||||
const getMachines = () => machines.value
|
||||
const isLoading = () => loading.value
|
||||
|
||||
return {
|
||||
machines,
|
||||
loading,
|
||||
loadMachines,
|
||||
createMachine,
|
||||
createMachineFromType,
|
||||
updateMachine: updateMachineData,
|
||||
deleteMachine,
|
||||
getMachineById,
|
||||
getMachinesBySite,
|
||||
getMachinesByType,
|
||||
getMachines,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
134
app/composables/usePieces.js
Normal file
134
app/composables/usePieces.js
Normal file
@@ -0,0 +1,134 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
const pieces = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
export function usePieces() {
|
||||
const { showSuccess, showError, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadPieces = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/pieces')
|
||||
if (result.success) {
|
||||
pieces.value = result.data
|
||||
showInfo(`Chargement de ${pieces.value.length} pièce(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des pièces:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getPiecesByMachine = async (machineId) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get(`/pieces/machine/${machineId}`)
|
||||
if (result.success) {
|
||||
return { success: true, data: result.data }
|
||||
}
|
||||
return { success: false, error: result.error }
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des pièces:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getPiecesByComposant = async (composantId) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get(`/pieces/composant/${composantId}`)
|
||||
if (result.success) {
|
||||
return { success: true, data: result.data }
|
||||
}
|
||||
return { success: false, error: result.error }
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des pièces:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createPiece = async (pieceData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/pieces', pieceData)
|
||||
if (result.success) {
|
||||
pieces.value.push(result.data)
|
||||
showSuccess(`Pièce "${pieceData.name}" créée avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création de la pièce:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updatePieceData = async (id, pieceData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/pieces/${id}`, pieceData)
|
||||
if (result.success) {
|
||||
const index = pieces.value.findIndex(piece => piece.id === id)
|
||||
if (index !== -1) {
|
||||
pieces.value[index] = result.data
|
||||
}
|
||||
showSuccess(`Pièce "${pieceData.name}" mise à jour avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour de la pièce:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deletePiece = async (id) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/pieces/${id}`)
|
||||
if (result.success) {
|
||||
const deletedPiece = pieces.value.find(piece => piece.id === id)
|
||||
pieces.value = pieces.value.filter(piece => piece.id !== id)
|
||||
showSuccess(`Pièce "${deletedPiece?.name || 'inconnu'}" supprimée avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression de la pièce:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getPieceById = (id) => {
|
||||
return pieces.value.find(piece => piece.id === id)
|
||||
}
|
||||
|
||||
const getPieces = () => pieces.value
|
||||
const isLoading = () => loading.value
|
||||
|
||||
return {
|
||||
pieces,
|
||||
loading,
|
||||
loadPieces,
|
||||
getPiecesByMachine,
|
||||
getPiecesByComposant,
|
||||
createPiece,
|
||||
updatePiece: updatePieceData,
|
||||
deletePiece,
|
||||
getPieceById,
|
||||
getPieces,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
100
app/composables/useSites.js
Normal file
100
app/composables/useSites.js
Normal file
@@ -0,0 +1,100 @@
|
||||
import { ref } from 'vue'
|
||||
import { useToast } from './useToast'
|
||||
import { useApi } from './useApi'
|
||||
|
||||
const sites = ref([])
|
||||
const loading = ref(false)
|
||||
|
||||
export function useSites() {
|
||||
const { showSuccess, showInfo } = useToast()
|
||||
const { get, post, patch, delete: del } = useApi()
|
||||
|
||||
const loadSites = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await get('/sites')
|
||||
if (result.success) {
|
||||
sites.value = result.data
|
||||
showInfo(`Chargement de ${sites.value.length} site(s) réussi`)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Erreur lors du chargement des sites:', error)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const createSite = async (siteData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await post('/sites', siteData)
|
||||
if (result.success) {
|
||||
sites.value.push(result.data)
|
||||
showSuccess(`Site "${siteData.name}" créé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la création du site:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const updateSite = async (id, siteData) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await patch(`/sites/${id}`, siteData)
|
||||
if (result.success) {
|
||||
const index = sites.value.findIndex(site => site.id === id)
|
||||
if (index !== -1) {
|
||||
sites.value[index] = result.data
|
||||
}
|
||||
showSuccess(`Site "${siteData.name}" mis à jour avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la mise à jour du site:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const deleteSite = async (id) => {
|
||||
loading.value = true
|
||||
try {
|
||||
const result = await del(`/sites/${id}`)
|
||||
if (result.success) {
|
||||
const deletedSite = sites.value.find(site => site.id === id)
|
||||
sites.value = sites.value.filter(site => site.id !== id)
|
||||
showSuccess(`Site "${deletedSite?.name || 'inconnu'}" supprimé avec succès`)
|
||||
}
|
||||
return result
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la suppression du site:', error)
|
||||
return { success: false, error: error.message }
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const getSiteById = (id) => {
|
||||
return sites.value.find(site => site.id === id)
|
||||
}
|
||||
|
||||
const getSites = () => sites.value
|
||||
const isLoading = () => loading.value
|
||||
|
||||
return {
|
||||
sites,
|
||||
loading,
|
||||
loadSites,
|
||||
createSite,
|
||||
updateSite,
|
||||
deleteSite,
|
||||
getSiteById,
|
||||
getSites,
|
||||
isLoading
|
||||
}
|
||||
}
|
||||
66
app/composables/useToast.js
Normal file
66
app/composables/useToast.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { ref } from 'vue'
|
||||
|
||||
const toasts = ref([])
|
||||
let nextId = 1
|
||||
|
||||
export function useToast() {
|
||||
const showToast = (message, type = 'info', duration = 5000) => {
|
||||
const id = nextId++
|
||||
const toast = {
|
||||
id,
|
||||
message,
|
||||
type,
|
||||
visible: true
|
||||
}
|
||||
|
||||
toasts.value.push(toast)
|
||||
|
||||
// Auto-remove after duration
|
||||
setTimeout(() => {
|
||||
removeToast(id)
|
||||
}, duration)
|
||||
|
||||
return id
|
||||
}
|
||||
|
||||
const showSuccess = (message, duration = 5000) => {
|
||||
return showToast(message, 'success', duration)
|
||||
}
|
||||
|
||||
const showError = (message, duration = 7000) => {
|
||||
return showToast(message, 'error', duration)
|
||||
}
|
||||
|
||||
const showWarning = (message, duration = 6000) => {
|
||||
return showToast(message, 'warning', duration)
|
||||
}
|
||||
|
||||
const showInfo = (message, duration = 5000) => {
|
||||
return showToast(message, 'info', duration)
|
||||
}
|
||||
|
||||
const removeToast = (id) => {
|
||||
const index = toasts.value.findIndex(toast => toast.id === id)
|
||||
if (index !== -1) {
|
||||
toasts.value[index].visible = false
|
||||
setTimeout(() => {
|
||||
toasts.value.splice(index, 1)
|
||||
}, 300) // Animation duration
|
||||
}
|
||||
}
|
||||
|
||||
const clearAll = () => {
|
||||
toasts.value = []
|
||||
}
|
||||
|
||||
return {
|
||||
toasts,
|
||||
showToast,
|
||||
showSuccess,
|
||||
showError,
|
||||
showWarning,
|
||||
showInfo,
|
||||
removeToast,
|
||||
clearAll
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user