394663597f
- SettingsView (/settings): sidebar tabs-rail (md=3, 8 v-list-item с mdi-icon) + content-pane (md=9 v-card outlined min-height 480px). activeTab ref переключает рендер вкладки. Реализованы: - ProfileTab: avatar 80px + 5 form-fields (имя/email disabled/телефон/TZ/роль). - SecurityTab: 3 cards (Пароль / 2FA включена + recovery codes + Отключить / Активные сессии 3 mock с Завершить-btn). - ApiTab: API-ключ password+eye-toggle + Webhook (URL + signing secret HMAC). Текст про дедуп (tenant_id, source_crm_id) 24ч и антифрод по phone (§10.8.1). - NotificationsTab: матрица 8x3 (events × channels) соответствует schema v8.7 §4 users.notification_preferences JSONB. 8 событий (new_lead, duplicate_detected, low_balance, tariff_charge, reminder_due, manager_assigned, webhook_failed, monthly_report) × 3 канала (email/sms/in_app). + sound_enabled switch. Placeholder: - PlaceholderTab универсальный с props title/description + v-alert «В разработке». - Используется для Проекты / Команда / Интеграции / Тихие часы. Маршрут /settings (meta.layout=app, lazy-import) в router + web.php. .gitleaks.toml: settings/*.vue в allowlist (фиктивный профиль). cspell-words.txt: смыслово. Vitest +8 (всего 98/98 за 8.42s): - 8 nav-tabs + все названия + дефолт «Профиль» + Проекты → «В разработке» + Уведомления показывает «События × каналы» + 5 событий матрицы + Безопасность: 2FA + сессии + API: API-ключ + Signing secret HMAC. Регресс: lint+type+format OK; vitest 98/98; vite build (SettingsView lazy-chunk; main app-chunk 107.85KB); story:build 17/24 за 31.7s; Pest 48/48 за 5.03s. CLAUDE.md v1.27->v1.28, реестр Открытых_вопросов v1.36->v1.37. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
76 lines
3.5 KiB
Vue
76 lines
3.5 KiB
Vue
<script setup lang="ts">
|
||
/**
|
||
* Settings → API и Webhook. Token + endpoint URL + signing secret + история webhook-вызовов.
|
||
* Источник дизайна: liderra_v8_handoff/concepts/v8_settings.html секция #api.
|
||
*
|
||
* Реальная логика по ТЗ §5/§5.5 + schema v8.7 webhook_dedup_keys (CTO-17 addendum).
|
||
* Token + secret НЕ показываются в открытом виде после генерации (single-time view).
|
||
*/
|
||
import { ref } from 'vue';
|
||
|
||
const apiToken = ref('lpkapi_7g8h********************************2klm');
|
||
const webhookUrl = ref('https://crm.example.ru/api/webhook/leads');
|
||
const signingSecret = ref('whsec_********************************************');
|
||
const tokenVisible = ref(false);
|
||
const secretVisible = ref(false);
|
||
</script>
|
||
|
||
<template>
|
||
<div class="tab-content">
|
||
<h2 class="tab-title text-h6 mb-4">API и Webhook</h2>
|
||
|
||
<v-card variant="outlined" class="pa-4 mb-4">
|
||
<h3 class="text-subtitle-2 mb-3">API-ключ</h3>
|
||
<p class="text-body-2 text-medium-emphasis mb-3">
|
||
Используется для подписи запросов в публичный API CRM. После регенерации старый ключ перестаёт работать
|
||
немедленно.
|
||
</p>
|
||
<v-text-field
|
||
:model-value="apiToken"
|
||
:type="tokenVisible ? 'text' : 'password'"
|
||
readonly
|
||
variant="outlined"
|
||
density="comfortable"
|
||
:append-inner-icon="tokenVisible ? 'mdi-eye-off' : 'mdi-eye'"
|
||
@click:append-inner="tokenVisible = !tokenVisible"
|
||
/>
|
||
<div class="d-flex ga-2 mt-2">
|
||
<v-btn variant="outlined" size="small" prepend-icon="mdi-content-copy">Копировать</v-btn>
|
||
<v-btn variant="outlined" size="small" color="warning" prepend-icon="mdi-refresh">
|
||
Перегенерировать
|
||
</v-btn>
|
||
</div>
|
||
</v-card>
|
||
|
||
<v-card variant="outlined" class="pa-4">
|
||
<h3 class="text-subtitle-2 mb-3">Webhook для приёма лидов</h3>
|
||
<p class="text-body-2 text-medium-emphasis mb-3">
|
||
URL источника лидов отправляет POST с подписью HMAC-SHA256. Дедуп по
|
||
<code>(tenant_id, source_crm_id)</code> в окне 24 ч (антифрод по phone — §10.8.1).
|
||
</p>
|
||
<v-text-field v-model="webhookUrl" label="Endpoint URL" variant="outlined" density="comfortable" />
|
||
<v-text-field
|
||
:model-value="signingSecret"
|
||
:type="secretVisible ? 'text' : 'password'"
|
||
label="Signing secret (HMAC)"
|
||
readonly
|
||
variant="outlined"
|
||
density="comfortable"
|
||
:append-inner-icon="secretVisible ? 'mdi-eye-off' : 'mdi-eye'"
|
||
@click:append-inner="secretVisible = !secretVisible"
|
||
/>
|
||
<div class="d-flex ga-2 mt-2">
|
||
<v-btn color="primary" variant="flat" size="small">Сохранить</v-btn>
|
||
<v-btn variant="outlined" size="small" prepend-icon="mdi-test-tube"> Тестовый webhook </v-btn>
|
||
</div>
|
||
</v-card>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.tab-title {
|
||
font-variation-settings: 'opsz' 18;
|
||
letter-spacing: -0.005em;
|
||
}
|
||
</style>
|