Files
portal/app/resources/js/views/SettingsView.vue
T

124 lines
4.9 KiB
Vue
Raw Normal View History

<script setup lang="ts">
/**
* Settings — настройки тенанта/пользователя. 8 вкладок (по v8.5 §13 + ТЗ §14).
*
* Источник дизайна: liderra_v8_handoff/concepts/v8_settings.html.
* Полностью реализованы (с UI-разводкой): Профиль, Безопасность, API и Webhook,
* Уведомления (матрица 8×3 по schema v8.7 §4 users.notification_preferences).
* Placeholder-заглушки: Проекты, Команда, Интеграции, Тихие часы.
*/
import { computed, ref } from 'vue';
import ApiTab from './settings/ApiTab.vue';
import NotificationsTab from './settings/NotificationsTab.vue';
import PlaceholderTab from './settings/PlaceholderTab.vue';
import ProfileTab from './settings/ProfileTab.vue';
import SecurityTab from './settings/SecurityTab.vue';
interface Tab {
id: string;
label: string;
icon: string;
}
const tabs: Tab[] = [
{ id: 'profile', label: 'Профиль', icon: 'mdi-account-outline' },
{ id: 'security', label: 'Безопасность', icon: 'mdi-shield-lock-outline' },
{ id: 'projects', label: 'Проекты', icon: 'mdi-folder-outline' },
{ id: 'team', label: 'Команда', icon: 'mdi-account-group-outline' },
{ id: 'api', label: 'API и Webhook', icon: 'mdi-api' },
{ id: 'integrations', label: 'Интеграции', icon: 'mdi-puzzle-outline' },
{ id: 'hours', label: 'Тихие часы', icon: 'mdi-clock-outline' },
{ id: 'notifications', label: 'Уведомления', icon: 'mdi-bell-outline' },
];
const activeTab = ref('profile');
const placeholderProps = computed(() => {
const map: Record<string, { title: string; description: string }> = {
projects: {
title: 'Проекты',
description:
'Управление проектами тенанта (макс. 10 на тарифе «Команда»). Для каждого проекта — поставщик ГЦК, цена за лид, активные UTM-кампании.',
},
team: {
title: 'Команда',
description:
'Менеджеры тенанта (макс. 4 + расширение). Назначение прав, автораспределение, ограничение доступа к проектам.',
},
integrations: {
title: 'Интеграции',
description:
'Подключение Telegram-бота для нотификаций, экспорт в 1С 8.3, JivoSite helpdesk, Yandex 360 SSO.',
},
hours: {
title: 'Тихие часы',
description:
'Расписание, в которое не приходят SMS/звонки автонапоминаний (например, 22:00-08:00 + выходные).',
},
};
return map[activeTab.value];
});
</script>
<template>
<v-container fluid class="settings pa-6">
<header class="page-head">
<h1 class="text-h4 mb-2 page-title">Настройки</h1>
<p class="text-body-2 text-medium-emphasis ma-0">Профиль, безопасность, API и интеграции</p>
</header>
<v-row class="settings-row mt-4">
<v-col cols="12" md="3">
<v-card variant="outlined" class="tabs-rail pa-2">
<v-list density="compact" nav>
<v-list-item
v-for="tab in tabs"
:key="tab.id"
:prepend-icon="tab.icon"
:active="activeTab === tab.id"
rounded="lg"
@click="activeTab = tab.id"
>
<v-list-item-title>{{ tab.label }}</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-col>
<v-col cols="12" md="9">
<v-card variant="outlined" class="tab-pane pa-6">
<ProfileTab v-if="activeTab === 'profile'" />
<SecurityTab v-else-if="activeTab === 'security'" />
<ApiTab v-else-if="activeTab === 'api'" />
<NotificationsTab v-else-if="activeTab === 'notifications'" />
<PlaceholderTab
v-else-if="placeholderProps"
:title="placeholderProps.title"
:description="placeholderProps.description"
/>
</v-card>
</v-col>
</v-row>
</v-container>
</template>
<style scoped>
.settings {
max-width: 1440px;
}
.page-title {
font-variation-settings: 'opsz' 28;
letter-spacing: -0.018em;
}
.tabs-rail {
background: #fff;
}
.tab-pane {
background: #fff;
min-height: 480px;
}
</style>