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>
81 lines
3.1 KiB
Vue
81 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
/**
|
|
* Settings → Профиль. Данные текущего user'а: имя, email, телефон, тайм-зона.
|
|
* Источник дизайна: liderra_v8_handoff/concepts/v8_settings.html секция #profile.
|
|
*
|
|
* MVP: form-fields без save (TODO: PATCH /api/me).
|
|
*/
|
|
import { ref } from 'vue';
|
|
|
|
const fullName = ref('Иван Петров');
|
|
const email = ref('ivan.petrov@example.ru');
|
|
const phone = ref('+7 (916) 871-23-45');
|
|
const timezone = ref('Europe/Moscow');
|
|
const role = ref('Владелец');
|
|
</script>
|
|
|
|
<template>
|
|
<div class="tab-content">
|
|
<h2 class="tab-title text-h6 mb-4">Профиль</h2>
|
|
|
|
<v-row class="profile-row">
|
|
<v-col cols="auto">
|
|
<v-avatar size="80" color="primary">
|
|
<span class="text-h5">ИП</span>
|
|
</v-avatar>
|
|
<v-btn variant="text" size="small" class="mt-2" prepend-icon="mdi-camera"> Сменить </v-btn>
|
|
</v-col>
|
|
<v-col>
|
|
<v-row dense>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field v-model="fullName" label="Полное имя" variant="outlined" density="comfortable" />
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="email"
|
|
label="Email"
|
|
type="email"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
disabled
|
|
persistent-hint
|
|
hint="Email менять только через support — связан с авторизацией"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field v-model="phone" label="Телефон" variant="outlined" density="comfortable" />
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="timezone"
|
|
label="Тайм-зона"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
persistent-hint
|
|
hint="Используется в логах и напоминаниях"
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field v-model="role" label="Роль" variant="outlined" density="comfortable" disabled />
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<div class="d-flex ga-2 mt-4">
|
|
<v-btn color="primary" variant="flat">Сохранить</v-btn>
|
|
<v-btn variant="text">Отмена</v-btn>
|
|
</div>
|
|
</v-col>
|
|
</v-row>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.tab-title {
|
|
font-variation-settings: 'opsz' 18;
|
|
letter-spacing: -0.005em;
|
|
}
|
|
.profile-row {
|
|
align-items: flex-start;
|
|
}
|
|
</style>
|