[ВОЛК] управление публикацией площадок
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2025-12-25 20:59:18 +03:00
parent 0490135d9e
commit 2284fd3263
3 changed files with 53 additions and 8 deletions
+9 -3
View File
@@ -1100,7 +1100,7 @@ def api_categories():
try:
with db.conn.cursor() as cursor:
cursor.execute("""
SELECT AUTO_ID, ID, TITLE, description
SELECT AUTO_ID, ID, TITLE, description, marked_for_publication, is_tg_published
FROM categories
ORDER BY TITLE, ID
""")
@@ -1112,7 +1112,9 @@ def api_categories():
'auto_id': cat['AUTO_ID'],
'id': cat['ID'],
'title': cat['TITLE'] or '',
'description': cat['description'] or ''
'description': cat['description'] or '',
'marked_for_publication': bool(cat['marked_for_publication']) if cat['marked_for_publication'] is not None else False,
'is_tg_published': bool(cat['is_tg_published']) if cat['is_tg_published'] is not None else False
})
return jsonify(categories_list)
@@ -1129,7 +1131,7 @@ def api_category_details(category_id):
try:
with db.conn.cursor() as cursor:
cursor.execute("""
SELECT AUTO_ID, ID, TITLE, description, image_url
SELECT AUTO_ID, ID, TITLE, description, image_url, tg_id, is_tg_published, tg_published_date, marked_for_publication
FROM categories
WHERE ID = %s
""", (category_id,))
@@ -1153,6 +1155,10 @@ def api_category_details(category_id):
'title': category['TITLE'] or '',
'description': category['description'] or '',
'image_url': category['image_url'] or '',
'tg_id': category['tg_id'],
'is_tg_published': bool(category['is_tg_published']) if category['is_tg_published'] is not None else False,
'tg_published_date': category['tg_published_date'].isoformat() if category['tg_published_date'] else None,
'marked_for_publication': bool(category['marked_for_publication']) if category['marked_for_publication'] is not None else False,
'event_count': event_count
})
except Exception as e:
+8 -2
View File
@@ -164,7 +164,10 @@ def ensure_database_structure():
TITLE VARCHAR(2048),
description TEXT,
tg_id BIGINT NULL,
image_url VARCHAR(2048)
image_url VARCHAR(2048),
is_tg_published BOOLEAN DEFAULT 0,
tg_published_date DATETIME NULL,
marked_for_publication BOOLEAN DEFAULT 0
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
'''
}
@@ -228,7 +231,10 @@ def ensure_database_structure():
'categories': [
{'column': 'description', 'type': 'TEXT'},
{'column': 'tg_id', 'type': 'BIGINT NULL'},
{'column': 'image_url', 'type': 'VARCHAR(2048)'}
{'column': 'image_url', 'type': 'VARCHAR(2048)'},
{'column': 'is_tg_published', 'type': 'BOOLEAN DEFAULT 0'},
{'column': 'tg_published_date', 'type': 'DATETIME NULL'},
{'column': 'marked_for_publication', 'type': 'BOOLEAN DEFAULT 0'}
],
'events': [
{'column': 'authors', 'type': 'VARCHAR(255)'}
+36 -3
View File
@@ -700,6 +700,7 @@
<tr>
<th class="sortable-header">ID</th>
<th class="sortable-header">Название</th>
<th class="sortable-header">Статус</th>
</tr>
</thead>
</table>
@@ -709,7 +710,7 @@
<table class="table table-hover mb-0">
<tbody id="categories-table">
<tr>
<td colspan="2" class="text-center py-5">
<td colspan="3" class="text-center py-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Загрузка...</span>
</div>
@@ -1846,7 +1847,7 @@
if (categories.length === 0) {
tableBody.innerHTML = `
<tr>
<td colspan="2" class="text-center py-5 text-muted">
<td colspan="3" class="text-center py-5 text-muted">
<i class="fas fa-inbox fa-3x mb-3"></i>
<p>Нет доступных площадок</p>
</td>
@@ -1855,10 +1856,17 @@
}
tableBody.innerHTML = '';
categories.forEach(category => {
const publicationBadge = category.marked_for_publication
? '<span class="badge bg-warning status-badge">Для публикации</span>'
: '';
const publishedBadge = category.is_tg_published
? '<span class="badge bg-primary status-badge ms-1">Опубликовано</span>'
: '';
const row = `
<tr class="category-row" data-id="${category.id}">
<td>${category.id || '-'}</td>
<td class="category-name-preview" title="${category.title || ''}">${category.title || 'Без названия'}</td>
<td>${publicationBadge}${publishedBadge}</td>
</tr>`;
tableBody.innerHTML += row;
});
@@ -1878,7 +1886,7 @@
} catch (error) {
tableBody.innerHTML = `
<tr>
<td colspan="2" class="text-center py-5 text-danger">
<td colspan="3" class="text-center py-5 text-danger">
<i class="fas fa-exclamation-triangle fa-2x mb-3"></i>
<p>Ошибка загрузки данных</p>
<button class="btn btn-sm btn-outline-primary mt-2" onclick="loadCategoriesList()">
@@ -1922,6 +1930,20 @@
throw new Error('Площадка не найдена');
}
const category = await response.json();
// Форматируем дату из UTC в локальное время
const formatDateTime = (dateStr) => {
if (!dateStr) return '';
// Парсим дату как UTC и конвертируем в локальное время
const date = new Date(dateStr + (dateStr.includes('Z') ? '' : 'Z'));
return date.toLocaleString('ru-RU', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short'
});
};
// Создаем HTML для деталей
let detailsHtml = `
<div style="position: relative;">
@@ -1939,6 +1961,17 @@
<div class="mb-2">
<strong>Название:</strong> ${category.title || 'Не указано'}
</div>
<div class="mb-2">
<strong>Статус:</strong>
${category.marked_for_publication && !category.is_tg_published ? '<span class="badge bg-warning">Для публикации</span>' : ''}
${!category.marked_for_publication && !category.is_tg_published ? '<span class="badge bg-secondary">Не для публикации</span>' : ''}
${category.is_tg_published ? '<span class="badge bg-primary">Опубликовано</span>' : ''}
</div>
${category.is_tg_published ? `
<div class="mb-2">
<strong>Опубликовано в TG</strong> ${category.tg_id ? `[ID ${category.tg_id}]` : ''} ${category.tg_published_date ? formatDateTime(category.tg_published_date) : ''}
</div>
` : ''}
<div class="mb-2">
<strong>Количество событий:</strong> ${category.event_count || 0}
</div>