79ff60ffd9
ErrorView 320→178 (+ ErrorBrand 54 + ErrorIllustration 31 + ErrorActions 55 + ErrorMeta 102).
DashboardView 302→84 (+ DashboardPageHead 65 + DashboardKpiRow 97 + DashboardBalance 124).
State (config, errorCode в ErrorView; range/kpis/balance в DashboardView) остаётся
в parent ради единого route.meta-driven flow + future API-fetch'а (Phase B/1 паттерн).
DashboardPageHead использует Vue 3.5 defineModel<T>() для двусторонней привязки range.
Sub-components читают только props — без Pinia stores (mock-data flow).
Все sub-components <250 строк (acceptance threshold). Shell line counts: 178/84.
ЗАМЕЧАНИЕ по acceptance «0 components >300»: НЕ закрыто полностью. 2 файла остались
выше порога — DealsView 560 + DealDetailDrawer 386. Зафиксировано в Sprint 3 Phase C
commit 6c2f0ce: bulk-action функции (applyBulkStatus/applyBulkDelete/applyBulkExport/
undoBulkDelete/applyBulkRestoreFromTrash) и comment/reminders fetch экспонируются
через defineExpose в Vitest-тестах напрямую — дальнейшая декомпозиция требует
изменения тест-контракта (отдельным flow, не вошло в Sprint 4 Phase B).
Phase B/3 закрывает 8/12 audit-кандидатов O-refactor-04: 3 в Sprint 3 Phase C
(Top-3) + 5 в Sprint 4 Phase B/1+B/2 (admin/layout/billing/security/reminders) +
2 в B/3 (errors/dashboard). Оставшиеся: 2 крупных deals-view (defineExpose-blocked)
+ ImpersonationDialog уже <300 органически.
Регрессия: ESLint 0 + vue-tsc 0 + Vitest 416/416 + build OK 989 ms.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
103 lines
2.7 KiB
Vue
103 lines
2.7 KiB
Vue
<script setup lang="ts">
|
||
/**
|
||
* ErrorMeta — мета-блоки ErrorView: status-list (только для 500),
|
||
* RequestId/IncidentId с кнопкой копирования, и помощь-mailto (только 404).
|
||
*
|
||
* Sprint 4 Phase B/3 — split ErrorView (audit O-refactor-04 закрытие).
|
||
*/
|
||
defineProps<{
|
||
code: '404' | '403' | '500';
|
||
showStatusList?: boolean;
|
||
showRequestId?: boolean;
|
||
requestIdLabel?: string;
|
||
requestId?: string;
|
||
}>();
|
||
|
||
const statusList = [
|
||
{ name: 'API', status: 'ok' },
|
||
{ name: 'Telegram', status: 'degraded' },
|
||
{ name: 'YooKassa', status: 'ok' },
|
||
];
|
||
|
||
async function copyRequestId(id: string | undefined) {
|
||
if (id) {
|
||
await navigator.clipboard.writeText(id);
|
||
}
|
||
}
|
||
|
||
function statusColor(s: string): string {
|
||
return s === 'ok' ? '#2E8B57' : s === 'degraded' ? '#D9A441' : '#B83A3A';
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div v-if="showStatusList" class="status-list">
|
||
<span v-for="s in statusList" :key="s.name" class="status-item">
|
||
<span class="dot" :style="{ background: statusColor(s.status) }" />
|
||
{{ s.name }} ·
|
||
{{ s.status === 'ok' ? 'OK' : s.status === 'degraded' ? 'деградация' : 'недоступен' }}
|
||
</span>
|
||
</div>
|
||
|
||
<div v-if="showRequestId" class="err-id">
|
||
<span class="text-caption text-medium-emphasis">{{ requestIdLabel }}</span>
|
||
<span class="request-id">{{ requestId }}</span>
|
||
<v-btn
|
||
icon="mdi-content-copy"
|
||
variant="text"
|
||
size="x-small"
|
||
:aria-label="`Скопировать ID ${requestIdLabel}`"
|
||
@click="copyRequestId(requestId)"
|
||
/>
|
||
</div>
|
||
|
||
<p v-if="code === '404'" class="err-help text-caption">
|
||
Что-то не так? Напишите в
|
||
<a href="mailto:support@liderra.app" class="text-primary">support@liderra.app</a>
|
||
</p>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.status-list {
|
||
display: flex;
|
||
gap: 16px;
|
||
margin-bottom: 16px;
|
||
flex-wrap: wrap;
|
||
justify-content: center;
|
||
}
|
||
.status-item {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
font-size: 12px;
|
||
color: #b1c2bd;
|
||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||
}
|
||
.status-item .dot {
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 50%;
|
||
}
|
||
|
||
.err-id {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: rgba(255, 255, 255, 0.05);
|
||
padding: 6px 10px;
|
||
border-radius: 6px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.request-id {
|
||
font-family: 'JetBrains Mono', ui-monospace, monospace;
|
||
font-size: 12px;
|
||
color: #fff;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.err-help {
|
||
color: #7a8c87;
|
||
margin-top: 16px;
|
||
}
|
||
</style>
|