sozday-sovremennyy-dostupnyy/index.html

530 lines
11 KiB
HTML
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.

<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Анализ данных — загрузи файл и получи отчёт</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;600;700&family=Unbounded:wght@700&display=swap" rel="stylesheet">
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>📊</text></svg>">
<script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.min.js"></script>
<style>
:root {
--primary: #6366F1;
--primary-dark: #4F46E5;
--primary-light: #EEF2FF;
--accent: #10B981;
--ink: #0F1218;
--ink-light: #2D3748;
--gray-100: #F7FAFC;
--gray-200: #EDF2F7;
--gray-300: #CBD5E0;
--gray-500: #718096;
--white: #FFFFFF;
--error: #E53E3E;
--warning: #DD6B20;
--font-heading: 'Unbounded', sans-serif;
--font-body: 'Manrope', sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
font-family: var(--font-body);
font-size: 17px;
line-height: 1.6;
color: var(--ink);
background: var(--white);
}
.container { max-width: 1200px; margin: 0 auto; padding: 0 24px; }
header {
background: var(--white);
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
padding: 16px 0;
position: sticky;
top: 0;
z-index: 100;
}
.header-content {
display: flex;
align-items: center;
justify-content: space-between;
}
.logo {
display: flex;
align-items: center;
gap: 12px;
font-size: 24px;
font-weight: 700;
color: var(--primary);
}
.hero {
background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
color: var(--white);
padding: 60px 0;
text-align: center;
}
.hero h1 {
font-family: var(--font-heading);
font-size: clamp(32px, 5vw, 48px);
margin-bottom: 16px;
}
.hero p {
font-size: 18px;
opacity: 0.9;
max-width: 600px;
margin: 0 auto 32px;
}
.upload-section {
background: var(--white);
border-radius: 16px;
padding: 40px;
max-width: 700px;
margin: -40px auto 40px;
box-shadow: 0 20px 40px rgba(0,0,0,0.1);
position: relative;
z-index: 10;
}
.upload-area {
border: 3px dashed var(--gray-300);
border-radius: 12px;
padding: 40px;
text-align: center;
cursor: pointer;
transition: all 0.3s ease;
background: var(--gray-100);
}
.upload-area:hover,
.upload-area.dragover {
border-color: var(--primary);
background: var(--primary-light);
}
.upload-area.has-file {
border-color: var(--accent);
background: #ECFDF5;
}
.upload-icon {
font-size: 64px;
margin-bottom: 16px;
}
.upload-text {
font-size: 18px;
font-weight: 600;
margin-bottom: 8px;
}
.upload-hint {
font-size: 14px;
color: var(--gray-500);
}
#file-input { display: none; }
.file-info {
display: none;
margin-top: 24px;
padding: 16px;
background: var(--white);
border-radius: 8px;
border-left: 4px solid var(--accent);
}
.file-info.visible { display: block; }
.file-name {
font-weight: 600;
margin-bottom: 8px;
}
.file-meta {
font-size: 14px;
color: var(--gray-500);
}
.analyze-btn {
display: block;
width: 100%;
padding: 16px;
background: var(--primary);
color: var(--white);
border: none;
border-radius: 8px;
font-size: 18px;
font-weight: 700;
cursor: pointer;
margin-top: 24px;
transition: all 0.3s ease;
}
.analyze-btn:hover {
background: var(--primary-dark);
transform: translateY(-2px);
}
.analyze-btn:disabled {
background: var(--gray-300);
cursor: not-allowed;
transform: none;
}
.results {
display: none;
padding: 40px 0;
}
.results.visible { display: block; }
.section-title {
font-family: var(--font-heading);
font-size: 28px;
margin-bottom: 24px;
color: var(--ink);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 40px;
}
.stat-card {
background: var(--white);
border: 2px solid var(--gray-200);
border-radius: 12px;
padding: 24px;
text-align: center;
transition: all 0.3s ease;
}
.stat-card:hover {
border-color: var(--primary);
transform: translateY(-4px);
box-shadow: 0 8px 16px rgba(0,0,0,0.08);
}
.stat-value {
font-size: 36px;
font-weight: 700;
color: var(--primary);
margin-bottom: 8px;
}
.stat-label {
font-size: 14px;
color: var(--gray-500);
}
.charts-section {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
gap: 24px;
margin-bottom: 40px;
}
.chart-card {
background: var(--white);
border: 2px solid var(--gray-200);
border-radius: 12px;
padding: 24px;
}
.chart-card h3 {
font-size: 18px;
margin-bottom: 16px;
color: var(--ink);
}
.chart-container {
position: relative;
height: 300px;
}
.table-section {
background: var(--white);
border: 2px solid var(--gray-200);
border-radius: 12px;
padding: 24px;
margin-bottom: 40px;
overflow-x: auto;
}
.table-section h3 {
font-size: 18px;
margin-bottom: 16px;
}
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.data-table th,
.data-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid var(--gray-200);
}
.data-table th {
background: var(--gray-100);
font-weight: 600;
position: sticky;
top: 0;
}
.data-table tbody tr:hover {
background: var(--gray-100);
}
.insights-section {
background: linear-gradient(135deg, var(--primary-light) 0%, #ECFDF5 100%);
border-radius: 12px;
padding: 32px;
margin-bottom: 40px;
}
.insights-section h3 {
font-size: 20px;
margin-bottom: 16px;
color: var(--ink);
}
.insight-item {
display: flex;
gap: 16px;
padding: 16px 0;
border-bottom: 1px solid var(--gray-200);
}
.insight-item:last-child {
border-bottom: none;
}
.insight-icon {
font-size: 24px;
flex-shrink: 0;
}
.insight-text {
flex: 1;
}
.insight-text strong {
color: var(--primary-dark);
}
.export-section {
text-align: center;
padding: 24px;
background: var(--white);
border-radius: 12px;
border: 2px solid var(--gray-200);
}
.export-btn {
padding: 14px 28px;
background: var(--accent);
color: var(--white);
border: none;
border-radius: 8px;
font-size: 16px;
font-weight: 700;
cursor: pointer;
margin: 0 8px;
transition: all 0.3s ease;
}
.export-btn:hover {
background: #059669;
transform: translateY(-2px);
}
.loading {
display: none;
text-align: center;
padding: 40px;
}
.loading.visible {
display: block;
}
.spinner {
width: 50px;
height: 50px;
border: 4px solid var(--gray-200);
border-top-color: var(--primary);
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 16px;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.error-message {
display: none;
background: #FEF2F2;
border: 2px solid var(--error);
border-radius: 12px;
padding: 24px;
margin: 24px 0;
color: var(--error);
}
.error-message.visible {
display: block;
}
footer {
background: var(--ink);
color: var(--white);
padding: 40px 0;
text-align: center;
margin-top: 60px;
}
footer p {
opacity: 0.7;
font-size: 14px;
}
@media (max-width: 768px) {
.charts-section {
grid-template-columns: 1fr;
}
.upload-section {
padding: 24px;
margin: -20px 20px 24px;
}
.stat-card {
padding: 16px;
}
.stat-value {
font-size: 28px;
}
}
</style>
</head>
<body>
<header role="banner">
<div class="container header-content">
<div class="logo">
<span aria-hidden="true">📊</span>
<span>DataAnalyzer</span>
</div>
</div>
</header>
<main role="main">
<section class="hero" aria-labelledby="hero-title">
<div class="container">
<h1 id="hero-title">Анализ данных онлайн</h1>
<p>Загрузите Excel или CSV файл — получите готовый отчёт с графиками и выводами за секунды</p>
</div>
</section>
<div class="container">
<section class="upload-section" aria-labelledby="upload-title">
<h2 id="upload-title" class="visually-hidden">Загрузка файла</h2>
<div class="upload-area" id="upload-area" role="button" tabindex="0" aria-describedby="upload-desc">
<div class="upload-icon" aria-hidden="true">📁</div>
<div class="upload-text">Перетащите файл сюда</div>
<div class="upload-hint" id="upload-desc">или нажмите, чтобы выбрать (.xlsx, .xls, .csv)</div>
<input type="file" id="file-input" accept=".xlsx,.xls,.csv" aria-label="Выбрать файл для загрузки">
</div>
<div class="file-info" id="file-info" role="status" aria-live="polite">
<div class="file-name" id="file-name"></div>
<div class="file-meta" id="file-meta"></div>
</div>
<button class="analyze-btn" id="analyze-btn" disabled>
🔍 Начать анализ
</button>
<div class="error-message" id="error-message" role="alert"></div>
<div class="loading" id="loading" aria-live="polite">
<div class="spinner" aria-hidden="true"></div>
<div>Анализируем данные...</div>
</div>
</section>
<section class="results" id="results" aria-labelledby="results-title">
<h2 id="results-title" class="section-title">📈 Результаты анализа</h2>
<div class="insights-section" id="insights-section">
<h3>💡 Ключевые выводы</h3>
<div id="insights-list"></div>
</div>
<h3 class="section-title">📊 Статистика</h3>
<div class="stats-grid" id="stats-grid"></div>
<h3 class="section-title">📉 Графики</h3>
<div class="charts-section" id="charts-section"></div>
<h3 class="section-title">📋 Данные</h3>
<div class="table-section">
<div style="overflow-x: auto;">
<table class="data-table" id="data-table"></table>
</div>
</div>
<div class="export-section">
<h3 style="margin-bottom: 16px;">💾 Экспорт отчёта</h3>
<button class="export-btn" onclick="exportToCSV()">📥 Скачать CSV</button>
<button class="export-btn" onclick="exportToExcel()">📊 Скачать Excel</button>
<button class="export-btn" onclick="window.print()">🖨️ Печать</button>
</div>
</section>
</div>
</main>
<footer role="contentinfo">
<div class="container">
<p>© 2026 DataAnalyzer. Все данные обрабатываются в вашем браузере и не отправляются на сервер.</p>
</div>
</footer>
<style>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}
</style>
<script src="script.js"></script>
</body>
</html>