b264e7e983
Три находки приёмки глазами, все по решению владельца 02.08. 1. Срок показа. Вопрос владельца: «цена на 40% больше, а в течение какого срока показываться будет?». На экране этого не было нигде. Портал сроком не управляет вовсе: ни в кампании, ни в задании роботу нет ни одной даты — их ставит кабинет МТС своими умолчаниями. В сводку шага «Проверка и отправка» добавлена строка «Срок показа: 7 дней, каждый человек увидит объявление один раз». Заодно снимает путаницу с лимитом: лимит — потолок-предохранитель, а не длительность. 2. Подпись пустого счётчика охвата врала. Одна фраза стояла на два разных положения: «Выберите, кому показывать». Когда клиент УЖЕ выбрал «Свой список номеров», но не вставил их, портал звал сделать выбор, который сделан, и молчал о том, чего на самом деле не хватает. Теперь в этом положении — «Вставьте номера». 3. Значки: долг закрыт полностью. Оставались 23 сломанных имени вне рекламы — личный кабинет, отдел продаж, проекты, счета, админка. Все заведены в карту Lucide, список «известного долга» в стороже опустошён. Значит сторож теперь охраняет без единой поблажки. Букв в Lucide нет, поэтому имена вида mdi-alpha-* подобраны по смыслу канала: Яндекс глобусом, ВК значком сети, Телеграм самолётиком. Точной буквы не будет, искать её бесполезно — это записано в коде рядом. Приёмка вырезанием, а не одним зелёным: - опустошил список поблажек в стороже значков — красный ровно на 23 имени, с адресами файлов; после правки карты зелёный; - тест срока показа до правки красный по верной причине: строки нет; - тест подписи до правки красный: видел старую фразу. Замеры: экраны 243 файла 1846 тестов 0 падений. Проверка типов 6 ошибок, все в чужих файлах, столько же было до работы. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
429 lines
14 KiB
TypeScript
429 lines
14 KiB
TypeScript
// @ts-expect-error vuetify/styles — CSS-импорт без d.ts
|
|
import 'vuetify/styles';
|
|
import { h, type Component } from 'vue';
|
|
import { createVuetify } from 'vuetify';
|
|
import { ru } from 'vuetify/locale';
|
|
import type { ThemeDefinition, IconSet, IconProps } from 'vuetify';
|
|
import {
|
|
Activity,
|
|
AlertCircle,
|
|
AlertTriangle,
|
|
Archive,
|
|
ArrowDown,
|
|
ArrowLeft,
|
|
ArrowRightLeft,
|
|
ArrowUp,
|
|
Ban,
|
|
BanknoteX,
|
|
Bell,
|
|
BellOff,
|
|
Bot,
|
|
Calendar,
|
|
CalendarClock,
|
|
CalendarDays,
|
|
CalendarRange,
|
|
Camera,
|
|
Check,
|
|
CheckCheck,
|
|
CheckCircle,
|
|
ChevronDown,
|
|
ChevronLeft,
|
|
ChevronRight,
|
|
ChevronsLeft,
|
|
ChevronsRight,
|
|
ChevronsUpDown,
|
|
ChevronUp,
|
|
Circle,
|
|
CircleDot,
|
|
CirclePause,
|
|
CirclePlay,
|
|
CircleStop,
|
|
CircleX,
|
|
Clock,
|
|
Code,
|
|
Columns3,
|
|
Copy,
|
|
CreditCard,
|
|
Crosshair,
|
|
Download,
|
|
ExternalLink,
|
|
Eye,
|
|
EyeOff,
|
|
FilterX,
|
|
FileCheck,
|
|
FileSpreadsheet,
|
|
FileText,
|
|
FileUp,
|
|
FlaskConical,
|
|
Folder,
|
|
Folders,
|
|
Globe,
|
|
HelpCircle,
|
|
History,
|
|
Hourglass,
|
|
Image as ImageIcon,
|
|
Info,
|
|
Key,
|
|
KeyRound,
|
|
LayoutDashboard,
|
|
LifeBuoy,
|
|
LineChart,
|
|
Link2,
|
|
List,
|
|
ListFilter,
|
|
LogOut,
|
|
Mail,
|
|
MapPinned,
|
|
Megaphone,
|
|
Menu,
|
|
MessageSquare,
|
|
MessageSquareText,
|
|
Minus,
|
|
MoreVertical,
|
|
Paperclip,
|
|
Pause,
|
|
Pencil,
|
|
Phone,
|
|
Play,
|
|
Plus,
|
|
PlusCircle,
|
|
Puzzle,
|
|
Radar,
|
|
ReceiptText,
|
|
RefreshCw,
|
|
Repeat,
|
|
Repeat2,
|
|
Rocket,
|
|
RotateCcw,
|
|
RotateCw,
|
|
RussianRuble,
|
|
Save,
|
|
Search,
|
|
Send,
|
|
SendHorizontal,
|
|
Settings,
|
|
Share2,
|
|
Shield,
|
|
ShieldCheck,
|
|
ShieldOff,
|
|
Square,
|
|
SquareCheck,
|
|
SquareMinus,
|
|
Star,
|
|
StarHalf,
|
|
Tag,
|
|
Target,
|
|
Trash2,
|
|
Undo2,
|
|
Upload,
|
|
User,
|
|
UserCheck,
|
|
UserCog,
|
|
UserPlus,
|
|
UserRoundSearch,
|
|
Users,
|
|
UserSearch,
|
|
UserX,
|
|
Wallet,
|
|
Webhook,
|
|
X,
|
|
XCircle,
|
|
} from 'lucide-vue-next';
|
|
|
|
/**
|
|
* Палитра Forest extended (Iteration 1 — Quiet Luxury redesign).
|
|
* Spec: docs/superpowers/specs/2026-05-12-portal-redesign-quiet-luxury-design.md §3
|
|
* CSS-токены: app/resources/css/tokens.css (single source of truth)
|
|
*
|
|
* 14 OKLCH-статусов воронки маппятся на slugs из db/schema.sql:2076 (lead_statuses)
|
|
* через `useStatusPill` composable, НЕ через Vuetify theme.
|
|
*/
|
|
const liderraForest: ThemeDefinition = {
|
|
dark: false,
|
|
colors: {
|
|
background: '#F6F3EC',
|
|
surface: '#FFFFFF',
|
|
primary: '#0F6E56',
|
|
'on-primary': '#FFFFFF',
|
|
secondary: '#012019',
|
|
'on-secondary': '#F6F3EC',
|
|
success: '#2E8B57',
|
|
warning: '#D9A441',
|
|
// Текстовые двойники success/warning. Сами брендовые цвета не трогаем —
|
|
// они остаются для заливок, иконок и рамок, где 4.5:1 не требуется. Но
|
|
// ТЕКСТОМ они нечитаемы: success даёт 4.25:1 на белой карточке и 3.83:1
|
|
// на ивори #F6F3EC, warning — 2.25/2.03 при норме WCAG 2.1 AA 4.5:1.
|
|
// Затемнённые двойники: 6.10/5.51 и 5.37/4.85 — тон сохранён.
|
|
// Использовать как text-success-strong / text-warning-strong.
|
|
'success-strong': '#256F46',
|
|
'warning-strong': '#8A6410',
|
|
error: '#B83A3A',
|
|
info: '#3F7C95',
|
|
// Расширения — для data viz и semantic uses
|
|
'liderra-plum': '#7A5BA3',
|
|
'liderra-salmon': '#CC6E50',
|
|
'liderra-teal-deep': '#0A5A47',
|
|
'liderra-muted': '#6B6356',
|
|
},
|
|
};
|
|
|
|
/**
|
|
* Liderra Lucide IconSet (CTO-19 closure, v1.83).
|
|
* Spec: docs/superpowers/specs/2026-05-13-cto-19-lucide-icon-migration-design.md
|
|
*
|
|
* Maps 80 mdi-* semantic-ID strings (used across 52 Vue/TS files in resources/js/)
|
|
* to Lucide Vue components for rendering. Views НЕ touched — mdi-* строки остаются
|
|
* как semantic identifiers, рендерятся через Lucide stroke-based SVG icons.
|
|
*
|
|
* CLAUDE.md §2 «Иконки: Lucide» — бренд-spec compliance.
|
|
*
|
|
* Экспортируется наружу РАДИ СТОРОЖА: имя, которого тут нет, молча подменяется
|
|
* на HelpCircle (см. ниже), и на экране вместо значка появляется вопрос в кружке.
|
|
* Замер 02.08.2026: так молча ломались 43 имени из 162. Сторож —
|
|
* tests/Frontend/znachki-est-v-karte.spec.ts.
|
|
*/
|
|
export const lucideMap: Record<string, Component> = {
|
|
'mdi-account-arrow-right-outline': UserCheck,
|
|
'mdi-account-group-outline': Users,
|
|
'mdi-account-outline': User,
|
|
'mdi-account-plus-outline': UserPlus,
|
|
'mdi-account-switch': UserCog,
|
|
'mdi-alert-circle': AlertCircle,
|
|
'mdi-alert-circle-outline': AlertCircle,
|
|
'mdi-alert-outline': AlertTriangle,
|
|
'mdi-api': Webhook,
|
|
'mdi-archive': Archive,
|
|
'mdi-arrow-down': ArrowDown,
|
|
'mdi-arrow-left': ArrowLeft,
|
|
'mdi-arrow-up': ArrowUp,
|
|
'mdi-autorenew': RotateCw,
|
|
'mdi-bell-off-outline': BellOff,
|
|
'mdi-bell-outline': Bell,
|
|
'mdi-bullhorn-outline': Megaphone,
|
|
'mdi-camera': Camera,
|
|
'mdi-cash-plus': PlusCircle,
|
|
'mdi-chart-box-outline': LayoutDashboard,
|
|
'mdi-check': Check,
|
|
'mdi-check-circle': CheckCircle,
|
|
'mdi-check-circle-outline': CheckCircle,
|
|
'mdi-chevron-right': ChevronRight,
|
|
'mdi-clock-check-outline': Clock,
|
|
'mdi-clock-outline': Clock,
|
|
'mdi-close': X,
|
|
'mdi-close-circle': XCircle,
|
|
'mdi-cog-outline': Settings,
|
|
'mdi-comment-outline': MessageSquare,
|
|
'mdi-content-copy': Copy,
|
|
'mdi-content-save-outline': Save,
|
|
'mdi-credit-card-outline': CreditCard,
|
|
'mdi-currency-rub': RussianRuble,
|
|
'mdi-delete': Trash2,
|
|
'mdi-delete-outline': Trash2,
|
|
'mdi-dots-vertical': MoreVertical,
|
|
'mdi-download': Download,
|
|
'mdi-email-outline': Mail,
|
|
'mdi-eye': Eye,
|
|
'mdi-eye-off': EyeOff,
|
|
'mdi-eye-outline': Eye,
|
|
'mdi-file-pdf-box': FileText,
|
|
'mdi-filter-off': FilterX,
|
|
'mdi-folder-multiple-outline': Folders,
|
|
'mdi-folder-outline': Folder,
|
|
'mdi-format-list-bulleted': List,
|
|
'mdi-key': Key,
|
|
'mdi-lock-reset': KeyRound,
|
|
'mdi-logout': LogOut,
|
|
'mdi-magnify': Search,
|
|
'mdi-message-text': MessageSquareText,
|
|
'mdi-pause': Pause,
|
|
'mdi-pencil': Pencil,
|
|
'mdi-pencil-outline': Pencil,
|
|
'mdi-phone': Phone,
|
|
'mdi-play': Play,
|
|
'mdi-plus': Plus,
|
|
'mdi-plus-circle-outline': PlusCircle,
|
|
'mdi-progress-clock': Clock,
|
|
'mdi-pulse': Activity,
|
|
'mdi-puzzle-outline': Puzzle,
|
|
'mdi-receipt-text-check-outline': ReceiptText,
|
|
'mdi-refresh': RefreshCw,
|
|
'mdi-restore': RotateCcw,
|
|
'mdi-shield-account-outline': ShieldCheck,
|
|
'mdi-shield-key': Shield,
|
|
'mdi-shield-lock-outline': ShieldCheck,
|
|
'mdi-shield-off': ShieldOff,
|
|
'mdi-stop-circle-outline': CircleStop,
|
|
'mdi-swap-horizontal': ArrowRightLeft,
|
|
'mdi-tag-arrow-right': Tag,
|
|
'mdi-test-tube': FlaskConical,
|
|
'mdi-trash-can-outline': Trash2,
|
|
'mdi-view-column-outline': Columns3,
|
|
'mdi-view-dashboard-outline': LayoutDashboard,
|
|
'mdi-wallet-outline': Wallet,
|
|
'mdi-web': Globe,
|
|
'mdi-xml': Code,
|
|
// UI-аудит 21.06.2026 — иконки, ранее падавшие в HelpCircle-fallback («?»):
|
|
// bulk-бар проектов, импорт, экспорт отчётов/сделок, помощь, действия админки.
|
|
'mdi-account-cancel': UserX,
|
|
'mdi-cash-edit': Pencil,
|
|
'mdi-cash-refund': RotateCcw,
|
|
'mdi-database-import-outline': Upload,
|
|
'mdi-delete-forever': Trash2,
|
|
'mdi-earth': Globe,
|
|
'mdi-file-delimited-outline': FileText,
|
|
'mdi-file-document-outline': FileText,
|
|
'mdi-file-excel-outline': FileSpreadsheet,
|
|
'mdi-format-list-checks': List,
|
|
'mdi-information-outline': Info,
|
|
'mdi-lifebuoy': LifeBuoy,
|
|
'mdi-target': Target,
|
|
// Раздел «Рекламные возможности» (витрина будущих каналов).
|
|
'mdi-robot-outline': Bot,
|
|
'mdi-send-outline': Send,
|
|
// Vuetify-internal default mdi-* aliases (CTO-19 closure extension)
|
|
'mdi-chevron-down': ChevronDown,
|
|
'mdi-chevron-left': ChevronLeft,
|
|
'mdi-menu-down': ChevronDown,
|
|
'mdi-menu-right': ChevronRight,
|
|
'mdi-menu-up': ChevronUp,
|
|
'mdi-menu': Menu,
|
|
'mdi-page-first': ChevronsLeft,
|
|
'mdi-page-last': ChevronsRight,
|
|
'mdi-checkbox-marked': SquareCheck,
|
|
'mdi-checkbox-blank-outline': Square,
|
|
'mdi-minus-box': SquareMinus,
|
|
'mdi-radiobox-marked': CircleDot,
|
|
'mdi-radiobox-blank': Circle,
|
|
'mdi-circle': Circle,
|
|
'mdi-information': Info,
|
|
'mdi-minus': Minus,
|
|
'mdi-calendar': Calendar,
|
|
'mdi-calendar-month': CalendarDays,
|
|
'mdi-paperclip': Paperclip,
|
|
'mdi-unfold-more-horizontal': ChevronsUpDown,
|
|
'mdi-window-close': X,
|
|
'mdi-cached': RefreshCw,
|
|
'mdi-star': Star,
|
|
'mdi-star-outline': Star,
|
|
'mdi-star-half-full': StarHalf,
|
|
|
|
// ——— Рекламные экраны (приёмка глазами 02.08.2026) ———
|
|
// Этих имён в карте не было, и на экране вместо значка стоял вопрос в
|
|
// кружке: у ярлыков «Проверяем вручную» и «Запущена в кабинете МТС», у поля
|
|
// «Картинка или видео», у заголовка телеграм-экрана. Ярлык состояния с
|
|
// вопросом вместо значка читается как «портал сам не знает, что происходит».
|
|
'mdi-account-search-outline': UserSearch,
|
|
'mdi-calendar-clock': CalendarClock,
|
|
'mdi-calendar-range': CalendarRange,
|
|
'mdi-cancel': Ban,
|
|
'mdi-check-all': CheckCheck,
|
|
'mdi-file-check-outline': FileCheck,
|
|
'mdi-file-outline': FileText,
|
|
'mdi-file-upload-outline': FileUp,
|
|
'mdi-help-circle-outline': HelpCircle,
|
|
'mdi-image-outline': ImageIcon,
|
|
'mdi-link-variant': Link2,
|
|
'mdi-pause-circle': CirclePause,
|
|
'mdi-play-circle': CirclePlay,
|
|
'mdi-repeat': Repeat,
|
|
'mdi-repeat-variant': Repeat2,
|
|
'mdi-rocket-launch-outline': Rocket,
|
|
'mdi-send-check-outline': SendHorizontal,
|
|
'mdi-send-circle-outline': Send,
|
|
'mdi-tag-outline': Tag,
|
|
'mdi-upload': Upload,
|
|
|
|
// ——— Остальные экраны портала: закрытие долга 02.08.2026 ———
|
|
// Те же 43 сломанных имени, но вне рекламы: личный кабинет, отдел продаж,
|
|
// проекты, счета, админка. Раньше держались списком «известного долга» в
|
|
// стороже — список опустошён, значит на этих экранах вопросов в кружке
|
|
// больше нет.
|
|
//
|
|
// 🪤 Букв в Lucide нет: имена вида `mdi-alpha-*` подобраны ПО СМЫСЛУ канала —
|
|
// Яндекс глобусом, ВК значком сети, Телеграм самолётиком. Точной буквы «В»
|
|
// или «Я» не будет, и искать её бесполезно.
|
|
'mdi-account-check-outline': UserCheck,
|
|
'mdi-account-clock-outline': Hourglass,
|
|
'mdi-account-eye-outline': UserRoundSearch,
|
|
'mdi-account-multiple-outline': Users,
|
|
'mdi-account-plus': UserPlus,
|
|
'mdi-alpha-v-box-outline': Share2,
|
|
'mdi-alpha-v-circle': Share2,
|
|
'mdi-alpha-y-circle': Globe,
|
|
'mdi-bullseye-arrow': Crosshair,
|
|
'mdi-cash-remove': BanknoteX,
|
|
'mdi-chart-line': LineChart,
|
|
'mdi-clock-edit-outline': CalendarClock,
|
|
'mdi-close-circle-outline': CircleX,
|
|
'mdi-file-document-check-outline': FileCheck,
|
|
'mdi-filter-variant': ListFilter,
|
|
'mdi-history': History,
|
|
'mdi-map-search-outline': MapPinned,
|
|
'mdi-message-text-outline': MessageSquareText,
|
|
'mdi-open-in-new': ExternalLink,
|
|
'mdi-pause-circle-outline': CirclePause,
|
|
'mdi-radar': Radar,
|
|
'mdi-send-circle': Send,
|
|
'mdi-undo': Undo2,
|
|
};
|
|
|
|
const liderraLucideSet: IconSet = {
|
|
component: (props: IconProps) => {
|
|
const Icon = lucideMap[String(props.icon)] || HelpCircle;
|
|
return h(Icon, { size: 20, strokeWidth: 1.75 });
|
|
},
|
|
};
|
|
|
|
export const vuetify = createVuetify({
|
|
// Русская локаль Vuetify — иначе дефолтные строки таблиц/пагинации на
|
|
// английском («No data available», «Items per page», «0-0 of 0») на всех экранах.
|
|
locale: {
|
|
locale: 'ru',
|
|
fallback: 'en',
|
|
messages: { ru },
|
|
},
|
|
theme: {
|
|
defaultTheme: 'liderraForest',
|
|
themes: { liderraForest },
|
|
},
|
|
icons: {
|
|
defaultSet: 'liderra',
|
|
sets: { liderra: liderraLucideSet },
|
|
},
|
|
defaults: {
|
|
VBtn: {
|
|
variant: 'flat',
|
|
rounded: 'lg',
|
|
},
|
|
VCard: {
|
|
rounded: 'lg',
|
|
variant: 'flat',
|
|
border: true,
|
|
},
|
|
VTextField: {
|
|
variant: 'outlined',
|
|
density: 'comfortable',
|
|
color: 'primary',
|
|
},
|
|
VTextarea: {
|
|
variant: 'outlined',
|
|
density: 'comfortable',
|
|
color: 'primary',
|
|
},
|
|
VSelect: {
|
|
variant: 'outlined',
|
|
density: 'comfortable',
|
|
},
|
|
VChip: {
|
|
rounded: 'pill',
|
|
size: 'small',
|
|
},
|
|
VDataTable: {
|
|
density: 'comfortable',
|
|
},
|
|
VDialog: {
|
|
scrim: 'rgba(1, 32, 25, 0.32)',
|
|
},
|
|
},
|
|
});
|