52 lines
1.9 KiB
Vue
52 lines
1.9 KiB
Vue
|
|
<script setup lang="ts">
|
||
|
|
/**
|
||
|
|
* Поле даты с гарантированным русским форматом дд.мм.гггг (UI-аудит 21.06.2026).
|
||
|
|
*
|
||
|
|
* Нативный <input type="date"> показывает формат по локали браузера (на en —
|
||
|
|
* мм/дд/гггг). Здесь — read-only текст дд.мм.гггг + Vuetify date-picker (ru-локаль
|
||
|
|
* из plugins/vuetify.ts). Наружу/внутрь — строка ISO `yyyy-mm-dd` (как раньше).
|
||
|
|
*/
|
||
|
|
import { computed, ref } from 'vue';
|
||
|
|
|
||
|
|
const props = defineProps<{ modelValue: string; label?: string }>();
|
||
|
|
const emit = defineEmits<{ 'update:modelValue': [string] }>();
|
||
|
|
|
||
|
|
const menu = ref(false);
|
||
|
|
|
||
|
|
const display = computed(() => {
|
||
|
|
const [y, m, d] = (props.modelValue || '').split('-');
|
||
|
|
return y && m && d ? `${d}.${m}.${y}` : '';
|
||
|
|
});
|
||
|
|
|
||
|
|
const pickerDate = computed<Date | undefined>({
|
||
|
|
get: () => (props.modelValue ? new Date(props.modelValue + 'T00:00:00') : undefined),
|
||
|
|
set: (v) => {
|
||
|
|
if (!v) {
|
||
|
|
emit('update:modelValue', '');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
const iso = `${v.getFullYear()}-${String(v.getMonth() + 1).padStart(2, '0')}-${String(v.getDate()).padStart(2, '0')}`;
|
||
|
|
emit('update:modelValue', iso);
|
||
|
|
menu.value = false;
|
||
|
|
},
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<template>
|
||
|
|
<v-menu v-model="menu" :close-on-content-click="false" location="bottom start">
|
||
|
|
<template #activator="{ props: activator }">
|
||
|
|
<v-text-field
|
||
|
|
:model-value="display"
|
||
|
|
:label="label"
|
||
|
|
variant="outlined"
|
||
|
|
density="comfortable"
|
||
|
|
readonly
|
||
|
|
prepend-inner-icon="mdi-calendar"
|
||
|
|
placeholder="дд.мм.гггг"
|
||
|
|
v-bind="activator"
|
||
|
|
/>
|
||
|
|
</template>
|
||
|
|
<v-date-picker v-model="pickerDate" hide-header show-adjacent-months />
|
||
|
|
</v-menu>
|
||
|
|
</template>
|