Files
portal/app/resources/js/components/common/RuDateField.vue
T
Дмитрий 5f209a2fcc fix(ui): косметика UI-аудита — даты дд.мм.гггг, инлайн-валидация, формат денег, aria, тосты, статус-метки, админка
Раунд 2 минор-фиксы (Playwright-аудит):
- RuDateField (новый): даты дд.мм.гггг через ru date-picker вместо нативного
  <input type=date> (показывал мм/дд/гггг на en-локали) — Отчёты + Сделки.
- BalanceCapacityIndicator: разделитель тысяч «1 000 ₽», эмодзи→mdi.
- dealsApiMapper/DealDetailBody: статус-смена в активности русскими метками
  (было «viewed → new» сырыми слагами).
- ProfileTab: инлайн-валидация Имя/Фамилия (под полем, как в Реквизитах).
- RequisitesTab: проверка формата телефона на клиенте.
- ApiTab: eye-toggle с aria-label (показать/скрыть ключ и секрет).
- DashboardView: «3 / 0» → скрываем «/ N» и «лимит тарифа» при лимите 0.
- KanbanView: тост-подтверждение при смене статуса (+ цветной фейл-тост).
- NotificationsTab: убран жаргон «users.notification_preferences в БД».
- Админка: TenantsTable «ИНН не указан» вместо пустого «ИНН »; PricingTiers
  epoch-дата «1970»→«начала» + ru-формат цены; Incidents empty-state «Инцидентов
  нет»; SupplierIntegration/PdSubjectRequests — window.confirm/alert → v-dialog/snackbar.

Верификация: type-check, build, Playwright (даты дд.мм.гггг подтверждены).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 17:08:51 +03:00

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>