Files
portal/app/resources/js/views/settings/ApiTab.vue
T
Дмитрий 394663597f phase2(settings): SettingsView - 8 вкладок (4 реализованы, 4 placeholder)
- 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>
2026-05-08 18:51:41 +03:00

76 lines
3.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<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>