codevdesign 1.0.6 → 1.0.8

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,131 +1,203 @@
1
- <template>
2
- <v-toolbar
3
- color="primary"
4
- height="72px"
5
- elevation="1"
6
- >
7
- <v-row
8
- class="pl-6 pr-6"
9
- align="center"
10
- no-gutters
11
- >
12
- <!-- Première colonne : Logo -->
13
- <v-col cols="auto">
14
- <a href="/">
15
- <img
16
- v-if="texteVide(logoUrl)"
17
- id="pivImage"
18
- src="/images/QUEBEC_blanc.svg"
19
- height="72"
20
- :alt="$t('csqc.pivFooter.logoAlt')"
21
- />
22
- <img
23
- v-else
24
- id="pivImage"
25
- :src="logoUrl"
26
- height="72"
27
- :alt="$t('csqc.pivFooter.logoAlt')"
28
- />
29
- </a>
30
- </v-col>
31
-
32
- <!-- Colonne pour le nom de l'application (Pour le mode desktop) -->
33
- <v-col
34
- v-if="!estMobile"
35
- class="d-flex justify-center"
36
- >
37
- <v-app-bar-title
38
- class="pl-12 ml-12"
39
- style="font-size: 16px !important"
40
- >
41
- {{ $t('nom_application') }}
42
- </v-app-bar-title>
43
- </v-col>
44
-
45
- <!-- Colonne pour le bouton de langue et icône d'aide -->
46
- <v-col class="d-none d-flex justify-end">
47
- <!-- langue -->
48
- <v-btn
49
- variant="text"
50
- @click="enregistrerLangue()"
51
- >{{ $t('csqc.pivEntete.langue') }}
52
- </v-btn>
53
-
54
- <!-- icône d'aide si dispo -->
55
- <v-btn
56
- v-if="aideUrl"
57
- icon="mdi-help-circle-outline"
58
- :href="aideUrl"
59
- target="_blank"
60
- rel="noopener noreferrer"
61
- style="margin-top: -6px"
62
- >
63
- </v-btn>
64
- </v-col>
65
-
66
- <!-- Colonne pour le nom de l'application (Pour le mode mobile) -->
67
- <v-col
68
- v-if="props.estMobile"
69
- cols="12"
70
- >
71
- <v-app-bar-title style="font-size: 16px !important">
72
- {{ $t('nom_application') }}
73
- </v-app-bar-title>
74
- </v-col>
75
- </v-row>
76
- </v-toolbar>
77
- </template>
78
-
79
- <script setup lang="ts">
80
- import { useLocale } from 'vuetify'
81
-
82
- const { current } = useLocale()
83
- const texteVide = (texte: string | undefined, retirerEspace: boolean = true): boolean => {
84
- let retour = texte === undefined || texte === null || texte === ''
85
-
86
- if (!retour && retirerEspace) {
87
- const temp = texte
88
- retour = temp!.replace(' ', '') === ''
89
- }
90
-
91
- return retour
92
- }
93
- const props = defineProps({
94
- estMobile: {
95
- type: Boolean,
96
- required: true,
97
- },
98
- urlBase: {
99
- type: String,
100
- required: true,
101
- },
102
- aideUrl: { type: String, default: '' },
103
- logoUrl: {
104
- type: String,
105
- default: '',
106
- },
107
- })
108
- const emit = defineEmits(['changementLangue'])
109
- // Fonction pour enregistrer la langue
110
-
111
- const enregistrerLangue = (): void => {
112
- const langueDispo: string = current.value === 'fr' ? 'en' : 'fr'
113
- let returnUrl = window.location.pathname + window.location.search
114
- if (import.meta.env.MODE === 'development') {
115
- returnUrl = '/'
116
- }
117
- window.location.href =
118
- props.urlBase + `/Traducteur/SetLanguage?culture=${langueDispo}&returnUrl=${encodeURIComponent(returnUrl)}`
119
- emit('changementLangue')
120
- }
121
- </script>
122
-
123
- <style scoped>
124
- .container {
125
- max-width: none !important;
126
- }
127
- .theme--light.v-app-bar.v-toolbar.v-sheet {
128
- background: #095797;
129
- color: #fff;
130
- }
131
- </style>
1
+ <template>
2
+ <v-toolbar
3
+ color="primary"
4
+ height="72px"
5
+ elevation="1"
6
+ >
7
+ <v-row
8
+ class="pl-6 pr-6"
9
+ align="center"
10
+ no-gutters
11
+ >
12
+ <!-- Première colonne : Logo -->
13
+ <v-col cols="auto">
14
+ <a
15
+ :href="href"
16
+ :target="cssUrlValide ? '_blank' : null"
17
+ :rel="cssUrlValide ? 'noopener noreferrer' : null"
18
+ >
19
+ <!-- Placeholder (même taille) pendant la décision -->
20
+ <div
21
+ v-if="!ready"
22
+ class="logo-placeholder"
23
+ ></div>
24
+ <!-- On ne rend l'image qu'une fois la source choisie -->
25
+ <img
26
+ v-else
27
+ class="logo-img"
28
+ id="pivImage"
29
+ :src="currentSrc!"
30
+ :alt="$t('csqc.pivFooter.logoAlt')"
31
+ decoding="async"
32
+ loading="eager"
33
+ @error="ErreurLogo"
34
+ />
35
+ </a>
36
+ </v-col>
37
+
38
+ <!-- Colonne pour le nom de l'application (Pour le mode desktop) -->
39
+ <v-col
40
+ v-if="!estMobile"
41
+ class="d-flex justify-center"
42
+ >
43
+ <v-app-bar-title
44
+ class="pl-12 ml-12"
45
+ style="font-size: 16px !important"
46
+ >
47
+ {{ formulaireNom }}
48
+ </v-app-bar-title>
49
+ </v-col>
50
+
51
+ <!-- Colonne pour le bouton de langue et icône d'aide -->
52
+ <v-col class="d-none d-flex justify-end">
53
+ <!-- langue -->
54
+ <v-btn
55
+ variant="text"
56
+ @click="enregistrerLangue()"
57
+ >{{ $t('csqc.pivEntete.langue') }}
58
+ </v-btn>
59
+
60
+ <!-- icône d'aide si dispo -->
61
+ <v-btn
62
+ v-if="aideUrl"
63
+ icon="mdi-help-circle-outline"
64
+ :href="aideUrl"
65
+ target="_blank"
66
+ rel="noopener noreferrer"
67
+ style="margin-top: -6px"
68
+ >
69
+ </v-btn>
70
+ </v-col>
71
+
72
+ <!-- Colonne pour le nom de l'application (Pour le mode mobile) -->
73
+ <v-col
74
+ v-if="props.estMobile"
75
+ cols="12"
76
+ >
77
+ <v-app-bar-title style="font-size: 16px !important">
78
+ {{ formulaireNom }}
79
+ </v-app-bar-title>
80
+ </v-col>
81
+ </v-row>
82
+ </v-toolbar>
83
+ </template>
84
+
85
+ <script setup lang="ts">
86
+ import { ref, watch, computed } from 'vue'
87
+ import { useLocale } from 'vuetify'
88
+ import { useI18n } from 'vue-i18n'
89
+
90
+ const { current } = useLocale()
91
+ const props = defineProps({
92
+ estMobile: { type: Boolean, default: false },
93
+ urlBase: { type: String, required: true },
94
+ aideUrl: { type: String, default: '' },
95
+ cssUrl: { type: String, default: '' },
96
+ logoUrl: { type: String, default: '' },
97
+ lienLogo: { type: String, default: '' },
98
+ formulaireId: { type: Number, default: 0 },
99
+ formulaireNom: { type: String, default: '' },
100
+ })
101
+ const emit = defineEmits(['changementLangue'])
102
+ const { t } = useI18n()
103
+
104
+ const FALLBACK = '/images/QUEBEC_blanc.svg'
105
+ const currentSrc = ref<string | null>(null) // pas d'image tant que null
106
+ const ready = ref(false)
107
+
108
+ const formulaireNom = computed(() => {
109
+ return props.formulaireNom || t('nom_application')
110
+ })
111
+
112
+ const href = computed(() => (props.cssUrl?.trim() ? props.cssUrl.trim() : '/'))
113
+ const cssUrlValide = computed(() => /^https?:\/\//i.test(href.value))
114
+
115
+ let loadToken = 0 // ← identifiant de “requête” pour annuler logiquement
116
+
117
+ // Sur changement de l’URL du logo, on tente de le charger, sinon fallback apres 3.5 secs
118
+ watch(
119
+ () => props.logoUrl,
120
+ async (nouvelle, ancienne) => {
121
+ const url = (nouvelle ?? '').trim()
122
+
123
+ // même URL → ne rien faire
124
+ if (url === (ancienne ?? '').trim() && currentSrc.value !== null) return
125
+
126
+ // pas d’URL → fallback immédiat
127
+ if (!url) {
128
+ currentSrc.value = FALLBACK
129
+ ready.value = true
130
+ return
131
+ }
132
+
133
+ // nouvelle tentative (avec “annulation logique”)
134
+ const token = ++loadToken
135
+ ready.value = false
136
+ const ok = await loadWithTimeout(url, 3500)
137
+ if (token !== loadToken) return // une nouvelle tentative a démarré entre-temps
138
+
139
+ currentSrc.value = ok ? url : FALLBACK
140
+ ready.value = true
141
+ },
142
+ { immediate: true },
143
+ )
144
+
145
+ // Charge une image avec un timeout
146
+ function loadWithTimeout(url: string, timeoutMs: number): Promise<boolean> {
147
+ return new Promise<boolean>(resolve => {
148
+ const img = new Image()
149
+ const timer = setTimeout(() => {
150
+ // trop long → on abandonne
151
+ img.src = '' // stoppe le chargement
152
+ resolve(false)
153
+ }, timeoutMs)
154
+
155
+ img.onload = () => {
156
+ clearTimeout(timer)
157
+ resolve(true)
158
+ }
159
+ img.onerror = () => {
160
+ clearTimeout(timer)
161
+ resolve(false)
162
+ }
163
+ img.src = url
164
+ })
165
+ }
166
+
167
+ // Si l'image choisie a un problème, switch sur le fallback
168
+ function ErreurLogo() {
169
+ if (currentSrc.value !== FALLBACK) currentSrc.value = FALLBACK
170
+ }
171
+
172
+ const enregistrerLangue = (): void => {
173
+ const langueDispo: string = current.value === 'fr' ? 'en' : 'fr'
174
+ let returnUrl = window.location.pathname + window.location.search
175
+ if (import.meta.env.MODE === 'development') {
176
+ returnUrl = '/'
177
+ }
178
+ window.location.href =
179
+ props.urlBase + `/Traducteur/SetLanguage?culture=${langueDispo}&returnUrl=${encodeURIComponent(returnUrl)}`
180
+ emit('changementLangue')
181
+ }
182
+ </script>
183
+
184
+ <style scoped>
185
+ .container {
186
+ max-width: none !important;
187
+ }
188
+ .theme--light.v-app-bar.v-toolbar.v-sheet {
189
+ background: #095797;
190
+
191
+ color: #fff;
192
+ }
193
+ .logo-placeholder {
194
+ height: 72px;
195
+ width: 180px;
196
+ }
197
+ .logo-img {
198
+ height: 72px;
199
+ transition: opacity 0.15s;
200
+ opacity: 1;
201
+ display: block;
202
+ }
203
+ </style>
package/index.ts CHANGED
@@ -8,6 +8,7 @@ import pivEntete from './composants/gabarit/pivEntete.vue'
8
8
  import pivFooter from './composants/gabarit/pivPiedPage.vue'
9
9
  import csqcMenu from './composants/gabarit/csqcMenu.vue'
10
10
  import csqcConfirmation from './composants/csqcConfirmation.vue'
11
+ import csqcSaisie from './composants/csqcModaleSaisie.vue'
11
12
  import csqcDate from './composants/csqcDate.vue'
12
13
  import csqcTable from './composants/csqcTable/csqcTable.vue'
13
14
  import csqcCodeBudgetaire from './composants/csqcCodeBudgetaireGenerique.vue'
@@ -43,6 +44,7 @@ export {
43
44
  csqcAlerteErreur,
44
45
  csqcDialogue,
45
46
  csqcConfirmation,
47
+ csqcSaisie,
46
48
  csqcDate,
47
49
  csqcOptionSwitch,
48
50
  csqcRecherche,
@@ -68,5 +70,5 @@ export {
68
70
  response,
69
71
  NotificationGabaritDefaut,
70
72
  csqcAppAxios,
71
- csqcRafraichisseurToken
73
+ csqcRafraichisseurToken,
72
74
  }
@@ -1,18 +1,18 @@
1
- export interface MenuItem {
2
- nom: string
3
- path: string
4
- droit: string
5
- }
6
-
7
- export interface SousListe {
8
- droit: string
9
- id: number
10
- nom: string
11
- }
12
-
13
- export interface SousListeItems {
14
- parentId: number
15
- nom: string
16
- path: string
17
- droit: string
18
- }
1
+ export interface MenuItem {
2
+ nom: string
3
+ path: string
4
+ droit: string
5
+ }
6
+
7
+ export interface SousListe {
8
+ droit: string
9
+ id: number
10
+ nom: string
11
+ }
12
+
13
+ export interface SousListeItems {
14
+ parentId: number
15
+ nom: string
16
+ path: string
17
+ droit: string
18
+ }
@@ -1,31 +1,31 @@
1
- import type { DataTableCompareFunction, DataTableHeader, FilterFunction } from 'vuetify'
2
- import { HeaderCellProps } from 'vuetify/lib/components/VDataTable/types.mjs';
3
- import { SelectItemKey } from 'vuetify/lib/util/helpers.mjs';
4
-
5
- class datatableColonne<T = any> implements DataTableHeader<T> {
6
- key?: 'data-table-group' | 'data-table-select' | 'data-table-expand' | (string & {});
7
- value?: SelectItemKey<T>;
8
- title?: string;
9
- fixed?: boolean | 'start' | 'end';
10
- align?: 'start' | 'end' | 'center';
11
- width?: number | string;
12
- minWidth?: number | string;
13
- maxWidth?: number | string;
14
- nowrap?: boolean;
15
- intent?: number;
16
- headerProps?: Record<string, any>;
17
- cellProps?: HeaderCellProps;
18
- sortable?: boolean;
19
- sort?: DataTableCompareFunction;
20
- sortRaw?: DataTableCompareFunction;
21
- filter?: FilterFunction;
22
- children?: DataTableHeader<T>[];
23
-
24
- constructor(title: string, key: string) {
25
- this.title = title
26
- this.key = key
27
- this.align = key === 'action' ? 'end' : key === 'estActif' ? 'center' : 'start'
28
- this.sortable = key !== 'action'
29
- }
30
- }
31
- export default datatableColonne
1
+ import type { DataTableCompareFunction, DataTableHeader, FilterFunction } from 'vuetify'
2
+ import { HeaderCellProps } from 'vuetify/lib/components/VDataTable/types.mjs';
3
+ import { SelectItemKey } from 'vuetify/lib/util/helpers.mjs';
4
+
5
+ class datatableColonne<T = any> implements DataTableHeader<T> {
6
+ key?: 'data-table-group' | 'data-table-select' | 'data-table-expand' | (string & {});
7
+ value?: SelectItemKey<T>;
8
+ title?: string;
9
+ fixed?: boolean | 'start' | 'end';
10
+ align?: 'start' | 'end' | 'center';
11
+ width?: number | string;
12
+ minWidth?: number | string;
13
+ maxWidth?: number | string;
14
+ nowrap?: boolean;
15
+ intent?: number;
16
+ headerProps?: Record<string, any>;
17
+ cellProps?: HeaderCellProps;
18
+ sortable?: boolean;
19
+ sort?: DataTableCompareFunction;
20
+ sortRaw?: DataTableCompareFunction;
21
+ filter?: FilterFunction;
22
+ children?: DataTableHeader<T>[];
23
+
24
+ constructor(title: string, key: string) {
25
+ this.title = title
26
+ this.key = key
27
+ this.align = key === 'action' ? 'end' : key === 'estActif' ? 'center' : 'start'
28
+ this.sortable = key !== 'action'
29
+ }
30
+ }
31
+ export default datatableColonne