ваше сообщение коммита
This commit is contained in:
@@ -81,12 +81,31 @@ http {
|
||||
return 404;
|
||||
}
|
||||
|
||||
# Защита от доступа к чувствительным файлам
|
||||
location ~* /(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config|robots\.txt|sitemap\.xml)$ {
|
||||
# Защита от доступа к чувствительным файлам (исключаем robots.txt и sitemap.xml для SEO)
|
||||
location ~* /(\.htaccess|\.htpasswd|\.env|\.git|\.svn|\.DS_Store|Thumbs\.db|web\.config)$ {
|
||||
deny all;
|
||||
return 404;
|
||||
}
|
||||
|
||||
# Разрешаем доступ к robots.txt и sitemap.xml для поисковых систем
|
||||
location = /robots.txt {
|
||||
proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/robots.txt;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
|
||||
location = /sitemap.xml {
|
||||
proxy_pass http://${BACKEND_CONTAINER}:8000/api/pages/public/sitemap.xml;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
add_header Content-Type application/xml;
|
||||
}
|
||||
|
||||
# Защита от доступа к конфигурационным файлам
|
||||
location ~* /\.(env|config|ini|conf|cfg|yml|yaml|json|xml|sql|db|bak|backup|old|tmp|temp|log)$ {
|
||||
deny all;
|
||||
|
||||
@@ -420,6 +420,35 @@ const isResizing = ref(false);
|
||||
const resizeStartX = ref(0);
|
||||
const resizeStartWidth = ref(0);
|
||||
|
||||
// Определяем, является ли устройство мобильным
|
||||
const isMobile = ref(false);
|
||||
|
||||
// Функция для проверки мобильного устройства
|
||||
const checkMobile = () => {
|
||||
isMobile.value = window.innerWidth <= 1024;
|
||||
if (isMobile.value) {
|
||||
// На мобильных устройствах устанавливаем ширину в 100%
|
||||
messagesWidth.value = 100;
|
||||
inputWidth.value = 100;
|
||||
} else {
|
||||
// На десктопе используем стандартные значения
|
||||
if (messagesWidth.value === 100) {
|
||||
messagesWidth.value = 70;
|
||||
inputWidth.value = 30;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Отслеживаем изменение размера окна
|
||||
onMounted(() => {
|
||||
checkMobile();
|
||||
window.addEventListener('resize', checkMobile);
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', checkMobile);
|
||||
});
|
||||
|
||||
const startResize = (e) => {
|
||||
isResizing.value = true;
|
||||
|
||||
@@ -535,6 +564,10 @@ const updateChatInputHeight = () => {
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// Проверяем мобильное устройство и устанавливаем ширину
|
||||
checkMobile();
|
||||
window.addEventListener('resize', checkMobile);
|
||||
|
||||
// Начальная установка высоты textarea и блока ввода
|
||||
adjustTextareaHeight();
|
||||
updateChatInputHeight();
|
||||
@@ -548,6 +581,8 @@ onMounted(() => {
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
window.removeEventListener('resize', checkMobile);
|
||||
|
||||
if (resizeObserver && chatInputRef.value) {
|
||||
resizeObserver.unobserve(chatInputRef.value);
|
||||
}
|
||||
@@ -709,8 +744,8 @@ async function handleAiReply() {
|
||||
/* На мобильных устройствах блок ввода занимает всё пространство внизу */
|
||||
@media (max-width: 1024px) {
|
||||
.chat-input {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
height: auto;
|
||||
border-top: none;
|
||||
border-right: none;
|
||||
@@ -737,6 +772,7 @@ async function handleAiReply() {
|
||||
color: var(--color-dark);
|
||||
overflow-y: auto;
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.chat-input textarea:focus {
|
||||
@@ -748,12 +784,15 @@ async function handleAiReply() {
|
||||
/* На мобильных устройствах поле ввода меньше */
|
||||
@media (max-width: 1024px) {
|
||||
.chat-input textarea {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
border-radius: 20px;
|
||||
padding: 12px 16px;
|
||||
min-height: var(--chat-input-min-height, 40px);
|
||||
max-height: var(--chat-input-max-height, 120px);
|
||||
overflow-y: hidden;
|
||||
resize: none;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -942,11 +981,25 @@ async function handleAiReply() {
|
||||
|
||||
.chat-messages {
|
||||
padding: var(--spacing-md) var(--spacing-md) 8px;
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
padding: var(--spacing-xs) var(--spacing-sm);
|
||||
height: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
width: 100% !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.input-area textarea {
|
||||
width: 100% !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.chat-icon-btn {
|
||||
@@ -958,10 +1011,16 @@ async function handleAiReply() {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
.resizer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.chat-input {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
position: sticky !important;
|
||||
bottom: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
@@ -969,14 +1028,27 @@ async function handleAiReply() {
|
||||
background: #f8f8f8 !important;
|
||||
border-top: 1px solid #eee !important;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
width: 100% !important;
|
||||
padding: var(--spacing-md) var(--spacing-md) 8px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.input-area {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
.input-area textarea {
|
||||
width: 100% !important;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.chat-input {
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
position: sticky !important;
|
||||
bottom: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
@@ -984,7 +1056,9 @@ async function handleAiReply() {
|
||||
background: #f8f8f8 !important;
|
||||
border-top: 1px solid #eee !important;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
width: 100% !important;
|
||||
padding: var(--spacing-md) var(--spacing-md) 8px !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
@@ -47,6 +47,9 @@
|
||||
<router-link to="/" class="nav-link-btn" active-class="active">
|
||||
<span>Чат</span>
|
||||
</router-link>
|
||||
<router-link to="/content/published" class="nav-link-btn" active-class="active">
|
||||
<span>Блог</span>
|
||||
</router-link>
|
||||
<router-link to="/crm" class="nav-link-btn" active-class="active">
|
||||
<span>CRM</span>
|
||||
</router-link>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<!-- Заголовок страницы -->
|
||||
<header v-if="page" class="page-header">
|
||||
<div class="page-header-top">
|
||||
<button v-if="breadcrumbs.length > 0" class="back-btn" @click="$emit('back')" title="Вернуться к списку">
|
||||
<button class="back-btn" @click="$emit('back')" title="Вернуться к списку">
|
||||
<i class="fas fa-arrow-left"></i>
|
||||
<span>Назад</span>
|
||||
</button>
|
||||
@@ -186,6 +186,68 @@ const navigation = ref(null);
|
||||
const breadcrumbs = ref([]);
|
||||
const isLoading = ref(false);
|
||||
|
||||
// Установка мета-тегов для SEO
|
||||
function updateMetaTags(pageData) {
|
||||
if (!pageData) return;
|
||||
|
||||
// Парсим seo, если это строка (может прийти из базы как JSON строка)
|
||||
let seoData = pageData.seo;
|
||||
if (typeof seoData === 'string') {
|
||||
try {
|
||||
seoData = JSON.parse(seoData);
|
||||
} catch (e) {
|
||||
console.warn('Ошибка парсинга SEO данных:', e);
|
||||
seoData = null;
|
||||
}
|
||||
}
|
||||
|
||||
const title = seoData?.title || pageData.title || 'Документ';
|
||||
const description = seoData?.description || pageData.summary || '';
|
||||
const keywords = seoData?.keywords || '';
|
||||
const canonicalUrl = `${window.location.origin}/content/published?page=${pageData.id}`;
|
||||
|
||||
// Обновляем title
|
||||
document.title = title;
|
||||
|
||||
// Обновляем или создаем meta теги
|
||||
const updateOrCreateMeta = (name, content, attribute = 'name') => {
|
||||
if (!content) return;
|
||||
let meta = document.querySelector(`meta[${attribute}="${name}"]`);
|
||||
if (!meta) {
|
||||
meta = document.createElement('meta');
|
||||
meta.setAttribute(attribute, name);
|
||||
document.head.appendChild(meta);
|
||||
}
|
||||
meta.setAttribute('content', content);
|
||||
};
|
||||
|
||||
// Meta description
|
||||
updateOrCreateMeta('description', description);
|
||||
|
||||
// Meta keywords
|
||||
if (keywords) {
|
||||
updateOrCreateMeta('keywords', keywords);
|
||||
}
|
||||
|
||||
// Canonical URL
|
||||
let canonical = document.querySelector('link[rel="canonical"]');
|
||||
if (!canonical) {
|
||||
canonical = document.createElement('link');
|
||||
canonical.setAttribute('rel', 'canonical');
|
||||
document.head.appendChild(canonical);
|
||||
}
|
||||
canonical.setAttribute('href', canonicalUrl);
|
||||
|
||||
// Open Graph теги для социальных сетей
|
||||
updateOrCreateMeta('og:title', title, 'property');
|
||||
updateOrCreateMeta('og:description', description, 'property');
|
||||
updateOrCreateMeta('og:type', 'article', 'property');
|
||||
updateOrCreateMeta('og:url', canonicalUrl, 'property');
|
||||
|
||||
// Robots meta
|
||||
updateOrCreateMeta('robots', 'index, follow');
|
||||
}
|
||||
|
||||
// Загрузка страницы
|
||||
async function loadPage() {
|
||||
if (!props.pageId) return;
|
||||
@@ -194,6 +256,11 @@ async function loadPage() {
|
||||
isLoading.value = true;
|
||||
page.value = await pagesService.getPublicPage(props.pageId);
|
||||
|
||||
// Устанавливаем мета-теги для SEO
|
||||
if (page.value) {
|
||||
updateMetaTags(page.value);
|
||||
}
|
||||
|
||||
// Загружаем навигацию
|
||||
try {
|
||||
navigation.value = await pagesService.getPublicPageNavigation(props.pageId);
|
||||
@@ -959,12 +1026,44 @@ onMounted(() => {
|
||||
@media (max-width: 768px) {
|
||||
.docs-content {
|
||||
padding: 20px;
|
||||
min-height: auto;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
display: block;
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.page-header h1 {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
.page-article {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.content-text {
|
||||
width: 100%;
|
||||
overflow-x: auto;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.file-preview {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.pdf-embed {
|
||||
width: 100%;
|
||||
height: 60vh;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.image-preview {
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.page-navigation {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
@@ -199,4 +199,55 @@ onMounted(() => {
|
||||
padding: 1rem;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.admin-chat-header {
|
||||
padding: 0.75rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 1.25rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
height: calc(100vh - 100px);
|
||||
}
|
||||
|
||||
:deep(.chat-messages) {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
:deep(.chat-input) {
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.loading-container {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.loading {
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.admin-chat-header {
|
||||
padding: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.chat-container {
|
||||
height: calc(100vh - 80px);
|
||||
}
|
||||
|
||||
:deep(.chat-messages) {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
:deep(.chat-input) {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -377,5 +377,98 @@ h1 {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.connect-wallet-container {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.connect-wallet-card {
|
||||
padding: 30px 24px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 48px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 24px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.info-block {
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.provider-info {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.connect-button,
|
||||
.go-chat-button {
|
||||
padding: 12px 24px;
|
||||
font-size: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.connect-wallet-container {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.connect-wallet-card {
|
||||
padding: 24px 16px;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
font-size: 40px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.provider-info {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.connect-button,
|
||||
.go-chat-button {
|
||||
padding: 10px 20px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.error-message {
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.expires-info {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.hint {
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.stats {
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -94,4 +94,24 @@ function goBack() {
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.contacts-header {
|
||||
font-size: 1rem;
|
||||
margin-bottom: 16px;
|
||||
padding: 0 10px;
|
||||
}
|
||||
|
||||
.badge {
|
||||
font-size: 0.85em;
|
||||
padding: 2px 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.contacts-header {
|
||||
font-size: 0.9rem;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -19,26 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="content-create-page">
|
||||
<!-- Заголовок страницы -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>{{ isEditMode ? 'Редактирование страницы' : 'Создание страницы' }}</h1>
|
||||
<p>{{ isEditMode ? 'Редактируйте существующую страницу' : 'Создайте новую страницу для вашего DLE' }}</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button
|
||||
v-if="isEditMode && canManageLegalDocs && address"
|
||||
class="btn btn-danger"
|
||||
@click="deletePage"
|
||||
type="button"
|
||||
>
|
||||
<i class="fas fa-trash"></i>
|
||||
Удалить
|
||||
</button>
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Основной контент с тенью -->
|
||||
<div class="content-block">
|
||||
<form class="content-form" @submit.prevent="handleSubmit">
|
||||
|
||||
@@ -19,13 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="crm-management">
|
||||
<!-- Заголовок -->
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>CRM Система</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блоки CRM -->
|
||||
<div class="management-blocks">
|
||||
<!-- Столбец 1 -->
|
||||
|
||||
@@ -19,13 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="home-management">
|
||||
<!-- Заголовок -->
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>Сообщения</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Чат интерфейс -->
|
||||
<div class="chat-wrapper">
|
||||
<template v-if="auth.userAccessLevel.value && auth.userAccessLevel.value.hasAccess">
|
||||
|
||||
@@ -19,12 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="management-container">
|
||||
<!-- Заголовок -->
|
||||
<div class="management-header">
|
||||
<h1>Управление DLE</h1>
|
||||
<button class="close-btn" @click="router.push('/')">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Деплоированные DLE -->
|
||||
<div class="deployed-dles-section">
|
||||
<div class="section-header">
|
||||
|
||||
@@ -308,4 +308,65 @@ onUnmounted(() => {
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.personal-messages-header {
|
||||
padding: 0.75rem;
|
||||
font-size: 1rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 1.25rem;
|
||||
padding: 0.2rem 0.4rem;
|
||||
}
|
||||
|
||||
.personal-messages-list {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
gap: 0.75rem;
|
||||
padding: 0.75rem;
|
||||
}
|
||||
|
||||
.message-info {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.admin-name {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.message-preview {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.message-date {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.personal-messages-header {
|
||||
padding: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.message-item {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.admin-name {
|
||||
font-size: 0.95rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 1.5rem 1rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="settings-view-container">
|
||||
<div v-if="route.name !== 'settings-index'" class="page-header">
|
||||
<h1>{{ pageTitle }}</h1>
|
||||
<div v-if="route.name === 'settings-blockchain-dle-deploy' || route.name === 'settings-dle-v2-deploy'" class="page-header">
|
||||
<button
|
||||
v-if="route.name === 'settings-blockchain-dle-deploy' || route.name === 'settings-dle-v2-deploy'"
|
||||
class="close-btn"
|
||||
@click="router.push('/settings')"
|
||||
>×</button>
|
||||
|
||||
@@ -19,9 +19,7 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="vds-management-container">
|
||||
<!-- Заголовок -->
|
||||
<div class="vds-header">
|
||||
<h1>Управление VDS</h1>
|
||||
<div class="status-badge" :class="{ online: isOnline }">
|
||||
<div class="status-indicator" :class="{ online: isOnline }"></div>
|
||||
<span>{{ isOnline ? 'Онлайн' : 'Офлайн' }}</span>
|
||||
|
||||
@@ -19,18 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="content-management-page">
|
||||
<!-- Заголовок страницы -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Управление контентом</h1>
|
||||
<p v-if="canEditData && address">Создавайте и управляйте страницами вашего DLE</p>
|
||||
<p v-else>Просмотр опубликованных страниц DLE</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Основной контент с тенью -->
|
||||
<div class="content-block">
|
||||
<!-- Быстрые разделы -->
|
||||
@@ -248,8 +236,33 @@ async function deletePage(id) {
|
||||
.details-btn { background: var(--color-primary); color: #fff; border: none; border-radius: 8px; padding: 0.75rem 1.5rem; cursor: pointer; font-size: 1rem; font-weight: 600; transition: all 0.2s; min-width: 120px; margin-top: auto; }
|
||||
.details-btn:hover { background: var(--color-primary-dark); transform: translateY(-1px); }
|
||||
|
||||
@media (max-width: 1024px) { .management-blocks { grid-template-columns: repeat(2, 1fr); } }
|
||||
@media (max-width: 768px) { .management-blocks { grid-template-columns: 1fr; } }
|
||||
@media (max-width: 1024px) {
|
||||
.management-blocks {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.management-blocks {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1.5rem;
|
||||
}
|
||||
|
||||
.blocks-column {
|
||||
gap: 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.management-blocks {
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.blocks-column {
|
||||
gap: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.content-section {
|
||||
background: #f8f9fa;
|
||||
@@ -496,6 +509,12 @@ async function deletePage(id) {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -505,6 +524,11 @@ async function deletePage(id) {
|
||||
padding: 5px;
|
||||
border-radius: var(--radius-sm);
|
||||
transition: background 0.2s;
|
||||
min-width: 32px;
|
||||
min-height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
@@ -513,9 +537,37 @@ async function deletePage(id) {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.content-management-page {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.header-content p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
font-size: 1.3rem;
|
||||
min-width: 28px;
|
||||
min-height: 28px;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.nav-tabs {
|
||||
@@ -536,9 +588,59 @@ async function deletePage(id) {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
.settings-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.management-block {
|
||||
padding: 1.5rem;
|
||||
height: auto;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
.management-block h3 {
|
||||
font-size: 1.3rem;
|
||||
}
|
||||
|
||||
.management-block p {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
.details-btn {
|
||||
padding: 0.6rem 1.2rem;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.content-management-page {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.management-block {
|
||||
padding: 1.2rem;
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.management-block h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.management-block p {
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -13,12 +13,6 @@
|
||||
<template>
|
||||
<BaseLayout>
|
||||
<div class="list-page">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Настройки контента</h1>
|
||||
<p>Юр. реквизиты и параметры подстановки переменных</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content-block">
|
||||
<div class="section-header">
|
||||
<h2>Юр. реквизиты (переменные)</h2>
|
||||
@@ -38,13 +32,136 @@ import BaseLayout from '../../components/BaseLayout.vue';
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.list-page { padding: 20px; width: 100%; }
|
||||
.page-header { display:flex; justify-content: space-between; align-items: flex-start; margin-bottom: 30px; padding-bottom: 20px; border-bottom: 2px solid #f0f0f0; }
|
||||
.header-content h1 { color: var(--color-primary); font-size: 2.2rem; margin: 0 0 8px 0; }
|
||||
.header-content p { color: var(--color-grey-dark); margin: 0; }
|
||||
.content-block { background: #f8f9fa; border-radius: var(--radius-lg); padding: 25px; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
|
||||
.section-header { display:flex; justify-content: space-between; align-items:center; margin-bottom: 20px; }
|
||||
.section-header h2 { color: var(--color-primary); margin: 0; }
|
||||
.empty-state { text-align:center; padding: 60px 20px; }
|
||||
.empty-icon { font-size: 3rem; color: var(--color-grey-dark); margin-bottom: 10px; }
|
||||
.list-page {
|
||||
padding: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: 30px;
|
||||
padding-bottom: 20px;
|
||||
border-bottom: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
color: var(--color-primary);
|
||||
font-size: 2.2rem;
|
||||
margin: 0 0 8px 0;
|
||||
}
|
||||
|
||||
.header-content p {
|
||||
color: var(--color-grey-dark);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
background: #f8f9fa;
|
||||
border-radius: var(--radius-lg);
|
||||
padding: 25px;
|
||||
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
color: var(--color-primary);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
text-align: center;
|
||||
padding: 60px 20px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 3rem;
|
||||
color: var(--color-grey-dark);
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.list-page {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 15px;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.header-content p {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 40px 16px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
|
||||
.empty-state h3 {
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
.list-page {
|
||||
padding: 12px;
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin-bottom: 15px;
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
.header-content h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.content-block {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
padding: 30px 12px;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
font-size: 2rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -16,13 +16,7 @@
|
||||
<template>
|
||||
<BaseLayout :is-authenticated="isAuthenticated" :identities="identities" :token-balances="tokenBalances" :is-loading-tokens="isLoadingTokens" @auth-action-completed="$emit('auth-action-completed')">
|
||||
<div class="list-page">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Внутренние документы</h1>
|
||||
<p>Документы, доступные только пользователям с ролями</p>
|
||||
</div>
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
<button class="close-btn" @click="goBack" style="margin-bottom: 20px;">×</button>
|
||||
<div class="content-block">
|
||||
<div class="section-header">
|
||||
<h2>Список документов</h2>
|
||||
|
||||
@@ -19,38 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="page-view-container">
|
||||
<!-- Заголовок страницы -->
|
||||
<div v-if="page" class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>📄 {{ page.title }}</h1>
|
||||
<div class="page-meta">
|
||||
<span class="page-status" :class="page.status">
|
||||
<i class="fas fa-circle"></i>
|
||||
{{ getStatusText(page.status) }}
|
||||
</span>
|
||||
<span class="page-date">
|
||||
<i class="fas fa-calendar"></i>
|
||||
Создано: {{ formatDate(page.createdAt) }}
|
||||
</span>
|
||||
<span v-if="page.updatedAt" class="page-date">
|
||||
<i class="fas fa-edit"></i>
|
||||
Обновлено: {{ formatDate(page.updatedAt) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button v-if="canEditPage" class="btn btn-outline" @click="goToEdit">
|
||||
<i class="fas fa-edit"></i>
|
||||
Редактировать
|
||||
</button>
|
||||
<button v-if="canManageLegalDocs && address" class="btn btn-danger" @click="deletePage" type="button">
|
||||
<i class="fas fa-trash"></i>
|
||||
Удалить
|
||||
</button>
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Контент страницы -->
|
||||
<div v-if="page" class="page-content-block">
|
||||
<div class="page-content">
|
||||
|
||||
@@ -19,13 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="public-pages-page">
|
||||
<!-- Заголовок страницы -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>📄 Публичные страницы</h1>
|
||||
<p>Просмотр опубликованных страниц DLE</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<div class="content-block">
|
||||
|
||||
@@ -16,16 +16,12 @@
|
||||
<template>
|
||||
<BaseLayout :is-authenticated="isAuthenticated" :identities="identities" :token-balances="tokenBalances" :is-loading-tokens="isLoadingTokens" @auth-action-completed="$emit('auth-action-completed')">
|
||||
<div class="docs-page">
|
||||
<!-- Заголовок страницы -->
|
||||
<div class="docs-header">
|
||||
<div class="header-content">
|
||||
<h1>Публичные документы</h1>
|
||||
</div>
|
||||
<button class="close-btn" @click="goBack" title="Закрыть">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Основной контент: сайдбар + контент -->
|
||||
<div class="docs-layout">
|
||||
<div class="docs-layout" :class="{ 'has-content': currentPageId }">
|
||||
<!-- Сайдбар навигации -->
|
||||
<DocsSidebar :current-page-id="currentPageId" />
|
||||
|
||||
@@ -734,7 +730,8 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
.docs-main {
|
||||
overflow-y: visible;
|
||||
overflow-y: auto;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -954,6 +951,32 @@ onBeforeUnmount(() => {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.docs-page {
|
||||
height: auto;
|
||||
min-height: calc(100vh - 40px);
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.docs-layout {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
overflow: visible;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* В мобильной версии, когда выбран документ, скрываем сайдбар */
|
||||
.docs-layout.has-content .docs-sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.docs-main {
|
||||
overflow-y: visible;
|
||||
min-height: auto;
|
||||
width: 100%;
|
||||
display: block;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.docs-header {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
@@ -5,14 +5,8 @@
|
||||
<template>
|
||||
<BaseLayout :is-authenticated="isAuthenticated" :identities="identities" :token-balances="tokenBalances" :is-loading-tokens="isLoadingTokens" @auth-action-completed="$emit('auth-action-completed')">
|
||||
<div class="list-page">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Шаблоны документов</h1>
|
||||
<p>Системные шаблоны для персонализации и публикации.</p>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
<div class="header-actions" style="margin-bottom: 20px;">
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
</div>
|
||||
|
||||
<div class="content-block">
|
||||
|
||||
@@ -11,9 +11,8 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="system-messages-page">
|
||||
<div class="page-header">
|
||||
<div class="page-header" v-if="canManageSystemMessages">
|
||||
<div class="header-content">
|
||||
<h1>Системные сообщения</h1>
|
||||
<p v-if="canManageSystemMessages">
|
||||
Создавайте и управляйте уведомлениями, которые видят пользователи в чате и интерфейсе DLE
|
||||
</p>
|
||||
|
||||
@@ -19,14 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="groups-management">
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>Группы</h1>
|
||||
<p class="groups-description">
|
||||
Создание и управление группами
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блоки управления группами -->
|
||||
<div class="management-blocks">
|
||||
|
||||
@@ -14,13 +14,6 @@
|
||||
<div class="security-settings">
|
||||
<button class="close-btn" @click="goBack">×</button>
|
||||
|
||||
<!-- Заголовок в стиле основной страницы настроек -->
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>Настройки безопасности</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блоки настроек в едином стиле -->
|
||||
<div class="management-blocks">
|
||||
<!-- Столбец 1 -->
|
||||
|
||||
@@ -12,13 +12,6 @@
|
||||
|
||||
<template>
|
||||
<div class="settings-management">
|
||||
<!-- Заголовок -->
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>Настройки системы</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Блоки настроек -->
|
||||
<div class="management-blocks">
|
||||
<!-- Столбец 1 -->
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="add-module-page">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Добавление модуля в DLE</h1>
|
||||
<p v-if="selectedDle">{{ selectedDle.name }} ({{ selectedDle.symbol }}) - {{ selectedDle.dleAddress }}</p>
|
||||
<p v-else-if="isLoadingDle">Загрузка...</p>
|
||||
<p v-else>DLE не выбран (Адрес: {{ dleAddress }})</p>
|
||||
<!-- Информация для неавторизованных пользователей -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="selectedDle?.dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ selectedDle.dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="isLoadingDle" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToProposals">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Информация для неавторизованных пользователей -->
|
||||
<div v-if="!props.isAuthenticated" class="auth-notice">
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
|
||||
@@ -19,18 +19,16 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="analytics-container">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Аналитика DLE</h1>
|
||||
<p v-if="selectedDle">{{ selectedDle.name }} ({{ selectedDle.symbol }}) - {{ formatAddress(dleAddress) }}</p>
|
||||
<p v-else-if="isLoadingDle">Загрузка...</p>
|
||||
<p v-else>Подробная аналитика и статистика DLE</p>
|
||||
<!-- Основная информация -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="isLoadingDle" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToBlocks">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Основная информация -->
|
||||
<div class="info-section">
|
||||
<h2>Основная информация</h2>
|
||||
<div class="info-grid">
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="create-proposal-page">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Создание предложения</h1>
|
||||
<p v-if="selectedDle">{{ selectedDle.name }} ({{ selectedDle.symbol }}) - {{ selectedDle.dleAddress }}</p>
|
||||
<p v-else-if="isLoadingDle">Загрузка...</p>
|
||||
<p v-else>DLE не выбран</p>
|
||||
<!-- Информация для неавторизованных пользователей -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="selectedDle?.dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ selectedDle.dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="isLoadingDle" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToBlocks">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Информация для неавторизованных пользователей -->
|
||||
<div v-if="!props.isAuthenticated" class="auth-notice">
|
||||
<div class="alert alert-info">
|
||||
<i class="fas fa-info-circle"></i>
|
||||
|
||||
@@ -19,18 +19,13 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="dle-blocks-management">
|
||||
<!-- Заголовок -->
|
||||
<div class="management-header">
|
||||
<div class="header-content">
|
||||
<h1>Управление DLE</h1>
|
||||
<p v-if="dleAddress" class="dle-address">
|
||||
<strong>DLE:</strong> {{ dleAddress }}
|
||||
</p>
|
||||
<!-- Блоки управления -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleAddress }}
|
||||
</div>
|
||||
<button class="close-btn" @click="router.push('/management')">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Блоки управления -->
|
||||
<div class="management-blocks">
|
||||
<!-- Столбец 1 -->
|
||||
<div class="blocks-column">
|
||||
|
||||
@@ -19,11 +19,6 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="dle-management">
|
||||
<div class="management-header">
|
||||
<h3>🏢 Управление DLE</h3>
|
||||
<p>Добавление DLE контрактов администраторами</p>
|
||||
</div>
|
||||
|
||||
<!-- Форма добавления DLE -->
|
||||
<div class="add-dle-form">
|
||||
<div class="form-header">
|
||||
|
||||
@@ -29,11 +29,9 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="proposals-page">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Предложения DLE</h1>
|
||||
<p v-if="dleAddress">Адрес DLE: {{ dleAddress }}</p>
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleAddress }}
|
||||
</div>
|
||||
<button @click="goBack" class="close-btn">×</button>
|
||||
</div>
|
||||
|
||||
@@ -19,18 +19,16 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="history-container">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>История DLE</h1>
|
||||
<p v-if="selectedDle">{{ selectedDle.name }} ({{ selectedDle.symbol }}) - {{ selectedDle.dleAddress }}</p>
|
||||
<p v-else-if="isLoadingDle">Загрузка...</p>
|
||||
<p v-else>Лог операций, события и транзакции DLE</p>
|
||||
<!-- Фильтры -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="selectedDle?.dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ selectedDle.dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="isLoadingDle" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToBlocks">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Фильтры -->
|
||||
<div class="filters-section">
|
||||
<h2>Фильтры</h2>
|
||||
<div class="filters-form">
|
||||
|
||||
@@ -19,24 +19,22 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="modules-management">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="title-section">
|
||||
<h1>Модули DLE</h1>
|
||||
<div class="websocket-status" :class="{ connected: isWSConnected }" title="WebSocket соединение для обновления модулей">
|
||||
<i class="fas fa-circle" :class="isWSConnected ? 'fa-solid' : 'fa-light'"></i>
|
||||
<span>{{ isWSConnected ? 'Подключено' : 'Отключено' }}</span>
|
||||
</div>
|
||||
<!-- Модальное окно деплоя -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div style="display: flex; align-items: center; gap: 20px;">
|
||||
<div v-if="selectedDle?.dleAddress" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ selectedDle.dleAddress }}
|
||||
</div>
|
||||
<div v-else-if="isLoadingDle" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<div class="websocket-status" :class="{ connected: isWSConnected }" title="WebSocket соединение для обновления модулей">
|
||||
<i class="fas fa-circle" :class="isWSConnected ? 'fa-solid' : 'fa-light'"></i>
|
||||
<span>{{ isWSConnected ? 'Подключено' : 'Отключено' }}</span>
|
||||
</div>
|
||||
<p v-if="selectedDle">{{ selectedDle.name }} ({{ selectedDle.symbol }}) - {{ selectedDle.dleAddress }}</p>
|
||||
<p v-else-if="isLoadingDle">Загрузка...</p>
|
||||
<p v-else>DLE не выбран</p>
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToBlocks">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Модальное окно деплоя -->
|
||||
<div v-if="showDeploymentModal" class="modal-overlay" @click="moduleDeploymentStatus === 'error' || !isDeploying ? closeDeploymentModal() : null">
|
||||
<div class="modal-content" @click.stop>
|
||||
<div class="modal-header">
|
||||
@@ -171,11 +169,6 @@
|
||||
|
||||
<!-- Блоки для деплоя стандартных модулей -->
|
||||
<div class="standard-modules">
|
||||
<div class="modules-header">
|
||||
<h3>🚀 Деплой стандартных модулей</h3>
|
||||
<p>Быстрый деплой предустановленных модулей DLE</p>
|
||||
</div>
|
||||
|
||||
<div class="modules-grid">
|
||||
<!-- TreasuryModule -->
|
||||
<div class="module-deploy-card">
|
||||
|
||||
@@ -19,18 +19,19 @@
|
||||
@auth-action-completed="$emit('auth-action-completed')"
|
||||
>
|
||||
<div class="settings-container">
|
||||
<!-- Заголовок -->
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<h1>Настройки DLE</h1>
|
||||
<p v-if="dleInfo">{{ dleInfo.name }} ({{ dleInfo.symbol }}) - {{ dleInfo.address }}</p>
|
||||
<p v-else-if="address">Загрузка...</p>
|
||||
<p v-else>DLE не выбран</p>
|
||||
<!-- Основной контент -->
|
||||
<div style="margin-bottom: 20px; display: flex; justify-content: space-between; align-items: center;">
|
||||
<div v-if="dleInfo?.address" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ dleInfo.address }}
|
||||
</div>
|
||||
<div v-else-if="address" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
{{ address }}
|
||||
</div>
|
||||
<div v-else-if="isLoading" style="color: var(--color-grey-dark); font-size: 0.9rem;">
|
||||
Загрузка...
|
||||
</div>
|
||||
<button class="close-btn" @click="goBackToBlocks">×</button>
|
||||
</div>
|
||||
|
||||
<!-- Основной контент -->
|
||||
<div v-if="dleInfo" class="main-content">
|
||||
<!-- Отображение в футере -->
|
||||
<div v-if="canSetFooterDle" class="footer-card">
|
||||
|
||||
@@ -27,7 +27,14 @@ export default defineConfig({
|
||||
build: {
|
||||
rollupOptions: {
|
||||
plugins: [polyfillNode()],
|
||||
output: {
|
||||
manualChunks: undefined,
|
||||
chunkFileNames: 'assets/[name]-[hash].js',
|
||||
entryFileNames: 'assets/[name]-[hash].js',
|
||||
assetFileNames: 'assets/[name]-[hash].[ext]',
|
||||
},
|
||||
},
|
||||
chunkSizeWarningLimit: 1000,
|
||||
},
|
||||
optimizeDeps: {
|
||||
esbuildOptions: {
|
||||
|
||||
Reference in New Issue
Block a user