codevdesign 2.0.12 → 2.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/composants/csqcChaise/chaiseConteneur.vue +370 -372
- package/composants/csqcDialogue.vue +120 -120
- package/composants/csqcImportCSV.vue +124 -126
- package/composants/csqcRecherche.vue +218 -219
- package/composants/csqcTable/csqcTable.vue +846 -847
- package/composants/csqcTable/csqcTableModaleChoixColonnes.vue +829 -831
- package/composants/csqcTiroir.vue +198 -197
- package/package.json +1 -1
- package/plugins/vuetify.ts +42 -4
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-dialog
|
|
3
|
-
v-model="dialog"
|
|
4
|
-
class="pa-0 ma-0"
|
|
5
|
-
:width="largeur"
|
|
6
|
-
:fullscreen="display.xs.value"
|
|
7
|
-
max-width="650"
|
|
8
|
-
:persistent="props.persistant"
|
|
9
|
-
v-bind="$attrs"
|
|
10
|
-
@keydown.esc="!persistant ? annuler : ''"
|
|
11
|
-
@click:outside="!persistant ? annuler : ''"
|
|
12
|
-
>
|
|
13
|
-
<v-card
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
:
|
|
55
|
-
:
|
|
56
|
-
|
|
57
|
-
@click="okBouton"
|
|
58
|
-
>
|
|
59
|
-
{{ btnOkTexte ? btnOkTexte : $t('csqc.bouton.ok') }}
|
|
60
|
-
</
|
|
61
|
-
</v-card-actions>
|
|
62
|
-
</v-card>
|
|
63
|
-
</v-dialog>
|
|
64
|
-
</template>
|
|
65
|
-
|
|
66
|
-
<script setup lang="ts">
|
|
67
|
-
import { ref } from 'vue'
|
|
68
|
-
import { useDisplay } from 'vuetify'
|
|
69
|
-
|
|
70
|
-
const display = useDisplay()
|
|
71
|
-
|
|
72
|
-
// Déclaration des props
|
|
73
|
-
const props = defineProps({
|
|
74
|
-
largeur: { type: String, default: '50vw' },
|
|
75
|
-
persistant: { type: Boolean, default: true },
|
|
76
|
-
operationEnCours: { type: Boolean, default: false },
|
|
77
|
-
btnAnnuler: { type: Boolean, default: true },
|
|
78
|
-
btnOk: { type: Boolean, default: true },
|
|
79
|
-
btnAnnulerTexte: { type: String, default: '' },
|
|
80
|
-
btnOkTexte: { type: String, default: '' },
|
|
81
|
-
titre: { type: String, default: '' },
|
|
82
|
-
btnOkDesactiver: { type: Boolean, default: false },
|
|
83
|
-
estDialogueAlerte: { type: Boolean, default: false },
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
// Déclaration des événements émis
|
|
87
|
-
const emit = defineEmits(['annuler', 'ok'])
|
|
88
|
-
|
|
89
|
-
// Gestion de l'état du dialogue
|
|
90
|
-
const dialog = ref(false)
|
|
91
|
-
|
|
92
|
-
// Méthodes pour gérer l'ouverture et la fermeture
|
|
93
|
-
const ouvrir = () => {
|
|
94
|
-
dialog.value = true
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const fermer = () => {
|
|
98
|
-
dialog.value = false
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Gestion des actions des boutons
|
|
102
|
-
const annuler = () => {
|
|
103
|
-
emit('annuler')
|
|
104
|
-
fermer()
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const okBouton = () => {
|
|
108
|
-
emit('ok')
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// permet d'exporter les 2 actions
|
|
112
|
-
defineExpose({ ouvrir, fermer })
|
|
113
|
-
</script>
|
|
114
|
-
|
|
115
|
-
<style lang="css" scoped>
|
|
116
|
-
.v-card__text,
|
|
117
|
-
.v-card__title {
|
|
118
|
-
word-break: normal; /* empeche le wrap de couper un mot en XS */
|
|
119
|
-
}
|
|
120
|
-
</style>
|
|
1
|
+
<template>
|
|
2
|
+
<v-dialog
|
|
3
|
+
v-model="dialog"
|
|
4
|
+
class="pa-0 ma-0"
|
|
5
|
+
:width="largeur"
|
|
6
|
+
:fullscreen="display.xs.value"
|
|
7
|
+
max-width="650"
|
|
8
|
+
:persistent="props.persistant"
|
|
9
|
+
v-bind="$attrs"
|
|
10
|
+
@keydown.esc="!persistant ? annuler : ''"
|
|
11
|
+
@click:outside="!persistant ? annuler : ''"
|
|
12
|
+
>
|
|
13
|
+
<v-card
|
|
14
|
+
color="background"
|
|
15
|
+
class="pa-0 ma-0 pl-8 pt-8"
|
|
16
|
+
>
|
|
17
|
+
<!-- Bouton en haut à droite -->
|
|
18
|
+
<v-btn
|
|
19
|
+
icon="mdi-close"
|
|
20
|
+
variant="text"
|
|
21
|
+
class="position-absolute iconeHover"
|
|
22
|
+
color="primary"
|
|
23
|
+
style="right: 5px; top: 5px"
|
|
24
|
+
@click="annuler"
|
|
25
|
+
></v-btn>
|
|
26
|
+
|
|
27
|
+
<v-card-title
|
|
28
|
+
class="pa-0 ma-0 pb-6 headline"
|
|
29
|
+
style="font-size: 24px; white-space: normal; word-break: break-word"
|
|
30
|
+
>
|
|
31
|
+
<slot name="titre"></slot>
|
|
32
|
+
<div text-h5><span v-html="titre"></span></div>
|
|
33
|
+
</v-card-title>
|
|
34
|
+
|
|
35
|
+
<v-card-text class="pa-0 ma-0 pb-6 pr-6">
|
|
36
|
+
<v-container>
|
|
37
|
+
<slot></slot>
|
|
38
|
+
<slot name="content"></slot>
|
|
39
|
+
</v-container>
|
|
40
|
+
</v-card-text>
|
|
41
|
+
<v-card-actions class="my-2 d-flex justify-end pr-6 pb-5">
|
|
42
|
+
<slot name="actions"></slot>
|
|
43
|
+
<bouton-tertiaire
|
|
44
|
+
v-if="btnAnnuler"
|
|
45
|
+
:loading="operationEnCours"
|
|
46
|
+
@click="annuler"
|
|
47
|
+
>
|
|
48
|
+
{{ btnAnnulerTexte ? btnAnnulerTexte : $t('csqc.bouton.annuler') }}
|
|
49
|
+
</bouton-tertiaire>
|
|
50
|
+
|
|
51
|
+
<bouton-primaire
|
|
52
|
+
v-if="btnOk"
|
|
53
|
+
class="Gouttiere"
|
|
54
|
+
:color="props.estDialogueAlerte ? 'rouge' : 'primary'"
|
|
55
|
+
:loading="operationEnCours"
|
|
56
|
+
:disabled="btnOkDesactiver"
|
|
57
|
+
@click="okBouton"
|
|
58
|
+
>
|
|
59
|
+
{{ btnOkTexte ? btnOkTexte : $t('csqc.bouton.ok') }}
|
|
60
|
+
</bouton-primaire>
|
|
61
|
+
</v-card-actions>
|
|
62
|
+
</v-card>
|
|
63
|
+
</v-dialog>
|
|
64
|
+
</template>
|
|
65
|
+
|
|
66
|
+
<script setup lang="ts">
|
|
67
|
+
import { ref } from 'vue'
|
|
68
|
+
import { useDisplay } from 'vuetify'
|
|
69
|
+
|
|
70
|
+
const display = useDisplay()
|
|
71
|
+
|
|
72
|
+
// Déclaration des props
|
|
73
|
+
const props = defineProps({
|
|
74
|
+
largeur: { type: String, default: '50vw' },
|
|
75
|
+
persistant: { type: Boolean, default: true },
|
|
76
|
+
operationEnCours: { type: Boolean, default: false },
|
|
77
|
+
btnAnnuler: { type: Boolean, default: true },
|
|
78
|
+
btnOk: { type: Boolean, default: true },
|
|
79
|
+
btnAnnulerTexte: { type: String, default: '' },
|
|
80
|
+
btnOkTexte: { type: String, default: '' },
|
|
81
|
+
titre: { type: String, default: '' },
|
|
82
|
+
btnOkDesactiver: { type: Boolean, default: false },
|
|
83
|
+
estDialogueAlerte: { type: Boolean, default: false },
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
// Déclaration des événements émis
|
|
87
|
+
const emit = defineEmits(['annuler', 'ok'])
|
|
88
|
+
|
|
89
|
+
// Gestion de l'état du dialogue
|
|
90
|
+
const dialog = ref(false)
|
|
91
|
+
|
|
92
|
+
// Méthodes pour gérer l'ouverture et la fermeture
|
|
93
|
+
const ouvrir = () => {
|
|
94
|
+
dialog.value = true
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const fermer = () => {
|
|
98
|
+
dialog.value = false
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Gestion des actions des boutons
|
|
102
|
+
const annuler = () => {
|
|
103
|
+
emit('annuler')
|
|
104
|
+
fermer()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const okBouton = () => {
|
|
108
|
+
emit('ok')
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// permet d'exporter les 2 actions
|
|
112
|
+
defineExpose({ ouvrir, fermer })
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<style lang="css" scoped>
|
|
116
|
+
.v-card__text,
|
|
117
|
+
.v-card__title {
|
|
118
|
+
word-break: normal; /* empeche le wrap de couper un mot en XS */
|
|
119
|
+
}
|
|
120
|
+
</style>
|
|
@@ -1,126 +1,124 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<
|
|
4
|
-
color="success"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
.trim()
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
emit('import',
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<bouton-secondaire
|
|
4
|
+
color="success"
|
|
5
|
+
:loading="chargement"
|
|
6
|
+
v-bind="$attrs"
|
|
7
|
+
@click="importCsv"
|
|
8
|
+
>
|
|
9
|
+
{{ boutonTexte }}
|
|
10
|
+
<template #append>
|
|
11
|
+
<v-icon icon="mdi-microsoft-excel"></v-icon>
|
|
12
|
+
</template>
|
|
13
|
+
</bouton-secondaire>
|
|
14
|
+
|
|
15
|
+
<input
|
|
16
|
+
ref="fileInput"
|
|
17
|
+
type="file"
|
|
18
|
+
accept=".csv"
|
|
19
|
+
style="display: none"
|
|
20
|
+
@change="handleFileUpload"
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
</template>
|
|
24
|
+
|
|
25
|
+
<script setup lang="ts">
|
|
26
|
+
import { ref, computed } from 'vue'
|
|
27
|
+
import { useI18n } from 'vue-i18n'
|
|
28
|
+
|
|
29
|
+
// Props
|
|
30
|
+
const props = withDefaults(
|
|
31
|
+
defineProps<{
|
|
32
|
+
boutonTexte?: string
|
|
33
|
+
erreurTexte?: string
|
|
34
|
+
chargement?: boolean
|
|
35
|
+
}>(),
|
|
36
|
+
{
|
|
37
|
+
chargement: false, // défaut
|
|
38
|
+
},
|
|
39
|
+
)
|
|
40
|
+
const emit = defineEmits(['import', 'import-erreur'])
|
|
41
|
+
|
|
42
|
+
const { t } = useI18n()
|
|
43
|
+
|
|
44
|
+
const boutonTexte = computed(() => props.boutonTexte ?? t('csqc.bouton.importer'))
|
|
45
|
+
const erreurTexte = computed(() => props.erreurTexte ?? t('csqc.csqcImportCSV.erreur.lectureFichier'))
|
|
46
|
+
|
|
47
|
+
// Références
|
|
48
|
+
const fileInput = ref<HTMLInputElement | null>(null)
|
|
49
|
+
const csvFile = ref<File | null>(null)
|
|
50
|
+
|
|
51
|
+
// Méthodes
|
|
52
|
+
function importCsv() {
|
|
53
|
+
fileInput.value?.click()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function handleFileUpload(event: Event) {
|
|
57
|
+
const target = event.target as HTMLInputElement
|
|
58
|
+
const file = target.files?.[0]
|
|
59
|
+
|
|
60
|
+
if (file?.name.toLowerCase().endsWith('.csv')) {
|
|
61
|
+
csvFile.value = file
|
|
62
|
+
|
|
63
|
+
const reader = new FileReader()
|
|
64
|
+
|
|
65
|
+
reader.onload = () => {
|
|
66
|
+
try {
|
|
67
|
+
let text = reader.result as string
|
|
68
|
+
|
|
69
|
+
// Supprime BOM UTF-8 si présent
|
|
70
|
+
if (text.charCodeAt(0) === 0xfeff) {
|
|
71
|
+
text = text.slice(1)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const lignes = text
|
|
75
|
+
.trim()
|
|
76
|
+
.split(/\r?\n/)
|
|
77
|
+
.filter(row => row.trim() !== '') // ignore lignes vides
|
|
78
|
+
|
|
79
|
+
if (lignes.length === 0) {
|
|
80
|
+
emit('import-erreur', 'Le fichier CSV est vide.')
|
|
81
|
+
return
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Détection automatique du séparateur
|
|
85
|
+
const separateur = detecterSeparateur(lignes[0]!)
|
|
86
|
+
|
|
87
|
+
// Découpage des lignes
|
|
88
|
+
const data: string[][] = lignes.map(row => row.split(separateur).map(cell => cell.trim()))
|
|
89
|
+
|
|
90
|
+
emit('import', data)
|
|
91
|
+
} catch (error) {
|
|
92
|
+
emit('import-erreur', erreurTexte.value || t('csqc.csqcImportCSV.erreur.lectureFichier'))
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
reader.onerror = () => {
|
|
97
|
+
emit('import-erreur', t('csqc.csqcImportCSV.erreur.lectureFichier'))
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
reader.readAsText(file)
|
|
101
|
+
} else {
|
|
102
|
+
const message = erreurTexte.value || t('csqc.csqcImportCSV.erreur.erreur')
|
|
103
|
+
emit('import-erreur', message)
|
|
104
|
+
csvFile.value = null
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Fonction pour détecter le séparateur le plus probable
|
|
109
|
+
function detecterSeparateur(ligne: string): string {
|
|
110
|
+
const separateursTestés = [',', ';', '\t', '|']
|
|
111
|
+
let meilleurSeparateur = ','
|
|
112
|
+
let maxColonnes = 0
|
|
113
|
+
|
|
114
|
+
for (const sep of separateursTestés) {
|
|
115
|
+
const nb = ligne.split(sep).length
|
|
116
|
+
if (nb > maxColonnes) {
|
|
117
|
+
maxColonnes = nb
|
|
118
|
+
meilleurSeparateur = sep
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return meilleurSeparateur
|
|
123
|
+
}
|
|
124
|
+
</script>
|