Reflex/src/views/admin/AdminDashboard.vue
Professional c04306a871 фикс
2025-05-26 00:57:20 +07:00

370 lines
8.4 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.

<template>
<div class="admin-dashboard">
<div class="admin-header">
<div class="admin-header-left">
<h1>Панель управления</h1>
</div>
<div class="admin-user-info">
<span class="user-name">{{ user?.name || 'Администратор' }}</span>
<button @click="logout" class="logout-btn">
<span class="logout-text">Выйти</span>
<i class="bi-box-arrow-right"></i>
</button>
</div>
</div>
<div class="admin-content">
<!-- Десктопная боковая панель -->
<div v-if="!isMobile" class="admin-sidebar">
<nav>
<router-link :to="{ name: 'AdminUsers' }" active-class="active">
<i class="bi-people"></i> Пользователи
</router-link>
<router-link :to="{ name: 'AdminConversations' }" active-class="active">
<i class="bi-chat-dots"></i> Диалоги
</router-link>
<router-link :to="{ name: 'AdminReports' }" active-class="active">
<i class="bi-exclamation-triangle"></i> Жалобы
</router-link>
<router-link :to="{ name: 'AdminStatistics' }" active-class="active">
<i class="bi-graph-up"></i> Статистика
</router-link>
</nav>
</div>
<div class="admin-main-content">
<router-view></router-view>
</div>
</div>
<!-- Мобильная нижняя навигация -->
<nav v-if="isMobile" class="admin-mobile-nav">
<router-link :to="{ name: 'AdminUsers' }" class="nav-item" active-class="active">
<div class="nav-icon">
<i class="bi-people"></i>
</div>
<span class="nav-text">Пользователи</span>
</router-link>
<router-link :to="{ name: 'AdminConversations' }" class="nav-item" active-class="active">
<div class="nav-icon">
<i class="bi-chat-dots"></i>
</div>
<span class="nav-text">Диалоги</span>
</router-link>
<router-link :to="{ name: 'AdminReports' }" class="nav-item" active-class="active">
<div class="nav-icon">
<i class="bi-exclamation-triangle"></i>
</div>
<span class="nav-text">Жалобы</span>
</router-link>
<router-link :to="{ name: 'AdminStatistics' }" class="nav-item" active-class="active">
<div class="nav-icon">
<i class="bi-graph-up"></i>
</div>
<span class="nav-text">Статистика</span>
</router-link>
</nav>
</div>
</template>
<script>
import { useAuth } from '../../auth';
import { useRouter } from 'vue-router';
import { computed, ref, onMounted, onBeforeUnmount } from 'vue';
export default {
name: 'AdminDashboard',
setup() {
const { user, logout: authLogout } = useAuth();
const router = useRouter();
const isMobile = ref(window.innerWidth < 768);
const handleResize = () => {
isMobile.value = window.innerWidth < 768;
};
const logout = async () => {
try {
await authLogout();
router.push({ name: 'Login' });
} catch (error) {
console.error('Ошибка при выходе:', error);
}
};
onMounted(() => {
window.addEventListener('resize', handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
});
return {
user: computed(() => user.value),
logout,
isMobile
};
}
}
</script>
<style scoped>
.admin-dashboard {
display: flex;
flex-direction: column;
height: 100vh;
background-color: #f5f5f5;
}
.admin-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem 1rem;
background: linear-gradient(135deg, #ff3e68 0%, #ff5252 100%);
color: white;
box-shadow: 0 2px 8px rgba(255, 62, 104, 0.2);
z-index: 100;
height: var(--header-height, 56px);
}
.admin-header-left {
display: flex;
align-items: center;
gap: 0.75rem;
}
.admin-header h1 {
font-size: 1.4rem;
margin: 0;
font-weight: 600;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
.menu-toggle-btn {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0.25rem;
display: flex;
align-items: center;
justify-content: center;
-webkit-tap-highlight-color: transparent;
}
.admin-user-info {
display: flex;
align-items: center;
gap: 1rem;
}
.logout-btn {
padding: 0.4rem 1rem;
background-color: rgba(255, 255, 255, 0.2);
color: white;
border: none;
border-radius: 50px;
cursor: pointer;
font-weight: 500;
display: flex;
align-items: center;
gap: 0.5rem;
transition: all 0.2s ease;
}
.logout-btn:hover {
background-color: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
}
.admin-content {
display: flex;
flex: 1;
overflow: hidden;
position: relative;
}
/* Стили для десктопной боковой панели */
.admin-sidebar {
width: 220px;
background: linear-gradient(to bottom, #ffffff, #f9f9f9);
box-shadow: 1px 0 5px rgba(0,0,0,0.05);
overflow-y: auto;
flex-shrink: 0;
border-right: 1px solid rgba(0,0,0,0.05);
}
.admin-sidebar nav {
display: flex;
flex-direction: column;
padding: 1rem 0;
}
.admin-sidebar a {
padding: 0.85rem 1.5rem;
color: #444;
text-decoration: none;
transition: all 0.3s ease;
display: flex;
align-items: center;
gap: 0.75rem;
border-left: 3px solid transparent;
}
.admin-sidebar a i {
font-size: 1.2rem;
color: #666;
transition: color 0.3s ease;
}
.admin-sidebar a:hover {
background-color: rgba(255, 62, 104, 0.05);
color: #ff3e68;
}
.admin-sidebar a:hover i {
color: #ff3e68;
}
.admin-sidebar a.active {
background-color: rgba(255, 62, 104, 0.1);
color: #ff3e68;
font-weight: 500;
border-left: 3px solid #ff3e68;
}
.admin-sidebar a.active i {
color: #ff3e68;
}
.admin-main-content {
flex: 1;
padding: 1.5rem;
overflow-y: auto;
height: calc(100vh - var(--header-height) - var(--nav-height, 0px));
}
/* Мобильная навигация */
.admin-mobile-nav {
display: none;
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--nav-height, 60px);
background: white;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.12);
z-index: 1000;
padding-bottom: env(safe-area-inset-bottom, 0);
}
/* Стили для мобильной навигации админ-панели */
.admin-mobile-nav .nav-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
text-decoration: none;
color: #777;
transition: all 0.3s ease;
padding: 0;
position: relative;
}
.admin-mobile-nav .nav-icon {
position: relative;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 3px;
height: 28px;
}
.admin-mobile-nav .nav-text {
font-size: 0.7rem;
font-weight: 500;
transform: translateY(-10px);
display: block;
}
.admin-mobile-nav .nav-item.active {
color: #ff3e68;
}
.admin-mobile-nav .nav-item.active .nav-icon i {
color: #ff3e68;
transform: translateY(-2px);
}
:root {
--header-height: 56px;
}
/* На мобильных устройствах */
@media (max-width: 767px) {
.admin-header h1 {
font-size: 1.25rem;
}
.user-name {
display: none;
}
.logout-text {
display: none;
}
.logout-btn {
padding: 0.4rem;
background-color: transparent;
}
.logout-btn i {
font-size: 1.2rem;
margin: 0;
}
.admin-main-content {
padding: 1rem;
height: calc(100vh - 56px - 56px - env(safe-area-inset-bottom, 0px)); /* header + nav + safe area */
padding-bottom: 1rem;
}
.admin-mobile-nav {
display: flex;
--nav-height: 56px;
}
}
/* Поддержка устройств с вырезом (iPhone X и новее) */
@supports (padding: env(safe-area-inset-bottom)) {
.admin-mobile-nav {
height: calc(var(--nav-height) + env(safe-area-inset-bottom, 0px));
padding-bottom: env(safe-area-inset-bottom, 0px);
}
}
/* Ландшафтная ориентация на мобильных */
@media (max-height: 450px) and (orientation: landscape) {
.admin-mobile-nav {
--nav-height: 50px;
}
.admin-mobile-nav .nav-item {
flex-direction: row;
gap: 5px;
}
.admin-mobile-nav .nav-icon {
margin-bottom: 0;
}
.admin-main-content {
height: calc(100vh - 56px - 50px);
}
}
</style>