codevdesign 0.0.89 → 0.0.90
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/codeBudgetaireGenerique.vue +260 -260
- package/composants/csqcDate/csqcDate.vue +56 -56
- package/index.ts +66 -65
- package/package.json +1 -1
|
@@ -1,260 +1,260 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<v-form
|
|
4
|
-
ref="form"
|
|
5
|
-
v-model="formValide"
|
|
6
|
-
@submit.prevent
|
|
7
|
-
>
|
|
8
|
-
<v-combobox
|
|
9
|
-
v-model="codeBudgetaire"
|
|
10
|
-
:items="codeBudgetairesProp"
|
|
11
|
-
:label="label"
|
|
12
|
-
persistent-hint
|
|
13
|
-
variant="outlined"
|
|
14
|
-
hide-details="auto"
|
|
15
|
-
:error="!estValide"
|
|
16
|
-
:rules="[v => (estValide ? true : regleMessageErreur)]"
|
|
17
|
-
:disabled="disable"
|
|
18
|
-
:density="density"
|
|
19
|
-
:hint="afficherHint ? placeholder : ''"
|
|
20
|
-
:max-width="maxWidth || '100%'"
|
|
21
|
-
:min-width="minWidth || '100%'"
|
|
22
|
-
@blur="sauvegarder"
|
|
23
|
-
@keydown.enter="sauvegarder"
|
|
24
|
-
@keydown="caractereAutorises"
|
|
25
|
-
@update:modelValue="gererChangement"
|
|
26
|
-
@paste="gererPaste"
|
|
27
|
-
/>
|
|
28
|
-
</v-form>
|
|
29
|
-
</div>
|
|
30
|
-
</template>
|
|
31
|
-
|
|
32
|
-
<script setup lang="ts">
|
|
33
|
-
import { ref, computed, onMounted, nextTick } from 'vue'
|
|
34
|
-
import type { VForm } from 'vuetify/components'
|
|
35
|
-
|
|
36
|
-
const emit = defineEmits(['update:modelValue', 'update:codeBudgetairesProp'])
|
|
37
|
-
|
|
38
|
-
const props = withDefaults(
|
|
39
|
-
defineProps<{
|
|
40
|
-
codeBudgetairesProp: string[]
|
|
41
|
-
modelValue: string | null
|
|
42
|
-
label: string
|
|
43
|
-
disable: boolean
|
|
44
|
-
afficherHint?: boolean
|
|
45
|
-
regleMessageErreur: string
|
|
46
|
-
density?: 'default' | 'comfortable' | 'compact'
|
|
47
|
-
maxWidth?: string | number
|
|
48
|
-
minWidth?: string | number
|
|
49
|
-
format?: string
|
|
50
|
-
activerExtension?: boolean
|
|
51
|
-
}>(),
|
|
52
|
-
{
|
|
53
|
-
afficherHint: false,
|
|
54
|
-
format: '999-9-99999-999',
|
|
55
|
-
activerExtension: false,
|
|
56
|
-
},
|
|
57
|
-
)
|
|
58
|
-
|
|
59
|
-
const formValide = ref(false)
|
|
60
|
-
const form = ref<VForm | null>(null)
|
|
61
|
-
const codeBudgetaire = ref(props.modelValue ?? '')
|
|
62
|
-
const derniereValeurSauvegardee = ref<string | null>(null)
|
|
63
|
-
const format = props.format
|
|
64
|
-
const activerExtension = props.activerExtension
|
|
65
|
-
|
|
66
|
-
const estValide = computed(() => {
|
|
67
|
-
const val = codeBudgetaire.value?.toUpperCase().trim() || ''
|
|
68
|
-
const base = val.slice(0, 15)
|
|
69
|
-
const extension = val.slice(15)
|
|
70
|
-
|
|
71
|
-
if (!/^\d{3}-\d{1}-\d{5}-\d{3}$/.test(base)) return false
|
|
72
|
-
|
|
73
|
-
if (!activerExtension) return val.length === 15
|
|
74
|
-
|
|
75
|
-
if (val.length === 15) return true
|
|
76
|
-
if (val.length !== 22) return false
|
|
77
|
-
if (extension.length !== 7) return false
|
|
78
|
-
|
|
79
|
-
if (extension[3] !== '/') return false
|
|
80
|
-
if (!/^[A-Z0-9/]$/i.test(extension[0]!)) return false
|
|
81
|
-
|
|
82
|
-
const alphanumAt = [1, 2, 4, 5, 6]
|
|
83
|
-
return alphanumAt.every(i => /^[A-Z0-9]$/i.test(extension[i]!))
|
|
84
|
-
})
|
|
85
|
-
|
|
86
|
-
const caractereAutorises = (e: KeyboardEvent) => {
|
|
87
|
-
if (e.ctrlKey || e.metaKey) return
|
|
88
|
-
|
|
89
|
-
const touchesSpecifiques = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Home', 'End']
|
|
90
|
-
if (touchesSpecifiques.includes(e.key)) return
|
|
91
|
-
|
|
92
|
-
const input = e.target as HTMLInputElement
|
|
93
|
-
let position = input.selectionStart ?? 0
|
|
94
|
-
|
|
95
|
-
// Gestion de la partie de base (15 premiers caractères)
|
|
96
|
-
if (position < 15) {
|
|
97
|
-
if (!/^\d$/.test(e.key)) {
|
|
98
|
-
e.preventDefault()
|
|
99
|
-
return
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Insérer chiffre et auto-ajout des tirets
|
|
103
|
-
e.preventDefault()
|
|
104
|
-
|
|
105
|
-
const value = codeBudgetaire.value.replace(/-/g, '')
|
|
106
|
-
const clean = value.slice(0, 12) + e.key
|
|
107
|
-
|
|
108
|
-
let formatted = ''
|
|
109
|
-
if (clean.length > 0) formatted += clean.slice(0, 3)
|
|
110
|
-
if (clean.length > 3) formatted += '-' + clean.slice(3, 4)
|
|
111
|
-
if (clean.length > 4) formatted += '-' + clean.slice(4, 9)
|
|
112
|
-
if (clean.length > 9) formatted += '-' + clean.slice(9, 12)
|
|
113
|
-
|
|
114
|
-
codeBudgetaire.value = formatted.slice(0, 15)
|
|
115
|
-
|
|
116
|
-
nextTick(() => {
|
|
117
|
-
const newPos = codeBudgetaire.value.length
|
|
118
|
-
input.selectionStart = input.selectionEnd = newPos
|
|
119
|
-
})
|
|
120
|
-
|
|
121
|
-
return
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// --- Gestion de l'extension ---
|
|
125
|
-
if (!activerExtension || position >= 22 || codeBudgetaire.value.length >= 22) {
|
|
126
|
-
e.preventDefault()
|
|
127
|
-
return
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const extensionPos = position - 15
|
|
131
|
-
|
|
132
|
-
// Règle 1 : extension[0] = alphanum ou /
|
|
133
|
-
if (extensionPos === 0) {
|
|
134
|
-
if (!/^[A-Z0-9/]$/i.test(e.key)) {
|
|
135
|
-
e.preventDefault()
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Règle 2 : extension[1,2,4,5,6] = alphanum
|
|
142
|
-
if ([1, 2, 4, 5, 6].includes(extensionPos)) {
|
|
143
|
-
if (!/^[A-Z0-9]$/i.test(e.key)) {
|
|
144
|
-
e.preventDefault()
|
|
145
|
-
return
|
|
146
|
-
}
|
|
147
|
-
return
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Règle 3 : slash automatique à position 3 (index 18)
|
|
151
|
-
if (extensionPos === 3) {
|
|
152
|
-
e.preventDefault()
|
|
153
|
-
const before = codeBudgetaire.value.slice(0, position)
|
|
154
|
-
const after = codeBudgetaire.value.slice(position)
|
|
155
|
-
codeBudgetaire.value = before + '/' + after
|
|
156
|
-
nextTick(() => {
|
|
157
|
-
input.selectionStart = input.selectionEnd = position + 1
|
|
158
|
-
})
|
|
159
|
-
return
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Tout autre cas = bloqué
|
|
163
|
-
e.preventDefault()
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const formaterCodeBudgetaire = (valeur: string): string => {
|
|
167
|
-
if (!valeur) return ''
|
|
168
|
-
|
|
169
|
-
const upper = valeur.toUpperCase().replace(/[^A-Z0-9/]/g, '')
|
|
170
|
-
const chiffres = upper.replace(/[^0-9]/g, '').slice(0, 12)
|
|
171
|
-
|
|
172
|
-
let base = ''
|
|
173
|
-
if (chiffres.length > 0) base += chiffres.slice(0, 3)
|
|
174
|
-
if (chiffres.length > 3) base += '-' + chiffres.slice(3, 4)
|
|
175
|
-
if (chiffres.length > 4) base += '-' + chiffres.slice(4, 9)
|
|
176
|
-
if (chiffres.length > 9) base += '-' + chiffres.slice(9, 12)
|
|
177
|
-
|
|
178
|
-
if (!activerExtension || base.length < 15) return base
|
|
179
|
-
|
|
180
|
-
const reste = upper.slice(chiffres.length).replace(/[^A-Z0-9/]/gi, '')
|
|
181
|
-
|
|
182
|
-
// Extraire les 7 premiers caractères restants pour l’extension
|
|
183
|
-
let ext = reste.slice(0, 7).split('')
|
|
184
|
-
|
|
185
|
-
// Ne garder que le premier slash s’il est à l’index 0 ou 3
|
|
186
|
-
ext = ext.filter((c, i) => {
|
|
187
|
-
if (c !== '/') return true
|
|
188
|
-
return i === 0 || i === 3
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
// Enlever les slash non autorisés
|
|
192
|
-
ext = ext.map((c, i) => {
|
|
193
|
-
if (c === '/' && i !== 0 && i !== 3) return ''
|
|
194
|
-
if (c !== '/' && !/^[A-Z0-9]$/i.test(c)) return ''
|
|
195
|
-
return c
|
|
196
|
-
})
|
|
197
|
-
|
|
198
|
-
// Forcer le slash à la 4e position
|
|
199
|
-
if (ext.length > 3) {
|
|
200
|
-
ext[3] = '/'
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Réduire à 7 caractères
|
|
204
|
-
ext = ext.slice(0, 7)
|
|
205
|
-
|
|
206
|
-
return (base + ext.join('')).slice(0, 22)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const gererPaste = (e: ClipboardEvent) => {
|
|
210
|
-
e.preventDefault()
|
|
211
|
-
const clipboardData = e.clipboardData
|
|
212
|
-
if (!clipboardData) return
|
|
213
|
-
let pasted = clipboardData.getData('text') || ''
|
|
214
|
-
codeBudgetaire.value = formaterCodeBudgetaire(pasted)
|
|
215
|
-
|
|
216
|
-
setTimeout(() => {
|
|
217
|
-
const input = e.target as HTMLInputElement
|
|
218
|
-
input.selectionStart = input.selectionEnd = codeBudgetaire.value.length
|
|
219
|
-
}, 0)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
const sauvegarder = () => {
|
|
223
|
-
codeBudgetaire.value = formaterCodeBudgetaire(codeBudgetaire.value)
|
|
224
|
-
if (!estValide.value) return
|
|
225
|
-
if (codeBudgetaire.value === derniereValeurSauvegardee.value) return
|
|
226
|
-
|
|
227
|
-
const existe = props.codeBudgetairesProp.some(
|
|
228
|
-
item => item.trim().toUpperCase() === codeBudgetaire.value.trim().toUpperCase(),
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
if (!existe) {
|
|
232
|
-
const nouvelleListe = [...props.codeBudgetairesProp, codeBudgetaire.value]
|
|
233
|
-
emit('update:codeBudgetairesProp', nouvelleListe)
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
derniereValeurSauvegardee.value = codeBudgetaire.value
|
|
237
|
-
emit('update:modelValue', codeBudgetaire.value)
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const gererChangement = (val: string) => {
|
|
241
|
-
codeBudgetaire.value = formaterCodeBudgetaire(val)
|
|
242
|
-
|
|
243
|
-
const valeurFormatee = codeBudgetaire.value
|
|
244
|
-
const estDansListe = props.codeBudgetairesProp.includes(valeurFormatee)
|
|
245
|
-
|
|
246
|
-
if (estDansListe && valeurFormatee !== derniereValeurSauvegardee.value && estValide.value) {
|
|
247
|
-
sauvegarder()
|
|
248
|
-
}
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
onMounted(() => {
|
|
252
|
-
derniereValeurSauvegardee.value = codeBudgetaire.value
|
|
253
|
-
})
|
|
254
|
-
|
|
255
|
-
const placeholder = computed(() => {
|
|
256
|
-
const base = format.replace(/9/g, '0')
|
|
257
|
-
const extension = activerExtension ? '-XXX/XXX' : ''
|
|
258
|
-
return base + extension
|
|
259
|
-
})
|
|
260
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<div>
|
|
3
|
+
<v-form
|
|
4
|
+
ref="form"
|
|
5
|
+
v-model="formValide"
|
|
6
|
+
@submit.prevent
|
|
7
|
+
>
|
|
8
|
+
<v-combobox
|
|
9
|
+
v-model="codeBudgetaire"
|
|
10
|
+
:items="codeBudgetairesProp"
|
|
11
|
+
:label="label"
|
|
12
|
+
persistent-hint
|
|
13
|
+
variant="outlined"
|
|
14
|
+
hide-details="auto"
|
|
15
|
+
:error="!estValide"
|
|
16
|
+
:rules="[v => (estValide ? true : regleMessageErreur)]"
|
|
17
|
+
:disabled="disable"
|
|
18
|
+
:density="density"
|
|
19
|
+
:hint="afficherHint ? placeholder : ''"
|
|
20
|
+
:max-width="maxWidth || '100%'"
|
|
21
|
+
:min-width="minWidth || '100%'"
|
|
22
|
+
@blur="sauvegarder"
|
|
23
|
+
@keydown.enter="sauvegarder"
|
|
24
|
+
@keydown="caractereAutorises"
|
|
25
|
+
@update:modelValue="gererChangement"
|
|
26
|
+
@paste="gererPaste"
|
|
27
|
+
/>
|
|
28
|
+
</v-form>
|
|
29
|
+
</div>
|
|
30
|
+
</template>
|
|
31
|
+
|
|
32
|
+
<script setup lang="ts">
|
|
33
|
+
import { ref, computed, onMounted, nextTick } from 'vue'
|
|
34
|
+
import type { VForm } from 'vuetify/components'
|
|
35
|
+
|
|
36
|
+
const emit = defineEmits(['update:modelValue', 'update:codeBudgetairesProp'])
|
|
37
|
+
|
|
38
|
+
const props = withDefaults(
|
|
39
|
+
defineProps<{
|
|
40
|
+
codeBudgetairesProp: string[]
|
|
41
|
+
modelValue: string | null
|
|
42
|
+
label: string
|
|
43
|
+
disable: boolean
|
|
44
|
+
afficherHint?: boolean
|
|
45
|
+
regleMessageErreur: string
|
|
46
|
+
density?: 'default' | 'comfortable' | 'compact'
|
|
47
|
+
maxWidth?: string | number
|
|
48
|
+
minWidth?: string | number
|
|
49
|
+
format?: string
|
|
50
|
+
activerExtension?: boolean
|
|
51
|
+
}>(),
|
|
52
|
+
{
|
|
53
|
+
afficherHint: false,
|
|
54
|
+
format: '999-9-99999-999',
|
|
55
|
+
activerExtension: false,
|
|
56
|
+
},
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
const formValide = ref(false)
|
|
60
|
+
const form = ref<VForm | null>(null)
|
|
61
|
+
const codeBudgetaire = ref(props.modelValue ?? '')
|
|
62
|
+
const derniereValeurSauvegardee = ref<string | null>(null)
|
|
63
|
+
const format = props.format
|
|
64
|
+
const activerExtension = props.activerExtension
|
|
65
|
+
|
|
66
|
+
const estValide = computed(() => {
|
|
67
|
+
const val = codeBudgetaire.value?.toUpperCase().trim() || ''
|
|
68
|
+
const base = val.slice(0, 15)
|
|
69
|
+
const extension = val.slice(15)
|
|
70
|
+
|
|
71
|
+
if (!/^\d{3}-\d{1}-\d{5}-\d{3}$/.test(base)) return false
|
|
72
|
+
|
|
73
|
+
if (!activerExtension) return val.length === 15
|
|
74
|
+
|
|
75
|
+
if (val.length === 15) return true
|
|
76
|
+
if (val.length !== 22) return false
|
|
77
|
+
if (extension.length !== 7) return false
|
|
78
|
+
|
|
79
|
+
if (extension[3] !== '/') return false
|
|
80
|
+
if (!/^[A-Z0-9/]$/i.test(extension[0]!)) return false
|
|
81
|
+
|
|
82
|
+
const alphanumAt = [1, 2, 4, 5, 6]
|
|
83
|
+
return alphanumAt.every(i => /^[A-Z0-9]$/i.test(extension[i]!))
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
const caractereAutorises = (e: KeyboardEvent) => {
|
|
87
|
+
if (e.ctrlKey || e.metaKey) return
|
|
88
|
+
|
|
89
|
+
const touchesSpecifiques = ['Backspace', 'Delete', 'ArrowLeft', 'ArrowRight', 'Tab', 'Home', 'End']
|
|
90
|
+
if (touchesSpecifiques.includes(e.key)) return
|
|
91
|
+
|
|
92
|
+
const input = e.target as HTMLInputElement
|
|
93
|
+
let position = input.selectionStart ?? 0
|
|
94
|
+
|
|
95
|
+
// Gestion de la partie de base (15 premiers caractères)
|
|
96
|
+
if (position < 15) {
|
|
97
|
+
if (!/^\d$/.test(e.key)) {
|
|
98
|
+
e.preventDefault()
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Insérer chiffre et auto-ajout des tirets
|
|
103
|
+
e.preventDefault()
|
|
104
|
+
|
|
105
|
+
const value = codeBudgetaire.value.replace(/-/g, '')
|
|
106
|
+
const clean = value.slice(0, 12) + e.key
|
|
107
|
+
|
|
108
|
+
let formatted = ''
|
|
109
|
+
if (clean.length > 0) formatted += clean.slice(0, 3)
|
|
110
|
+
if (clean.length > 3) formatted += '-' + clean.slice(3, 4)
|
|
111
|
+
if (clean.length > 4) formatted += '-' + clean.slice(4, 9)
|
|
112
|
+
if (clean.length > 9) formatted += '-' + clean.slice(9, 12)
|
|
113
|
+
|
|
114
|
+
codeBudgetaire.value = formatted.slice(0, 15)
|
|
115
|
+
|
|
116
|
+
nextTick(() => {
|
|
117
|
+
const newPos = codeBudgetaire.value.length
|
|
118
|
+
input.selectionStart = input.selectionEnd = newPos
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// --- Gestion de l'extension ---
|
|
125
|
+
if (!activerExtension || position >= 22 || codeBudgetaire.value.length >= 22) {
|
|
126
|
+
e.preventDefault()
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const extensionPos = position - 15
|
|
131
|
+
|
|
132
|
+
// Règle 1 : extension[0] = alphanum ou /
|
|
133
|
+
if (extensionPos === 0) {
|
|
134
|
+
if (!/^[A-Z0-9/]$/i.test(e.key)) {
|
|
135
|
+
e.preventDefault()
|
|
136
|
+
return
|
|
137
|
+
}
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Règle 2 : extension[1,2,4,5,6] = alphanum
|
|
142
|
+
if ([1, 2, 4, 5, 6].includes(extensionPos)) {
|
|
143
|
+
if (!/^[A-Z0-9]$/i.test(e.key)) {
|
|
144
|
+
e.preventDefault()
|
|
145
|
+
return
|
|
146
|
+
}
|
|
147
|
+
return
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Règle 3 : slash automatique à position 3 (index 18)
|
|
151
|
+
if (extensionPos === 3) {
|
|
152
|
+
e.preventDefault()
|
|
153
|
+
const before = codeBudgetaire.value.slice(0, position)
|
|
154
|
+
const after = codeBudgetaire.value.slice(position)
|
|
155
|
+
codeBudgetaire.value = before + '/' + after
|
|
156
|
+
nextTick(() => {
|
|
157
|
+
input.selectionStart = input.selectionEnd = position + 1
|
|
158
|
+
})
|
|
159
|
+
return
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Tout autre cas = bloqué
|
|
163
|
+
e.preventDefault()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const formaterCodeBudgetaire = (valeur: string): string => {
|
|
167
|
+
if (!valeur) return ''
|
|
168
|
+
|
|
169
|
+
const upper = valeur.toUpperCase().replace(/[^A-Z0-9/]/g, '')
|
|
170
|
+
const chiffres = upper.replace(/[^0-9]/g, '').slice(0, 12)
|
|
171
|
+
|
|
172
|
+
let base = ''
|
|
173
|
+
if (chiffres.length > 0) base += chiffres.slice(0, 3)
|
|
174
|
+
if (chiffres.length > 3) base += '-' + chiffres.slice(3, 4)
|
|
175
|
+
if (chiffres.length > 4) base += '-' + chiffres.slice(4, 9)
|
|
176
|
+
if (chiffres.length > 9) base += '-' + chiffres.slice(9, 12)
|
|
177
|
+
|
|
178
|
+
if (!activerExtension || base.length < 15) return base
|
|
179
|
+
|
|
180
|
+
const reste = upper.slice(chiffres.length).replace(/[^A-Z0-9/]/gi, '')
|
|
181
|
+
|
|
182
|
+
// Extraire les 7 premiers caractères restants pour l’extension
|
|
183
|
+
let ext = reste.slice(0, 7).split('')
|
|
184
|
+
|
|
185
|
+
// Ne garder que le premier slash s’il est à l’index 0 ou 3
|
|
186
|
+
ext = ext.filter((c, i) => {
|
|
187
|
+
if (c !== '/') return true
|
|
188
|
+
return i === 0 || i === 3
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
// Enlever les slash non autorisés
|
|
192
|
+
ext = ext.map((c, i) => {
|
|
193
|
+
if (c === '/' && i !== 0 && i !== 3) return ''
|
|
194
|
+
if (c !== '/' && !/^[A-Z0-9]$/i.test(c)) return ''
|
|
195
|
+
return c
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
// Forcer le slash à la 4e position
|
|
199
|
+
if (ext.length > 3) {
|
|
200
|
+
ext[3] = '/'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Réduire à 7 caractères
|
|
204
|
+
ext = ext.slice(0, 7)
|
|
205
|
+
|
|
206
|
+
return (base + ext.join('')).slice(0, 22)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
const gererPaste = (e: ClipboardEvent) => {
|
|
210
|
+
e.preventDefault()
|
|
211
|
+
const clipboardData = e.clipboardData
|
|
212
|
+
if (!clipboardData) return
|
|
213
|
+
let pasted = clipboardData.getData('text') || ''
|
|
214
|
+
codeBudgetaire.value = formaterCodeBudgetaire(pasted)
|
|
215
|
+
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
const input = e.target as HTMLInputElement
|
|
218
|
+
input.selectionStart = input.selectionEnd = codeBudgetaire.value.length
|
|
219
|
+
}, 0)
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const sauvegarder = () => {
|
|
223
|
+
codeBudgetaire.value = formaterCodeBudgetaire(codeBudgetaire.value)
|
|
224
|
+
if (!estValide.value) return
|
|
225
|
+
if (codeBudgetaire.value === derniereValeurSauvegardee.value) return
|
|
226
|
+
|
|
227
|
+
const existe = props.codeBudgetairesProp.some(
|
|
228
|
+
item => item.trim().toUpperCase() === codeBudgetaire.value.trim().toUpperCase(),
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
if (!existe) {
|
|
232
|
+
const nouvelleListe = [...props.codeBudgetairesProp, codeBudgetaire.value]
|
|
233
|
+
emit('update:codeBudgetairesProp', nouvelleListe)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
derniereValeurSauvegardee.value = codeBudgetaire.value
|
|
237
|
+
emit('update:modelValue', codeBudgetaire.value)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const gererChangement = (val: string) => {
|
|
241
|
+
codeBudgetaire.value = formaterCodeBudgetaire(val)
|
|
242
|
+
|
|
243
|
+
const valeurFormatee = codeBudgetaire.value
|
|
244
|
+
const estDansListe = props.codeBudgetairesProp.includes(valeurFormatee)
|
|
245
|
+
|
|
246
|
+
if (estDansListe && valeurFormatee !== derniereValeurSauvegardee.value && estValide.value) {
|
|
247
|
+
sauvegarder()
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
onMounted(() => {
|
|
252
|
+
derniereValeurSauvegardee.value = codeBudgetaire.value
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
const placeholder = computed(() => {
|
|
256
|
+
const base = format.replace(/9/g, '0')
|
|
257
|
+
const extension = activerExtension ? '-XXX/XXX' : ''
|
|
258
|
+
return base + extension
|
|
259
|
+
})
|
|
260
|
+
</script>
|
|
@@ -1,56 +1,56 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<v-date-input
|
|
3
|
-
v-model="dateValeur"
|
|
4
|
-
@update:model-value="formatDate"
|
|
5
|
-
v-bind="$attrs"
|
|
6
|
-
variant="outlined"
|
|
7
|
-
prepend-icon=""
|
|
8
|
-
prepend-inner-icon="$calendar"
|
|
9
|
-
density="comfortable"
|
|
10
|
-
></v-date-input>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<script setup lang="ts">
|
|
14
|
-
import { ref, watch, computed } from 'vue'
|
|
15
|
-
import { VDateInput } from 'vuetify/labs/VDateInput'
|
|
16
|
-
|
|
17
|
-
const props = withDefaults(
|
|
18
|
-
defineProps<{
|
|
19
|
-
modelValue: string | Date | null
|
|
20
|
-
}>(),
|
|
21
|
-
{},
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
const emit = defineEmits(['update:modelValue'])
|
|
25
|
-
const dateValeur = ref<Date | string | null>(props.modelValue)
|
|
26
|
-
|
|
27
|
-
const formatDate = (date: Date | string | null) => {
|
|
28
|
-
if (date == null) {
|
|
29
|
-
emit('update:modelValue', null)
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (typeof date === 'string') {
|
|
34
|
-
emit('update:modelValue', props.modelValue)
|
|
35
|
-
return
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
//Transformer la date en string
|
|
39
|
-
const d = new Date(date)
|
|
40
|
-
const yyyy = d.getFullYear()
|
|
41
|
-
const mm = String(d.getMonth() + 1).padStart(2, '0')
|
|
42
|
-
const dd = String(d.getDate()).padStart(2, '0')
|
|
43
|
-
const formatte = `${yyyy}-${mm}-${dd}`
|
|
44
|
-
dateValeur.value = formatte
|
|
45
|
-
|
|
46
|
-
emit('update:modelValue', dateValeur.value)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Synchronise les props externes avec l'état interne
|
|
50
|
-
watch(
|
|
51
|
-
() => props.modelValue,
|
|
52
|
-
nouvelle => {
|
|
53
|
-
dateValeur.value = nouvelle
|
|
54
|
-
},
|
|
55
|
-
)
|
|
56
|
-
</script>
|
|
1
|
+
<template>
|
|
2
|
+
<v-date-input
|
|
3
|
+
v-model="dateValeur"
|
|
4
|
+
@update:model-value="formatDate"
|
|
5
|
+
v-bind="$attrs"
|
|
6
|
+
variant="outlined"
|
|
7
|
+
prepend-icon=""
|
|
8
|
+
prepend-inner-icon="$calendar"
|
|
9
|
+
density="comfortable"
|
|
10
|
+
></v-date-input>
|
|
11
|
+
</template>
|
|
12
|
+
|
|
13
|
+
<script setup lang="ts">
|
|
14
|
+
import { ref, watch, computed } from 'vue'
|
|
15
|
+
import { VDateInput } from 'vuetify/labs/VDateInput'
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(
|
|
18
|
+
defineProps<{
|
|
19
|
+
modelValue: string | Date | null
|
|
20
|
+
}>(),
|
|
21
|
+
{},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const emit = defineEmits(['update:modelValue'])
|
|
25
|
+
const dateValeur = ref<Date | string | null>(props.modelValue)
|
|
26
|
+
|
|
27
|
+
const formatDate = (date: Date | string | null) => {
|
|
28
|
+
if (date == null) {
|
|
29
|
+
emit('update:modelValue', null)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeof date === 'string') {
|
|
34
|
+
emit('update:modelValue', props.modelValue)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//Transformer la date en string
|
|
39
|
+
const d = new Date(date)
|
|
40
|
+
const yyyy = d.getFullYear()
|
|
41
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0')
|
|
42
|
+
const dd = String(d.getDate()).padStart(2, '0')
|
|
43
|
+
const formatte = `${yyyy}-${mm}-${dd}`
|
|
44
|
+
dateValeur.value = formatte
|
|
45
|
+
|
|
46
|
+
emit('update:modelValue', dateValeur.value)
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Synchronise les props externes avec l'état interne
|
|
50
|
+
watch(
|
|
51
|
+
() => props.modelValue,
|
|
52
|
+
nouvelle => {
|
|
53
|
+
dateValeur.value = nouvelle
|
|
54
|
+
},
|
|
55
|
+
)
|
|
56
|
+
</script>
|
package/index.ts
CHANGED
|
@@ -1,65 +1,66 @@
|
|
|
1
|
-
import csqcAlerteErreur from './composants/csqcAlerteErreur.vue'
|
|
2
|
-
import csqcDialogue from './composants/csqcDialogue.vue'
|
|
3
|
-
import csqcOptionSwitch from './composants/csqcOptionSwitch.vue'
|
|
4
|
-
import csqcRecherche from './composants/csqcRecherche.vue'
|
|
5
|
-
import csqcSnackbar from './composants/csqcSnackbar.vue'
|
|
6
|
-
import csqcTiroir from './composants/csqcTiroir.vue'
|
|
7
|
-
import pivEntete from './composants/gabarit/pivEntete.vue'
|
|
8
|
-
import pivFooter from './composants/gabarit/pivPiedPage.vue'
|
|
9
|
-
import csqcMenu from './composants/gabarit/csqcMenu.vue'
|
|
10
|
-
import csqcConfirmation from './composants/csqcConfirmation.vue'
|
|
11
|
-
import
|
|
12
|
-
import
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
import
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
import
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import
|
|
29
|
-
import
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
import
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
1
|
+
import csqcAlerteErreur from './composants/csqcAlerteErreur.vue'
|
|
2
|
+
import csqcDialogue from './composants/csqcDialogue.vue'
|
|
3
|
+
import csqcOptionSwitch from './composants/csqcOptionSwitch.vue'
|
|
4
|
+
import csqcRecherche from './composants/csqcRecherche.vue'
|
|
5
|
+
import csqcSnackbar from './composants/csqcSnackbar.vue'
|
|
6
|
+
import csqcTiroir from './composants/csqcTiroir.vue'
|
|
7
|
+
import pivEntete from './composants/gabarit/pivEntete.vue'
|
|
8
|
+
import pivFooter from './composants/gabarit/pivPiedPage.vue'
|
|
9
|
+
import csqcMenu from './composants/gabarit/csqcMenu.vue'
|
|
10
|
+
import csqcConfirmation from './composants/csqcConfirmation.vue'
|
|
11
|
+
import csqcDate from './composants/csqcDate/csqcDate.vue'
|
|
12
|
+
import csqcTable from './composants/csqcTable/csqcTable.vue'
|
|
13
|
+
import csqcCodeBudgetaire from './composants/codeBudgetaireGenerique.vue'
|
|
14
|
+
import csqcChaise from './composants/csqcChaise/chaiseConteneur.vue'
|
|
15
|
+
import csqcAide from './composants/csqcAide.vue'
|
|
16
|
+
import csqcEntete from './composants/csqcEntete.vue'
|
|
17
|
+
import csqcTexteBilingue from './composants/csqcTexteBilingue.vue'
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
|
+
import csqcEditeurTexteRiche from './composants/csqcEditeurTexteRiche.vue'
|
|
20
|
+
import csqcImportCSV from './composants/csqcImportCSV.vue'
|
|
21
|
+
import csqcRechercheUtilisateur from './composants/csqcRechercheUtilisateur.vue'
|
|
22
|
+
import validateurs from './composants/validateurs'
|
|
23
|
+
|
|
24
|
+
// modèles
|
|
25
|
+
import NotificationGabaritDefaut from './modeles/notificationGabaritDefaut'
|
|
26
|
+
import modeleSnackbar from './modeles/composants/snackbar'
|
|
27
|
+
import modeleDatatableColonne from './modeles/composants/datatableColonne'
|
|
28
|
+
import apiReponse from './modeles/apiReponse'
|
|
29
|
+
import data from './modeles/data'
|
|
30
|
+
import response from './modeles/response'
|
|
31
|
+
|
|
32
|
+
// i18n
|
|
33
|
+
import csqcEn from './locales/en.json'
|
|
34
|
+
import csqcFr from './locales/fr.json'
|
|
35
|
+
|
|
36
|
+
export {
|
|
37
|
+
csqcFr,
|
|
38
|
+
csqcEn,
|
|
39
|
+
csqcAlerteErreur,
|
|
40
|
+
csqcDialogue,
|
|
41
|
+
csqcConfirmation,
|
|
42
|
+
csqcDate,
|
|
43
|
+
csqcOptionSwitch,
|
|
44
|
+
csqcRecherche,
|
|
45
|
+
csqcSnackbar,
|
|
46
|
+
csqcTable,
|
|
47
|
+
csqcTiroir,
|
|
48
|
+
csqcMenu,
|
|
49
|
+
csqcCodeBudgetaire,
|
|
50
|
+
csqcChaise,
|
|
51
|
+
pivFooter,
|
|
52
|
+
pivEntete,
|
|
53
|
+
csqcAide,
|
|
54
|
+
csqcEntete,
|
|
55
|
+
csqcTexteBilingue,
|
|
56
|
+
csqcEditeurTexteRiche,
|
|
57
|
+
validateurs,
|
|
58
|
+
csqcImportCSV,
|
|
59
|
+
csqcRechercheUtilisateur,
|
|
60
|
+
modeleSnackbar,
|
|
61
|
+
modeleDatatableColonne,
|
|
62
|
+
apiReponse,
|
|
63
|
+
data,
|
|
64
|
+
response,
|
|
65
|
+
NotificationGabaritDefaut,
|
|
66
|
+
}
|