330 lines
14 KiB
HTML
330 lines
14 KiB
HTML
<!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>
|