sozday-sovremennyy-veb-sayt/excel-editor.html

330 lines
14 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" data-theme="auto">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Excel Редактор | Сопоставление данных</title>
<link rel="icon" href="design-system/brand/kt-ai-logo.png">
<link rel="stylesheet" href="design-system/kt-ai-fonts.css">
<link rel="stylesheet" href="design-system/kt-ai-tokens.css">
<link rel="stylesheet" href="design-system/kt-ai-components.css">
<link rel="stylesheet" href="design-system/kt-ai-page.css">
<style>
.kt-ai-btn { text-decoration: none; }
.upload-zone {
border: 2px dashed var(--kt-ai-border);
border-radius: var(--kt-ai-radius-xl);
padding: var(--kt-ai-space-8);
text-align: center;
cursor: pointer;
transition: all 0.2s;
background: var(--kt-ai-bg-soft);
}
.upload-zone:hover {
border-color: var(--kt-ai-primary);
background: var(--kt-ai-primary-bg);
}
.upload-zone.has-file {
border-color: var(--kt-ai-success);
background: var(--kt-ai-success-bg);
}
.file-info {
margin-top: var(--kt-ai-space-3);
font-size: var(--kt-ai-text-sm);
color: var(--kt-ai-fg-muted);
}
.mapping-row {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: var(--kt-ai-space-3);
align-items: center;
padding: var(--kt-ai-space-3);
border-radius: var(--kt-ai-radius-lg);
background: var(--kt-ai-bg-soft);
margin-bottom: var(--kt-ai-space-2);
}
.mapping-row.matched {
background: var(--kt-ai-success-bg);
}
.mapping-row.no-match {
background: var(--kt-ai-warning-bg);
}
.column-badge {
padding: var(--kt-ai-space-1) var(--kt-ai-space-2);
border-radius: var(--kt-ai-radius-md);
background: var(--kt-ai-card-bg);
border: 1px solid var(--kt-ai-border);
font-size: var(--kt-ai-text-xs);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.preview-table {
width: 100%;
border-collapse: collapse;
font-size: var(--kt-ai-text-sm);
}
.preview-table th,
.preview-table td {
padding: var(--kt-ai-space-2) var(--kt-ai-space-3);
border: 1px solid var(--kt-ai-border);
text-align: left;
}
.preview-table th {
background: var(--kt-ai-bg-soft);
font-weight: var(--kt-ai-weight-semibold);
position: sticky;
top: 0;
}
.preview-table tr:nth-child(even) {
background: var(--kt-ai-bg-soft);
}
.preview-table tr:hover {
background: var(--kt-ai-primary-bg);
}
.table-container {
max-height: 400px;
overflow: auto;
border: 1px solid var(--kt-ai-border);
border-radius: var(--kt-ai-radius-lg);
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: var(--kt-ai-space-4);
margin: var(--kt-ai-space-4) 0;
}
.stat-card {
padding: var(--kt-ai-space-4);
border-radius: var(--kt-ai-radius-lg);
background: var(--kt-ai-card-bg);
border: 1px solid var(--kt-ai-border);
}
.stat-value {
font-size: var(--kt-ai-text-2xl);
font-weight: var(--kt-ai-weight-bold);
color: var(--kt-ai-fg);
}
.stat-label {
font-size: var(--kt-ai-text-xs);
color: var(--kt-ai-fg-muted);
margin-top: var(--kt-ai-space-1);
}
.step-indicator {
display: flex;
gap: var(--kt-ai-space-2);
margin-bottom: var(--kt-ai-space-6);
}
.step {
flex: 1;
padding: var(--kt-ai-space-3);
border-radius: var(--kt-ai-radius-lg);
background: var(--kt-ai-bg-soft);
border: 2px solid var(--kt-ai-border);
text-align: center;
font-size: var(--kt-ai-text-sm);
font-weight: var(--kt-ai-weight-semibold);
}
.step.active {
border-color: var(--kt-ai-primary);
background: var(--kt-ai-primary-bg);
color: var(--kt-ai-primary-fg);
}
.step.completed {
border-color: var(--kt-ai-success);
background: var(--kt-ai-success-bg);
}
.hidden { display: none; }
</style>
</head>
<body>
<header class="kt-ai-pagehead">
<div class="kt-ai-wrap kt-ai-pagehead-in">
<div style="display: flex; align-items: center; gap: var(--kt-ai-space-3);">
<img src="design-system/brand/kt-ai-logo.png" alt="" height="24">
<strong>Excel Редактор</strong>
</div>
<span class="kt-ai-spacer"></span>
<a class="kt-ai-btn" data-variant="ghost" href="index.html">← Назад</a>
</div>
</header>
<main>
<section class="kt-ai-hero" data-align="center">
<div class="kt-ai-wrap">
<h1>Сопоставление Excel файлов</h1>
<p class="kt-ai-hero-sub">Заполните пустые столбцы шаблона данными из основного файла по номеру телефона или лицевому счету</p>
</div>
</section>
<div class="kt-ai-wrap">
<div class="step-indicator">
<div class="step active" id="step1">1. Загрузка файлов</div>
<div class="step" id="step2">2. Настройка полей</div>
<div class="step" id="step3">3. Результат</div>
</div>
<!-- STEP 1: UPLOAD -->
<div id="upload-section">
<div class="kt-ai-section">
<div class="kt-ai-wrap">
<div class="kt-ai-section-head">
<h2>Загрузите файлы</h2>
<p>Основной файл содержит данные для заполнения, шаблон — файл для заполнения</p>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: var(--kt-ai-space-6); margin-top: var(--kt-ai-space-6);">
<div>
<h3 style="margin-bottom: var(--kt-ai-space-3);">Основной файл</h3>
<div class="upload-zone" id="main-upload" onclick="document.getElementById('main-file').click()">
<svg class="kt-icon kt-icon-lg" style="color: var(--kt-ai-primary);" aria-hidden="true"><use href="#file"></use></svg>
<p style="margin-top: var(--kt-ai-space-3); font-weight: var(--kt-ai-weight-medium);">Основной файл с данными</p>
<p style="font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-top: var(--kt-ai-space-1);">.xlsx, .xls, .csv</p>
<div class="file-info" id="main-file-info"></div>
</div>
<input type="file" id="main-file" accept=".xlsx,.xls,.csv" style="display: none;" onchange="handleFileSelect(event, 'main')">
</div>
<div>
<h3 style="margin-bottom: var(--kt-ai-space-3);">Файл-шаблон</h3>
<div class="upload-zone" id="template-upload" onclick="document.getElementById('template-file').click()">
<svg class="kt-icon kt-icon-lg" style="color: var(--kt-ai-primary);" aria-hidden="true"><use href="#file"></use></svg>
<p style="margin-top: var(--kt-ai-space-3); font-weight: var(--kt-ai-weight-medium);">Шаблон для заполнения</p>
<p style="font-size: var(--kt-ai-text-sm); color: var(--kt-ai-fg-muted); margin-top: var(--kt-ai-space-1);">.xlsx, .xls, .csv</p>
<div class="file-info" id="template-file-info"></div>
</div>
<input type="file" id="template-file" accept=".xlsx,.xls,.csv" style="display: none;" onchange="handleFileSelect(event, 'template')">
</div>
</div>
<div style="margin-top: var(--kt-ai-space-6); text-align: center;">
<button class="kt-ai-btn" data-variant="primary" data-size="lg" id="btn-mapping" onclick="goToMapping()" disabled>
<svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#arrowRight"></use></svg>
Продолжить
</button>
</div>
</div>
</div>
</div>
<!-- STEP 2: MAPPING -->
<div id="mapping-section" class="hidden">
<div class="kt-ai-section">
<div class="kt-ai-wrap">
<div class="kt-ai-section-head">
<h2>Настройте поля для сопоставления</h2>
<p>Укажите, какие поля использовать для поиска соответствий</p>
</div>
<div class="kt-ai-card" style="padding: var(--kt-ai-space-5); margin-top: var(--kt-ai-space-4);">
<h3 style="margin-bottom: var(--kt-ai-space-4);">1. Ключевое поле для поиска</h3>
<p style="color: var(--kt-ai-fg-muted); margin-bottom: var(--kt-ai-space-3);">По какому полю искать совпадения (номер телефона или лицевой счет)</p>
<div style="display: grid; grid-template-columns: 1fr auto 1fr; gap: var(--kt-ai-space-4); align-items: end;">
<div class="kt-ai-field">
<label>В основном файле</label>
<select class="kt-ai-select" id="main-key-field" onchange="processMapping()"></select>
</div>
<div style="padding-top: var(--kt-ai-space-6);">
<svg class="kt-icon kt-icon-lg" style="color: var(--kt-ai-primary);" aria-hidden="true"><use href="#arrowRight"></use></svg>
</div>
<div class="kt-ai-field">
<label>В шаблоне</label>
<select class="kt-ai-select" id="template-key-field" onchange="processMapping()"></select>
</div>
</div>
<h3 style="margin: var(--kt-ai-space-6) 0 var(--kt-ai-space-4);">2. Какие столбцы заполнять</h3>
<p style="color: var(--kt-ai-fg-muted); margin-bottom: var(--kt-ai-space-3);">Укажите, какие столбцы из какого поля брать</p>
<div id="column-mappings" style="margin-bottom: var(--kt-ai-space-4);">
<!-- Сюда добавляются пары столбцов -->
</div>
<button class="kt-ai-btn" data-variant="ghost" onclick="addMappingRow()" style="margin-bottom: var(--kt-ai-space-4);">
<svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#plus"></use></svg>
Добавить пару столбцов
</button>
<div id="mapping-stats" class="stats-grid"></div>
</div>
<div class="kt-ai-card" style="padding: var(--kt-ai-space-5); margin-top: var(--kt-ai-space-4);">
<h3 style="margin-bottom: var(--kt-ai-space-4);">Предпросмотр сопоставления</h3>
<div class="table-container">
<table class="preview-table" id="mapping-preview"></table>
</div>
</div>
<div style="margin-top: var(--kt-ai-space-6); display: flex; gap: var(--kt-ai-space-3);">
<button class="kt-ai-btn" data-variant="ghost" onclick="goBackToUpload()">Назад</button>
<button class="kt-ai-btn" data-variant="primary" data-size="lg" id="btn-process" onclick="processFiles()" disabled>
<svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#rocket"></use></svg>
Заполнить и скачать результат
</button>
</div>
</div>
</div>
</div>
<!-- STEP 3: RESULT -->
<div id="result-section" class="hidden">
<div class="kt-ai-section">
<div class="kt-ai-wrap">
<div class="kt-ai-section-head">
<h2>Готово!</h2>
<p>Файл успешно обработан</p>
</div>
<div class="kt-ai-card" style="padding: var(--kt-ai-space-6); text-align: center;">
<svg class="kt-icon kt-icon-lg" style="color: var(--kt-ai-success);" aria-hidden="true"><use href="#check"></use></svg>
<h3 style="margin: var(--kt-ai-space-4) 0;">Файл готов к скачиванию</h3>
<p style="color: var(--kt-ai-fg-muted); margin-bottom: var(--kt-ai-space-4);">Все пустые столбцы заполнены данными из основного файла</p>
<div style="display: flex; gap: var(--kt-ai-space-3); justify-content: center; margin-top: var(--kt-ai-space-4);">
<a class="kt-ai-btn" data-variant="primary" data-size="lg" id="download-link" href="#">
<svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#download"></use></svg>
Скачать Excel
</a>
<button class="kt-ai-btn" data-variant="ghost" onclick="location.reload()">
<svg class="kt-icon kt-icon-sm" aria-hidden="true"><use href="#refresh"></use></svg>
Обработать ещё
</button>
</div>
</div>
<div class="stats-grid" id="result-stats"></div>
</div>
</div>
</div>
</div>
</main>
<footer class="kt-ai-wrap kt-ai-pagefoot">
<span>© 2026 Excel Редактор</span>
<span class="kt-ai-spacer"></span>
<span>Сопоставление данных по ключевым полям</span>
</footer>
<script src="https://cdn.sheetjs.com/xlsx-0.20.1/package/dist/xlsx.full.min.js"></script>
<script>
// Проверка загрузки библиотеки
window.addEventListener('DOMContentLoaded', function() {
console.log('DOM загружен');
if (window.XLSX) {
console.log('SheetJS версии:', XLSX.version);
} else {
console.error('SheetJS НЕ загружен!');
document.getElementById('upload-section').innerHTML =
'<div class="kt-ai-card" style="padding: var(--kt-ai-space-5); text-align: center; background: var(--kt-ai-danger-bg);">' +
'<h3>Ошибка загрузки библиотеки</h3>' +
'<p>Не удалось загрузить библиотеку для работы с Excel.</p>' +
'<p>Проверьте подключение к интернету или обновите страницу.</p>' +
'</div>';
}
});
</script>
<script src="excel-editor.js"></script>
</body>
</html>