192 lines
7.8 KiB
HTML
192 lines
7.8 KiB
HTML
{% extends "base.html" %}
|
||
|
||
{% block title %}Менеджер артефактов - LKM37{% endblock %}
|
||
{% block nav_files %}active{% endblock %}
|
||
|
||
{% block content %}
|
||
<h2 class="mb-4" style="color: var(--matrix-green); text-shadow: 0 0 10px var(--matrix-green);">
|
||
>_ ЦЕНТРАЛЬНЫЙ_АРХИВ_ДАННЫХ (FILES_CORE)
|
||
</h2>
|
||
|
||
<!-- Секция загрузки артефактов -->
|
||
<div class="row mb-4">
|
||
<div class="col-md-12">
|
||
<div class="card bg-black border-success shadow-sm">
|
||
<div class="card-body">
|
||
<h5 class="text-success mb-3"><i class="bi bi-cloud-upload"></i> РЕГИСТРАЦИЯ НОВОГО АРТЕФАКТА В TELEGRAM</h5>
|
||
<p class="small text-muted mb-3">Загрузите файл сюда, и бот отправит его вам в личку, чтобы получить постоянный <code>file_id</code>. Вы сможете использовать этот ID в рассылках и постах многократно.</p>
|
||
<form id="uploadForm" class="row g-3">
|
||
<div class="col-md-9">
|
||
<input type="file" id="fileInput" class="form-control bg-dark border-success text-success">
|
||
</div>
|
||
<div class="col-md-3">
|
||
<button type="button" id="uploadBtn" onclick="uploadFile()" class="btn btn-matrix w-100">
|
||
<span id="uploadSpinner" class="spinner-border spinner-border-sm d-none" role="status"></span>
|
||
ЗАГРУЗИТЬ
|
||
</button>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Таблица артефактов -->
|
||
<div class="card mb-4 border-info">
|
||
<div class="card-header border-info bg-info bg-opacity-10 d-flex justify-content-between align-items-center">
|
||
<span class="text-info fw-bold">💠 АРТЕФАКТЫ TELEGRAM (ДЛЯ РАССЫЛОК)</span>
|
||
<button class="btn btn-outline-info btn-sm" onclick="loadFiles()">
|
||
<i class="bi bi-arrow-clockwise"></i> ОБНОВИТЬ
|
||
</button>
|
||
</div>
|
||
<div class="card-body p-0">
|
||
<div class="table-responsive">
|
||
<table class="table table-dark table-hover mb-0">
|
||
<thead>
|
||
<tr class="text-info opacity-75" style="font-size: 0.8em;">
|
||
<th>ИМЯ ФАЙЛА</th>
|
||
<th>ТИП</th>
|
||
<th>TELEGRAM_FILE_ID</th>
|
||
<th class="text-end">ДЕЙСТВИЯ</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="artifactsTable">
|
||
<!-- Заполняется через API -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Таблица системных файлов -->
|
||
<div class="card border-secondary">
|
||
<div class="card-header border-secondary bg-secondary bg-opacity-10">
|
||
<span class="text-secondary fw-bold">📁 СИСТЕМНЫЕ ФАЙЛЫ (ЛОГИ И ЭКСПОРТЫ)</span>
|
||
</div>
|
||
<div class="card-body p-0">
|
||
<div class="table-responsive">
|
||
<table class="table table-dark table-hover mb-0">
|
||
<thead>
|
||
<tr class="text-muted" style="font-size: 0.8em;">
|
||
<th>ИМЯ ФАЙЛА</th>
|
||
<th>КАТЕГОРИЯ</th>
|
||
<th>РАЗМЕР</th>
|
||
<th class="text-end">ДЕЙСТВИЯ</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody id="systemFilesTable">
|
||
<!-- Заполняется через API -->
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
|
||
{% block extra_script %}
|
||
<script>
|
||
document.addEventListener('DOMContentLoaded', loadFiles);
|
||
|
||
async function loadFiles() {
|
||
const artifactsTable = document.getElementById('artifactsTable');
|
||
const systemFilesTable = document.getElementById('systemFilesTable');
|
||
|
||
try {
|
||
const response = await fetch('/api/files/list');
|
||
const result = await response.json();
|
||
|
||
if (!result.success) throw new Error(result.error);
|
||
|
||
artifactsTable.innerHTML = '';
|
||
systemFilesTable.innerHTML = '';
|
||
|
||
const artifacts = result.files.filter(f => f.is_artifact);
|
||
const systemFiles = result.files.filter(f => !f.is_artifact);
|
||
|
||
if (artifacts.length === 0) {
|
||
artifactsTable.innerHTML = '<tr><td colspan="4" class="text-center p-3 text-muted">Артефакты не зарегистрированы</td></tr>';
|
||
} else {
|
||
artifacts.forEach(f => {
|
||
artifactsTable.innerHTML += `
|
||
<tr>
|
||
<td class="font-monospace text-info">${f.filename}</td>
|
||
<td><span class="badge bg-info text-dark">${f.file_type}</span></td>
|
||
<td><code class="text-success small" style="word-break: break-all;">${f.file_id}</code></td>
|
||
<td class="text-end">
|
||
<button class="btn btn-sm btn-outline-info" onclick="copyId('${f.file_id}')">
|
||
<i class="bi bi-copy"></i> ID
|
||
</button>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
});
|
||
}
|
||
|
||
if (systemFiles.length === 0) {
|
||
systemFilesTable.innerHTML = '<tr><td colspan="4" class="text-center p-3 text-muted">Файлы не найдены</td></tr>';
|
||
} else {
|
||
systemFiles.forEach(f => {
|
||
systemFilesTable.innerHTML += `
|
||
<tr>
|
||
<td class="font-monospace">${f.filename}</td>
|
||
<td><span class="badge bg-secondary">${f.file_type}</span></td>
|
||
<td class="text-muted">${f.size}</td>
|
||
<td class="text-end">
|
||
<a href="${f.path}" class="btn btn-sm btn-outline-secondary" download>
|
||
<i class="bi bi-download"></i>
|
||
</a>
|
||
</td>
|
||
</tr>
|
||
`;
|
||
});
|
||
}
|
||
} catch (error) {
|
||
console.error(error);
|
||
}
|
||
}
|
||
|
||
function copyId(id) {
|
||
navigator.clipboard.writeText(id);
|
||
const toast = document.createElement('div');
|
||
toast.className = 'position-fixed bottom-0 end-0 p-3';
|
||
toast.style.zIndex = '11';
|
||
toast.innerHTML = `<div class="alert alert-success">FILE_ID скопирован!</div>`;
|
||
document.body.appendChild(toast);
|
||
setTimeout(() => toast.remove(), 2000);
|
||
}
|
||
|
||
async function uploadFile() {
|
||
const fileInput = document.getElementById('fileInput');
|
||
const btn = document.getElementById('uploadBtn');
|
||
const spinner = document.getElementById('uploadSpinner');
|
||
|
||
if (!fileInput.files[0]) return alert('Выберите файл для загрузки');
|
||
|
||
btn.disabled = true;
|
||
spinner.classList.remove('d-none');
|
||
|
||
const formData = new FormData();
|
||
formData.append('file', fileInput.files[0]);
|
||
|
||
try {
|
||
const response = await fetch('/api/files/upload', {
|
||
method: 'POST',
|
||
body: formData
|
||
});
|
||
const result = await response.json();
|
||
|
||
if (result.success) {
|
||
alert('Файл успешно зарегистрирован в Telegram!\nFILE_ID: ' + result.file_id);
|
||
location.reload();
|
||
} else {
|
||
alert('Ошибка при регистрации: ' + result.error);
|
||
}
|
||
} catch (error) {
|
||
alert('Сетевая ошибка: ' + error.message);
|
||
} finally {
|
||
btn.disabled = false;
|
||
spinner.classList.add('d-none');
|
||
}
|
||
}
|
||
</script>
|
||
{% endblock %}
|