Initial
This commit is contained in:
423
miniapp2.html
Normal file
423
miniapp2.html
Normal file
@@ -0,0 +1,423 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="ru">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Загрузка файлов</title>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<style>
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.container {
|
||||
background: white;
|
||||
border-radius: 20px;
|
||||
padding: 30px;
|
||||
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.header h1 {
|
||||
color: #333;
|
||||
font-size: 24px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.header p {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.file-upload {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.file-upload label {
|
||||
display: block;
|
||||
margin-bottom: 8px;
|
||||
color: #333;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.file-input-wrapper {
|
||||
position: relative;
|
||||
border: 2px dashed #ddd;
|
||||
border-radius: 12px;
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
transition: all 0.3s ease;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.file-input-wrapper:hover {
|
||||
border-color: #667eea;
|
||||
background-color: #f8f9ff;
|
||||
}
|
||||
|
||||
.file-input-wrapper.dragover {
|
||||
border-color: #667eea;
|
||||
background-color: #f0f2ff;
|
||||
}
|
||||
|
||||
.file-input {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.file-input-text {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.file-input-text strong {
|
||||
color: #667eea;
|
||||
}
|
||||
|
||||
.file-preview {
|
||||
margin-top: 10px;
|
||||
padding: 10px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.file-preview.show {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.file-preview .file-name {
|
||||
font-weight: 500;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.file-preview .file-size {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.submit-btn {
|
||||
width: 100%;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 15px;
|
||||
border-radius: 12px;
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.submit-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
|
||||
}
|
||||
|
||||
.submit-btn:disabled {
|
||||
background: #ccc;
|
||||
cursor: not-allowed;
|
||||
transform: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-top: 15px;
|
||||
padding: 10px;
|
||||
border-radius: 8px;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.status.success {
|
||||
background: #d4edda;
|
||||
color: #155724;
|
||||
border: 1px solid #c3e6cb;
|
||||
}
|
||||
|
||||
.status.error {
|
||||
background: #f8d7da;
|
||||
color: #721c24;
|
||||
border: 1px solid #f5c6cb;
|
||||
}
|
||||
|
||||
.loading {
|
||||
display: none;
|
||||
text-align: center;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
border: 3px solid #f3f3f3;
|
||||
border-top: 3px solid #667eea;
|
||||
border-radius: 50%;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
animation: spin 1s linear infinite;
|
||||
margin: 0 auto 10px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>📁 Загрузка файлов</h1>
|
||||
<p>Выберите два файла для отправки</p>
|
||||
</div>
|
||||
|
||||
<form id="uploadForm">
|
||||
<div class="file-upload">
|
||||
<label for="file1">Первый файл</label>
|
||||
<div class="file-input-wrapper" onclick="document.getElementById('file1').click()">
|
||||
<input type="file" id="file1" class="file-input" accept="*/*">
|
||||
<div class="file-input-text">
|
||||
<strong>Нажмите</strong> или перетащите файл сюда
|
||||
</div>
|
||||
</div>
|
||||
<div id="preview1" class="file-preview">
|
||||
<div class="file-name"></div>
|
||||
<div class="file-size"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="file-upload">
|
||||
<label for="file2">Второй файл</label>
|
||||
<div class="file-input-wrapper" onclick="document.getElementById('file2').click()">
|
||||
<input type="file" id="file2" class="file-input" accept="*/*">
|
||||
<div class="file-input-text">
|
||||
<strong>Нажмите</strong> или перетащите файл сюда
|
||||
</div>
|
||||
</div>
|
||||
<div id="preview2" class="file-preview">
|
||||
<div class="file-name"></div>
|
||||
<div class="file-size"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="submit-btn" id="submitBtn">
|
||||
📤 Отправить файлы
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="loading" id="loading">
|
||||
<div class="spinner"></div>
|
||||
<p>Отправляем файлы...</p>
|
||||
</div>
|
||||
|
||||
<div class="status" id="status"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Инициализация Telegram Web App с проверкой доступности
|
||||
let tg = window.Telegram?.WebApp;
|
||||
|
||||
// Проверяем, доступен ли Telegram Web App API
|
||||
if (tg) {
|
||||
tg.ready();
|
||||
tg.expand();
|
||||
}
|
||||
|
||||
// Универсальная функция закрытия мини-аппа
|
||||
function closeMiniApp() {
|
||||
if (tg && typeof tg.close === 'function') {
|
||||
// Если доступен Telegram Web App API
|
||||
tg.close();
|
||||
} else if (window.parent && window.parent !== window) {
|
||||
// Если открыто в iframe (n8n webhook)
|
||||
try {
|
||||
window.parent.postMessage({ type: 'close' }, '*');
|
||||
} catch (e) {
|
||||
console.log('Не удалось закрыть через postMessage');
|
||||
}
|
||||
} else {
|
||||
// Альтернативный способ - попытка закрыть окно
|
||||
try {
|
||||
window.close();
|
||||
} catch (e) {
|
||||
console.log('Не удалось закрыть окно');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Настройка темы
|
||||
if (tg && tg.colorScheme === 'dark') {
|
||||
document.body.style.background = 'linear-gradient(135deg, #2c3e50 0%, #34495e 100%)';
|
||||
document.querySelector('.container').style.background = '#2c3e50';
|
||||
document.querySelector('.container').style.color = 'white';
|
||||
}
|
||||
|
||||
const file1Input = document.getElementById('file1');
|
||||
const file2Input = document.getElementById('file2');
|
||||
const preview1 = document.getElementById('preview1');
|
||||
const preview2 = document.getElementById('preview2');
|
||||
const submitBtn = document.getElementById('submitBtn');
|
||||
const loading = document.getElementById('loading');
|
||||
const status = document.getElementById('status');
|
||||
|
||||
// Функция для отображения предварительного просмотра файла
|
||||
function showFilePreview(file, previewElement) {
|
||||
if (file) {
|
||||
const fileName = file.name;
|
||||
const fileSize = (file.size / 1024).toFixed(2) + ' KB';
|
||||
|
||||
previewElement.querySelector('.file-name').textContent = fileName;
|
||||
previewElement.querySelector('.file-size').textContent = fileSize;
|
||||
previewElement.classList.add('show');
|
||||
} else {
|
||||
previewElement.classList.remove('show');
|
||||
}
|
||||
}
|
||||
|
||||
// Обработчики для файлов
|
||||
file1Input.addEventListener('change', (e) => {
|
||||
showFilePreview(e.target.files[0], preview1);
|
||||
updateSubmitButton();
|
||||
});
|
||||
|
||||
file2Input.addEventListener('change', (e) => {
|
||||
showFilePreview(e.target.files[0], preview2);
|
||||
updateSubmitButton();
|
||||
});
|
||||
|
||||
// Drag and drop функциональность
|
||||
function setupDragAndDrop(inputElement, previewElement) {
|
||||
const wrapper = inputElement.parentElement;
|
||||
|
||||
wrapper.addEventListener('dragover', (e) => {
|
||||
e.preventDefault();
|
||||
wrapper.classList.add('dragover');
|
||||
});
|
||||
|
||||
wrapper.addEventListener('dragleave', (e) => {
|
||||
e.preventDefault();
|
||||
wrapper.classList.remove('dragover');
|
||||
});
|
||||
|
||||
wrapper.addEventListener('drop', (e) => {
|
||||
e.preventDefault();
|
||||
wrapper.classList.remove('dragover');
|
||||
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
inputElement.files = files;
|
||||
showFilePreview(files[0], previewElement);
|
||||
updateSubmitButton();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setupDragAndDrop(file1Input, preview1);
|
||||
setupDragAndDrop(file2Input, preview2);
|
||||
|
||||
// Обновление состояния кнопки отправки
|
||||
function updateSubmitButton() {
|
||||
const file1 = file1Input.files[0];
|
||||
const file2 = file2Input.files[0];
|
||||
|
||||
if (file1 && file2) {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = '📤 Отправить файлы';
|
||||
} else {
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '⚠️ Выберите оба файла';
|
||||
}
|
||||
}
|
||||
|
||||
// Обработка отправки формы
|
||||
document.getElementById('uploadForm').addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const file1 = file1Input.files[0];
|
||||
const file2 = file2Input.files[0];
|
||||
|
||||
if (!file1 || !file2) {
|
||||
showStatus('Пожалуйста, выберите оба файла', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Показываем загрузку
|
||||
loading.style.display = 'block';
|
||||
submitBtn.disabled = true;
|
||||
status.style.display = 'none';
|
||||
|
||||
try {
|
||||
// Создаем FormData для отправки файлов
|
||||
const formData = new FormData();
|
||||
formData.append('file1', file1);
|
||||
formData.append('file2', file2);
|
||||
formData.append('user_id', tg?.initDataUnsafe?.user?.id || 'unknown');
|
||||
|
||||
// Здесь должна быть логика отправки на ваш сервер
|
||||
// Для демонстрации используем setTimeout
|
||||
await new Promise(resolve => setTimeout(resolve, 2000));
|
||||
|
||||
// Симуляция успешной отправки
|
||||
showStatus('✅ Файлы успешно отправлены!', 'success');
|
||||
|
||||
// Очищаем форму
|
||||
file1Input.value = '';
|
||||
file2Input.value = '';
|
||||
preview1.classList.remove('show');
|
||||
preview2.classList.remove('show');
|
||||
updateSubmitButton();
|
||||
|
||||
// Закрываем мини-апп через 2 секунды после успешной отправки
|
||||
setTimeout(() => {
|
||||
closeMiniApp();
|
||||
}, 2000);
|
||||
|
||||
} catch (error) {
|
||||
showStatus('❌ Ошибка при отправке файлов: ' + error.message, 'error');
|
||||
} finally {
|
||||
loading.style.display = 'none';
|
||||
submitBtn.disabled = false;
|
||||
}
|
||||
});
|
||||
|
||||
// Функция для отображения статуса
|
||||
function showStatus(message, type) {
|
||||
status.textContent = message;
|
||||
status.className = `status ${type}`;
|
||||
status.style.display = 'block';
|
||||
|
||||
// Скрываем статус через 5 секунд
|
||||
setTimeout(() => {
|
||||
status.style.display = 'none';
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
// Инициализация
|
||||
updateSubmitButton();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user