codevdesign 1.0.43 → 1.0.44

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,118 +1,118 @@
1
- <template>
2
- <v-dialog
3
- v-model="dialog"
4
- v-bind="$attrs"
5
- class="pa-0 ma-0"
6
- :width="largeur"
7
- :fullscreen="display.xs.value"
8
- max-width="650"
9
- :persistent="props.persistant"
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 couleurHover"
19
- style="top: 5px; right: 5px"
20
- @click="annuler"
21
- ></v-btn>
22
-
23
- <v-card-title
24
- class="pa-0 ma-0 pb-6"
25
- style="font-size: 24px; white-space: normal; word-break: break-word"
26
- >
27
- <slot name="titre"></slot>
28
- <div text-h5><span v-html="titre"></span></div>
29
- </v-card-title>
30
-
31
- <v-card-text class="pa-0 ma-0 pb-6 pr-6">
32
- <v-container>
33
- <slot></slot>
34
- <slot name="content"></slot>
35
- </v-container>
36
- </v-card-text>
37
- <v-card-actions class="my-2 d-flex justify-end pr-6 pb-5">
38
- <slot name="actions"></slot>
39
- <v-btn
40
- v-if="btnAnnuler"
41
- color="primary"
42
- :loading="operationEnCours"
43
- variant="text"
44
- @click="annuler"
45
- >
46
- {{ btnAnnulerTexte ? btnAnnulerTexte : $t('csqc.bouton.annuler') }}
47
- </v-btn>
48
-
49
- <v-btn
50
- v-if="btnOk"
51
- class="Gouttiere"
52
- color="primary"
53
- :loading="operationEnCours"
54
- :disabled="btnOkDesactiver"
55
- variant="flat"
56
- @click="okBouton"
57
- >
58
- {{ btnOkTexte ? btnOkTexte : $t('csqc.bouton.ok') }}
59
- </v-btn>
60
- </v-card-actions>
61
- </v-card>
62
- </v-dialog>
63
- </template>
64
-
65
- <script setup lang="ts">
66
- import { ref } from 'vue'
67
- import { useDisplay } from 'vuetify'
68
-
69
- const display = useDisplay()
70
-
71
- // Déclaration des props
72
- const props = defineProps({
73
- largeur: { type: String, default: '50vw' },
74
- persistant: { type: Boolean, default: true },
75
- operationEnCours: { type: Boolean, default: false },
76
- btnAnnuler: { type: Boolean, default: true },
77
- btnOk: { type: Boolean, default: true },
78
- btnAnnulerTexte: { type: String, default: '' },
79
- btnOkTexte: { type: String, default: '' },
80
- titre: { type: String, default: '' },
81
- btnOkDesactiver: { type: Boolean, default: false },
82
- })
83
-
84
- // Déclaration des événements émis
85
- const emit = defineEmits(['annuler', 'ok'])
86
-
87
- // Gestion de l'état du dialogue
88
- const dialog = ref(false)
89
-
90
- // Méthodes pour gérer l'ouverture et la fermeture
91
- const ouvrir = () => {
92
- dialog.value = true
93
- }
94
-
95
- const fermer = () => {
96
- dialog.value = false
97
- }
98
-
99
- // Gestion des actions des boutons
100
- const annuler = () => {
101
- emit('annuler')
102
- fermer()
103
- }
104
-
105
- const okBouton = () => {
106
- emit('ok')
107
- }
108
-
109
- // permet d'exporter les 2 actions
110
- defineExpose({ ouvrir, fermer })
111
- </script>
112
-
113
- <style lang="css" scoped>
114
- .v-card__text,
115
- .v-card__title {
116
- word-break: normal; /* empeche le wrap de couper un mot en XS */
117
- }
118
- </style>
1
+ <template>
2
+ <v-dialog
3
+ v-model="dialog"
4
+ v-bind="$attrs"
5
+ class="pa-0 ma-0"
6
+ :width="largeur"
7
+ :fullscreen="display.xs.value"
8
+ max-width="650"
9
+ :persistent="props.persistant"
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
+ style="top: 5px; right: 5px"
20
+ @click="annuler"
21
+ ></v-btn>
22
+
23
+ <v-card-title
24
+ class="pa-0 ma-0 pb-6"
25
+ style="font-size: 24px; white-space: normal; word-break: break-word"
26
+ >
27
+ <slot name="titre"></slot>
28
+ <div text-h5><span v-html="titre"></span></div>
29
+ </v-card-title>
30
+
31
+ <v-card-text class="pa-0 ma-0 pb-6 pr-6">
32
+ <v-container>
33
+ <slot></slot>
34
+ <slot name="content"></slot>
35
+ </v-container>
36
+ </v-card-text>
37
+ <v-card-actions class="my-2 d-flex justify-end pr-6 pb-5">
38
+ <slot name="actions"></slot>
39
+ <v-btn
40
+ v-if="btnAnnuler"
41
+ color="primary"
42
+ :loading="operationEnCours"
43
+ variant="text"
44
+ @click="annuler"
45
+ >
46
+ {{ btnAnnulerTexte ? btnAnnulerTexte : $t('csqc.bouton.annuler') }}
47
+ </v-btn>
48
+
49
+ <v-btn
50
+ v-if="btnOk"
51
+ class="Gouttiere"
52
+ color="primary"
53
+ :loading="operationEnCours"
54
+ :disabled="btnOkDesactiver"
55
+ variant="flat"
56
+ @click="okBouton"
57
+ >
58
+ {{ btnOkTexte ? btnOkTexte : $t('csqc.bouton.ok') }}
59
+ </v-btn>
60
+ </v-card-actions>
61
+ </v-card>
62
+ </v-dialog>
63
+ </template>
64
+
65
+ <script setup lang="ts">
66
+ import { ref } from 'vue'
67
+ import { useDisplay } from 'vuetify'
68
+
69
+ const display = useDisplay()
70
+
71
+ // Déclaration des props
72
+ const props = defineProps({
73
+ largeur: { type: String, default: '50vw' },
74
+ persistant: { type: Boolean, default: true },
75
+ operationEnCours: { type: Boolean, default: false },
76
+ btnAnnuler: { type: Boolean, default: true },
77
+ btnOk: { type: Boolean, default: true },
78
+ btnAnnulerTexte: { type: String, default: '' },
79
+ btnOkTexte: { type: String, default: '' },
80
+ titre: { type: String, default: '' },
81
+ btnOkDesactiver: { type: Boolean, default: false },
82
+ })
83
+
84
+ // Déclaration des événements émis
85
+ const emit = defineEmits(['annuler', 'ok'])
86
+
87
+ // Gestion de l'état du dialogue
88
+ const dialog = ref(false)
89
+
90
+ // Méthodes pour gérer l'ouverture et la fermeture
91
+ const ouvrir = () => {
92
+ dialog.value = true
93
+ }
94
+
95
+ const fermer = () => {
96
+ dialog.value = false
97
+ }
98
+
99
+ // Gestion des actions des boutons
100
+ const annuler = () => {
101
+ emit('annuler')
102
+ fermer()
103
+ }
104
+
105
+ const okBouton = () => {
106
+ emit('ok')
107
+ }
108
+
109
+ // permet d'exporter les 2 actions
110
+ defineExpose({ ouvrir, fermer })
111
+ </script>
112
+
113
+ <style lang="css" scoped>
114
+ .v-card__text,
115
+ .v-card__title {
116
+ word-break: normal; /* empeche le wrap de couper un mot en XS */
117
+ }
118
+ </style>
@@ -41,6 +41,14 @@
41
41
  :nom-fichier="excelNomFichier"
42
42
  class="mt-1 ml-1 float-right"
43
43
  />
44
+ <v-icon
45
+ v-if="permettreChoixColonnes"
46
+ color="grisMoyen"
47
+ class="mt-1 ml-1 float-right"
48
+ @click.stop="ouvrirChoixColonnes"
49
+ >
50
+ mdi-table-edit
51
+ </v-icon>
44
52
  </template>
45
53
  <template #rechercheAvanceeTitre>
46
54
  <slot name="rechercheAvanceeTitre" />
@@ -64,7 +72,7 @@
64
72
  <v-data-table
65
73
  ref="datatable"
66
74
  v-bind="$attrs"
67
- :headers="colonnes"
75
+ :headers="colonnesAffichees"
68
76
  :item-key="itemKey"
69
77
  :items="liste"
70
78
  :search="recherche"
@@ -123,166 +131,311 @@
123
131
  :largeur="modaleSupprimerLargeur"
124
132
  @confirmer="supprimer"
125
133
  />
134
+ <modale-choix
135
+ ref="modaleChoix"
136
+ v-if="permettreChoixColonnes"
137
+ :urlbase="urlbase"
138
+ :formulaire-id="formulaireId"
139
+ :identifiant="identifiant"
140
+ :colonnes="colonnesPourChoix"
141
+ :choix-origine="choixOrigineNormalise"
142
+ @selection="selectionChoix"
143
+ @sauvegarde="sauvegardeChoix"
144
+ />
126
145
  </v-col>
127
146
  </v-row>
128
147
  </div>
129
148
  </template>
130
-
131
149
  <script setup lang="ts">
132
150
  /* eslint-disable @typescript-eslint/no-explicit-any */
151
+ import { computed, onMounted, ref, type PropType, type Slots } from 'vue'
152
+ import { useI18n } from 'vue-i18n'
153
+ import type { SortItem } from 'vuetify/lib/components/VDataTable/composables/sort.mjs'
133
154
 
134
- import { ref, computed, type Slots, type PropType } from 'vue'
135
155
  import Recherche from '../csqcRecherche.vue'
136
156
  import confirmation from '../csqcConfirmation.vue'
137
157
  import exportExcelComponent from './csqcTableExportExcel.vue'
138
- //import ModaleChoix from './csqc-table-modale-choix-colonnes.vue';
139
- //import axios from 'axios'
140
- import { useI18n } from 'vue-i18n'
158
+ import ModaleChoix from './csqcTableModaleChoixColonnes.vue'
159
+ import axios from '../../outils/appAxios'
141
160
  import Colonne from '../../modeles/composants/datatableColonne'
142
- import type { SortItem } from 'vuetify/lib/components/VDataTable/composables/sort.mjs'
143
161
 
162
+ type VueColonnes = {
163
+ nomVue: string
164
+ colonnes: string[]
165
+ defaut?: boolean
166
+ }
167
+
168
+ const slots = defineSlots<Slots>()
169
+ const emit = defineEmits(['ajouter', 'cliqueLigne', 'supprimer', 'modifier', 'donneesExportees', 'panneau:etat'])
170
+
171
+ // ============================================================================
144
172
  // Props
173
+ // ============================================================================
145
174
  const props = defineProps({
146
175
  barreHautAfficher: { type: Boolean, default: true },
176
+
147
177
  btnAjouter: { type: Boolean, default: true },
148
178
  btnAjouterTexte: { type: String, default: '' },
149
179
  btnModifier: { type: Boolean, default: true },
150
180
  btnSupprimer: { type: Boolean, default: true },
181
+
151
182
  chargementListe: { type: Boolean, default: false },
152
183
  operationEnCours: { type: Boolean, default: false },
153
- //choixSwitchOptionDepart: { type: Boolean, default: false },
154
- // classeRangee: { type: String, default: '' },
184
+
185
+ // Headers Vuetify
155
186
  colonnes: {
156
187
  type: Array as PropType<Colonne[]>,
157
188
  default: () => [],
158
189
  },
190
+
159
191
  densite: { type: String as PropType<'default' | 'comfortable' | 'compact'>, default: 'default' },
192
+
160
193
  excel: { type: Boolean, default: false },
161
194
  excelNomFichier: { type: String, default: 'csqc' },
162
- //filtresDepart: { type: Object, default: null },
163
- //flechesTri: { type: Boolean, default: false },
195
+
196
+ // Choix colonnes
164
197
  formulaireId: { type: Number, default: -1 },
165
- identifiant: {
166
- type: [String, null] as PropType<string | null>,
167
- default: null,
168
- },
198
+ identifiant: { type: String, default: '' },
199
+ urlbase: { type: String, default: '' },
200
+ permettreChoixColonnes: { type: Boolean, default: false },
201
+
202
+ // Table
169
203
  itemKey: { type: String, default: 'id' },
170
204
  itemsParPage: { type: Number, default: 10 },
205
+ itemsParPageOptions: { type: Array, default: () => [10, 25, 30, -1] },
171
206
  liste: {
172
207
  type: Array as PropType<Record<string, any>[]>,
173
208
  default: () => [],
174
209
  },
175
210
  hover: { type: Boolean, default: false },
176
- // modulerDense: { type: Boolean, default: false },
177
- // multifiltre: { type: Boolean, default: false },
178
- itemsParPageOptions: { type: Array, default: () => [10, 25, 30, -1] },
179
- //pageCourante: { type: Number, default: 1 },
180
- //paginationBottom: { type: Boolean, default: true },
181
- // paginationTop: { type: Boolean, default: false },
182
- // permettreChoixColonnes: { type: Boolean, default: false },
183
- // rechercheDepart: { type: String, default: '' },
211
+
212
+ // Recherche
184
213
  rechercheTexte: { type: String, default: '' },
185
214
  rechercheAfficher: { type: Boolean, default: true },
186
215
  rechercheAvancee: { type: Boolean, default: false },
187
216
  rechercheAvanceeTexte: { type: String, default: '' },
188
217
  rechercheAvanceeLargeur: { type: Number, default: 12 },
189
218
  rechercheAvanceeStyle: { type: String, default: '' },
190
- // selectionChoixColonnesDepart: { type: String, default: '' },
191
- // showSelect: { type: Boolean, default: false },
192
219
 
220
+ // Modale suppression
193
221
  modaleSupprimerChamp: { type: String, default: '' },
194
222
  modaleSupprimerTexte: { type: String, default: '' },
195
223
  modaleSupprimerTitre: { type: String, default: '' },
196
224
  modaleSupprimerLargeur: { type: String, default: '525px' },
225
+
226
+ // Tri
197
227
  triDescDepart: { type: Boolean, default: false },
198
228
  triParDepart: {
199
229
  type: [Array, String] as PropType<string | string[] | SortItem[] | undefined>,
200
230
  default: undefined,
201
231
  },
202
- //urlbase: { type: String, default: '' },
203
232
  })
204
233
 
205
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
206
- const slots = defineSlots<Slots>()
207
234
  const { t } = useI18n({ useScope: 'global' })
208
- const itemSelectionne = ref(null)
209
- const modaleSupprimer = ref<InstanceType<typeof confirmation> | null>(null)
210
- const supprimerTexte = computed(() => {
211
- if (itemSelectionne.value == null) return ''
212
-
213
- if (props.modaleSupprimerTexte != null && props.modaleSupprimerTexte != '') return props.modaleSupprimerTexte
235
+ const recherche = ref<string>('')
214
236
 
215
- return t('csqc.message.supprimerMessage', { nom: itemSelectionne?.value[props.modaleSupprimerChamp] ?? '' })
237
+ // Modale suppression (on garde l’item sélectionné)
238
+ const itemSelectionne = ref<any>(null)
239
+
240
+ // ============================================================================
241
+ // State - Choix de colonnes (vues sauvegardées) + sélection courante
242
+ // ============================================================================
243
+ const modaleChoix = ref<InstanceType<typeof ModaleChoix> | null>(null)
244
+ const openChoixColonnes = ref(false)
245
+ const choix = ref<VueColonnes[]>([]) // la liste des vues disponibles
246
+ const vueActive = ref<VueColonnes | null>(null) // optionnel: la vue "appliquée"
247
+ const valeurSelectionChoixColonnes = ref<string | null>(null) // nomVue sélectionné dans la modale / UI
248
+
249
+ // ============================================================================
250
+ // Charger le choix de colonnes sauvegardé s'il y a lieu
251
+ // ============================================================================
252
+ onMounted(async () => {
253
+ if (!props.permettreChoixColonnes) return
254
+
255
+ try {
256
+ const res: any = await axios
257
+ .getAxios()
258
+ .get(`${props.urlbase}/api/ComposantUI/Colonnes/${props.formulaireId}/Identifiant/${props.identifiant}`)
259
+
260
+ const payload = res?.data ?? res
261
+
262
+ if (!payload) {
263
+ choix.value = []
264
+ return
265
+ }
266
+
267
+ choix.value = typeof payload === 'string' ? JSON.parse(payload) : payload
268
+ } catch (e) {
269
+ choix.value = []
270
+ // console.debug(e)
271
+ }
216
272
  })
217
273
 
218
- const supprimerTitreTexte = computed(() => props.modaleSupprimerTitre || t('csqc.message.supprimerTitre'))
219
-
220
- // Fonction pour ouvrir le dialogue pour un item spécifique
221
- const ouvrirModaleSupprimer = (item: any) => {
222
- itemSelectionne.value = item
223
-
224
- //modaleSupprimer.value?.ouvrir()
225
- emit('supprimer', itemSelectionne.value)
274
+ // ============================================================================
275
+ // Computed - Normaliser pour la modale Choix colonne
276
+ // ============================================================================
277
+ const choixOrigineNormalise = computed(() =>
278
+ (choix.value ?? []).map(c => ({
279
+ _id: '',
280
+ nomVue: c.nomVue,
281
+ colonnes: c.colonnes ?? [],
282
+ defaut: c.defaut ?? false,
283
+ })),
284
+ )
285
+
286
+ // ============================================================================
287
+ // Actions - Modale choix colonnes
288
+ // ============================================================================
289
+ function ouvrirChoixColonnes() {
290
+ modaleChoix.value?.ouvrir()
226
291
  }
227
292
 
228
- const supprimer = () => {
229
- emit('supprimer', itemSelectionne.value)
293
+ function appliquerVue(vue: VueColonnes) {
294
+ vueActive.value = vue
295
+ openChoixColonnes.value = false
230
296
  }
231
297
 
232
- const recherche = ref<string>('')
233
- const chargerRecherche = (val: string) => {
234
- recherche.value = val
298
+ function selectionChoix(vue: VueColonnes) {
299
+ // on garde une trace du nom sélectionné (pour retrouver la vue plus tard)
300
+ valeurSelectionChoixColonnes.value = vue.nomVue
301
+ appliquerVue(vue)
235
302
  }
236
303
 
237
- const ajouter = () => {
238
- emit('ajouter')
239
- }
304
+ function sauvegardeChoix(vues: VueColonnes[]) {
305
+ if (!props.permettreChoixColonnes) return
240
306
 
241
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
242
- const cliqueLigne = (e: Event, { item }: { item: any }) => {
243
- emit('cliqueLigne', item)
244
- }
307
+ // si la sélection courante n’existe plus, on reset
308
+ if (
309
+ valeurSelectionChoixColonnes.value != null &&
310
+ vues.find(x => x.nomVue === valeurSelectionChoixColonnes.value) == null
311
+ ) {
312
+ valeurSelectionChoixColonnes.value = null
313
+ }
245
314
 
246
- const modifier = (item: any) => {
247
- emit('modifier', item)
315
+ choix.value = vues
316
+
317
+ // optionnel: appliquer automatiquement la vue par défaut
318
+ const defaut = vues.find(v => v.defaut)
319
+ if (defaut) appliquerVue(defaut)
248
320
  }
249
- const filteredItems = computed(() => {
250
- if (!recherche.value) return props.liste // Si rien écrit, affiche tout
251
321
 
252
- return props.liste.filter(item =>
253
- Object.values(item).some(val => String(val).toLowerCase().includes(recherche.value.toLowerCase())),
322
+ // ============================================================================
323
+ // Computed - Colonnes à envoyer à la modale (liste ordonnée + libellé)
324
+ // ============================================================================
325
+ const colonnesPourChoix = computed(() =>
326
+ props.colonnes
327
+ // on exclut l'action (souvent toujours visible) + colonnes "cachées"
328
+ .filter(c => c.key && c.key !== 'action' && (c as any).align !== 'd-none')
329
+ .map((c, idx) => ({
330
+ title: (c as any).title ?? (c as any).text ?? String((c as any).key ?? (c as any).value),
331
+ value: String((c as any).key ?? (c as any).value), // ← on force string
332
+ ordre: idx + 1,
333
+ })),
334
+ )
335
+
336
+ // ============================================================================
337
+ // Computed - Headers réellement affichés par la table (selon le choix actif)
338
+ // ============================================================================
339
+ const colonnesAffichees = computed(() => {
340
+ // 1) colonnes "disponibles" (on enlève celles explicitement cachées)
341
+ const colonnesFiltre = props.colonnes.filter(c => (c as any).align !== 'd-none')
342
+
343
+ // 2) si feature OFF ou pas de vues sauvegardées => on retourne tout
344
+ if (!props.permettreChoixColonnes) return colonnesFiltre
345
+ if (!choix.value?.length) return colonnesFiltre
346
+
347
+ // 3) retrouver la vue sélectionnée (sinon la défaut)
348
+ const choixSelection = choix.value.find(
349
+ x => valeurSelectionChoixColonnes.value === x.nomVue || (!valeurSelectionChoixColonnes.value && x.defaut),
254
350
  )
351
+ if (!choixSelection) return colonnesFiltre
352
+
353
+ // 4) reconstruire la liste de headers dans l’ordre sauvegardé
354
+ return choixSelection.colonnes.map(k => colonnesFiltre.find(c => String(c.key) === k)).filter(Boolean) as Colonne[]
255
355
  })
256
356
 
357
+ // ============================================================================
358
+ // Computed - Tri initial (Vuetify sort-by)
359
+ // ============================================================================
257
360
  const triDepart = computed<SortItem[] | undefined>(() => {
258
361
  if (props.triParDepart == null) return undefined
259
362
 
260
363
  const ordre = props.triDescDepart ? 'desc' : 'asc'
261
-
262
364
  if (typeof props.triParDepart === 'string') return [{ key: props.triParDepart, order: ordre }]
263
365
 
264
- //On a un tableau de tri
265
- let retour: SortItem[] = []
366
+ const retour: SortItem[] = []
266
367
  for (let i = 0; i < props.triParDepart.length; i += 1) {
267
368
  const tri = props.triParDepart[i]!
268
- if (typeof tri == 'string') retour.push({ key: tri, order: ordre })
269
- else retour.push(tri) //C'est un SortItem déjà bâti
369
+ if (typeof tri === 'string') retour.push({ key: tri, order: ordre })
370
+ else retour.push(tri)
270
371
  }
271
372
  return retour
272
373
  })
273
374
 
274
375
  const estMultiTriActif = computed(() => {
275
376
  if (props.triParDepart == null) return false
276
-
277
377
  if (typeof props.triParDepart === 'string') return false
278
-
279
378
  return true
280
379
  })
281
380
 
282
- const onPanelChange = (val: boolean) => {
381
+ // ============================================================================
382
+ // Computed - Export (filtrage local basé sur recherche)
383
+ // ============================================================================
384
+ const filteredItems = computed(() => {
385
+ if (!recherche.value) return props.liste
386
+ const q = recherche.value.toLowerCase()
387
+ return props.liste.filter(item => Object.values(item).some(val => String(val).toLowerCase().includes(q)))
388
+ })
389
+
390
+ // ============================================================================
391
+ // UI Actions - Recherche / Table events
392
+ // ============================================================================
393
+ function chargerRecherche(val: string) {
394
+ recherche.value = val
395
+ }
396
+
397
+ function ajouter() {
398
+ emit('ajouter')
399
+ }
400
+
401
+ function cliqueLigne(_e: Event, { item }: { item: any }) {
402
+ emit('cliqueLigne', item)
403
+ }
404
+
405
+ function modifier(item: any) {
406
+ emit('modifier', item)
407
+ }
408
+
409
+ // ============================================================================
410
+ // Suppression - Texte + actions
411
+ // ============================================================================
412
+ const supprimerTexte = computed(() => {
413
+ if (itemSelectionne.value == null) return ''
414
+
415
+ if (props.modaleSupprimerTexte) return props.modaleSupprimerTexte
416
+
417
+ return t('csqc.message.supprimerMessage', {
418
+ nom: itemSelectionne?.value?.[props.modaleSupprimerChamp] ?? '',
419
+ })
420
+ })
421
+
422
+ const supprimerTitreTexte = computed(() => props.modaleSupprimerTitre || t('csqc.message.supprimerTitre'))
423
+
424
+ function ouvrirModaleSupprimer(item: any) {
425
+ itemSelectionne.value = item
426
+ emit('supprimer', itemSelectionne.value) // tu sembles gérer la modale ailleurs
427
+ }
428
+
429
+ function supprimer() {
430
+ emit('supprimer', itemSelectionne.value)
431
+ }
432
+
433
+ // ============================================================================
434
+ // UI - Panneau recherche avancée
435
+ // ============================================================================
436
+ function onPanelChange(val: boolean) {
283
437
  emit('panneau:etat', val)
284
438
  }
285
- const emit = defineEmits(['ajouter', 'cliqueLigne', 'supprimer', 'modifier', 'donneesExportees', 'panneau:etat'])
286
439
  </script>
287
440
 
288
441
  <style scoped lang="css">