codevdesign 2.0.11 → 2.0.13

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