+
1. Ключевое поле для поиска
+
По какому полю искать совпадения (номер телефона или лицевой счет)
+
-
+
+
+
+
-
+
-
-
-
+
2. Какие столбцы заполнять
+
Укажите, какие столбцы из какого поля брать
+
+
+
+
+
diff --git a/excel-editor.js b/excel-editor.js
index ce47050..1e6c13f 100644
--- a/excel-editor.js
+++ b/excel-editor.js
@@ -153,45 +153,84 @@ function populateFieldSelectors() {
}
});
- // Заполняем чекбоксы полей для заполнения
- const fieldsContainer = document.getElementById('fields-to-fill');
- fieldsContainer.innerHTML = '';
+ // Создаём первую строку сопоставления
+ addMappingRow();
+}
+
+function addMappingRow() {
+ const container = document.getElementById('column-mappings');
+ const mainFields = Object.keys(mainData[0] || {});
+ const templateFields = Object.keys(templateData[0] || {});
+ const rowId = 'mapping-' + Date.now();
+ const row = document.createElement('div');
+ row.id = rowId;
+ row.className = 'mapping-row';
+ row.style.cssText = 'display: grid; grid-template-columns: 1fr auto 1fr auto; gap: var(--kt-ai-space-3); align-items: center; margin-bottom: var(--kt-ai-space-2);';
+
+ // Заполняем столбец шаблона
+ let templateOptions = '';
templateFields.forEach(field => {
- const div = document.createElement('div');
- div.style.cssText = 'display: inline-flex; align-items: center; gap: var(--kt-ai-space-2); margin-right: var(--kt-ai-space-3); margin-bottom: var(--kt-ai-space-2);';
-
- const checkbox = document.createElement('input');
- checkbox.type = 'checkbox';
- checkbox.id = 'field-' + field;
- checkbox.value = field;
- checkbox.checked = true; // По умолчанию все поля выбраны
- checkbox.onchange = processMapping;
-
- const label = document.createElement('label');
- label.htmlFor = 'field-' + field;
- label.textContent = field;
- label.style.fontSize = 'var(--kt-ai-text-sm)';
-
- div.appendChild(checkbox);
- div.appendChild(label);
- fieldsContainer.appendChild(div);
+ templateOptions += '
';
});
+ // Заполняем столбец основного файла
+ let mainOptions = '';
+ mainFields.forEach(field => {
+ mainOptions += '
';
+ });
+
+ row.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ container.appendChild(row);
processMapping();
}
+function removeMappingRow(rowId) {
+ const row = document.getElementById(rowId);
+ if (row) {
+ row.remove();
+ processMapping();
+ }
+}
+
+function getColumnMappings() {
+ const mappings = [];
+ document.querySelectorAll('.template-column').forEach((select, index) => {
+ const mainSelect = document.querySelectorAll('.main-column')[index];
+ if (select && mainSelect) {
+ mappings.push({
+ templateColumn: select.value,
+ mainColumn: mainSelect.value
+ });
+ }
+ });
+ return mappings;
+}
+
function processMapping() {
const mainKeyField = document.getElementById('main-key-field').value;
const templateKeyField = document.getElementById('template-key-field').value;
if (!mainKeyField || !templateKeyField) return;
- // Собираем поля для заполнения
- const fieldsToFill = [];
- document.querySelectorAll('#fields-to-fill input[type="checkbox"]:checked').forEach(cb => {
- fieldsToFill.push(cb.value);
- });
+ // Получаем ручные сопоставления столбцов
+ const columnMappings = getColumnMappings();
// Создаём карту соответствий
const mainMap = new Map();
@@ -215,12 +254,16 @@ function processMapping() {
if (mainRow) {
matched++;
- // Заполняем пустые поля в копии
- fieldsToFill.forEach(field => {
- const isEmpty = rowCopy[field] === null || rowCopy[field] === undefined || rowCopy[field] === '';
- if (isEmpty && mainRow[field] !== null && mainRow[field] !== undefined) {
+ // Заполняем пустые поля согласно сопоставлениям
+ columnMappings.forEach(mapping => {
+ const templateCol = mapping.templateColumn;
+ const mainCol = mapping.mainColumn;
+ const isEmpty = rowCopy[templateCol] === null || rowCopy[templateCol] === undefined || String(rowCopy[templateCol]).trim() === '';
+ const hasValueInMain = mainRow[mainCol] !== null && mainRow[mainCol] !== undefined;
+
+ if (isEmpty && hasValueInMain) {
filled++;
- rowCopy[field] = mainRow[field];
+ rowCopy[templateCol] = mainRow[mainCol];
}
});
} else {
@@ -274,9 +317,18 @@ function processMapping() {
allFields.forEach(field => {
const originalValue = row.originalRow[field];
const newValue = row.templateRow[field];
- const wasEmpty = originalValue === null || originalValue === undefined || String(originalValue).trim() === '';
- const filled = wasEmpty && newValue !== null && newValue !== undefined;
- const cellStyle = filled ? 'background: var(--kt-ai-success-bg); font-weight: 600;' : '';
+
+ // Проверяем, было ли это поле заполнено из сопоставления
+ let wasFilled = false;
+ columnMappings.forEach(mapping => {
+ if (mapping.templateColumn === field) {
+ const wasEmpty = originalValue === null || originalValue === undefined || String(originalValue).trim() === '';
+ const hasValueInMain = row.mainRow && row.mainRow[mapping.mainColumn] !== null && row.mainRow[mapping.mainColumn] !== undefined;
+ wasFilled = wasEmpty && hasValueInMain;
+ }
+ });
+
+ const cellStyle = wasFilled ? 'background: var(--kt-ai-success-bg); font-weight: 600;' : '';
bodyHtml += '
' + escapeHtml(newValue !== null && newValue !== undefined ? newValue : '') + ' | ';
});
bodyHtml += '
' + (row.matched ? '✓' : '✗') + ' | ';
@@ -286,7 +338,7 @@ function processMapping() {
table.innerHTML = headerHtml + bodyHtml;
// Сохраняем результат для дальнейшей обработки
- mappedResult = { templateData, fieldsToFill, mainMap, templateKeyField };
+ mappedResult = { templateData, columnMappings, mainMap, templateKeyField };
document.getElementById('btn-process').disabled = matched === 0;
}
@@ -294,7 +346,7 @@ function processMapping() {
function processFiles() {
if (!mappedResult) return;
- const { templateData, fieldsToFill, mainMap, templateKeyField } = mappedResult;
+ const { templateData, columnMappings, mainMap, templateKeyField } = mappedResult;
// Полная обработка всех данных (без мутации!)
let totalFilled = 0;
@@ -305,13 +357,16 @@ function processFiles() {
const mainRow = mainMap.get(keyValue);
if (mainRow) {
- fieldsToFill.forEach(field => {
+ columnMappings.forEach(mapping => {
+ const templateCol = mapping.templateColumn;
+ const mainCol = mapping.mainColumn;
+
// Проверяем на пустое значение (null, undefined, пустая строка)
- const isEmpty = newRow[field] === null || newRow[field] === undefined || String(newRow[field]).trim() === '';
- const hasValueInMain = mainRow[field] !== null && mainRow[field] !== undefined;
+ const isEmpty = newRow[templateCol] === null || newRow[templateCol] === undefined || String(newRow[templateCol]).trim() === '';
+ const hasValueInMain = mainRow[mainCol] !== null && mainRow[mainCol] !== undefined;
if (isEmpty && hasValueInMain) {
- newRow[field] = mainRow[field];
+ newRow[templateCol] = mainRow[mainCol];
totalFilled++;
}
});