Создан utils.js — утилиты: чтение Excel, CSV, скачивание, форматирование
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
/**
|
||||
* utils.js — Вспомогательные утилиты
|
||||
* Чтение Excel, работа с CSV, скачивание файлов
|
||||
*/
|
||||
|
||||
/**
|
||||
* Прочитать Excel-файл и вернуть массив листов
|
||||
* @param {File} file - файл .xlsx/.xls
|
||||
* @returns {Promise<Array<{name: string, data: string[][]}>>}
|
||||
*/
|
||||
export async function readExcel(file) {
|
||||
const arr = await file.arrayBuffer();
|
||||
const wb = XLSX.read(arr, { type: 'array', codepage: 1251 });
|
||||
return wb.SheetNames.map(name => ({
|
||||
name,
|
||||
data: XLSX.utils.sheet_to_json(wb.Sheets[name], { header: 1, defval: '' })
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверить допустимость расширения файла
|
||||
* @param {File} file
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function validateFile(file) {
|
||||
const allowed = ['.xlsx', '.xls'];
|
||||
const ext = file.name.slice(file.name.lastIndexOf('.')).toLowerCase();
|
||||
if (!allowed.includes(ext)) {
|
||||
alert(`❌ Недопустимый тип файла: ${ext}. Разрешены: .xlsx, .xls`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразовать массив объектов в CSV-строку
|
||||
* @param {Object[]} data
|
||||
* @param {string[]} headers
|
||||
* @returns {string}
|
||||
*/
|
||||
export function arrayToCsv(data, headers) {
|
||||
const rows = data.map(r =>
|
||||
headers.map(h => `"${String(r[h] ?? '').replace(/"/g, '""')}"`).join(',')
|
||||
);
|
||||
return '\uFEFF' + headers.join(',') + '\n' + rows.join('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
* Скачать строку/Blob как файл
|
||||
* @param {string|Blob} content
|
||||
* @param {string} filename
|
||||
*/
|
||||
export function downloadFile(content, filename) {
|
||||
const blob = new Blob([content], { type: 'application/octet-stream' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Скачать Excel-файл (XLSX) из массива данных
|
||||
* @param {Object[]} data - массив строк
|
||||
* @param {string} filename
|
||||
*/
|
||||
export function downloadExcel(data, filename) {
|
||||
const wb = XLSX.utils.book_new();
|
||||
const ws = XLSX.utils.json_to_sheet(data);
|
||||
// Авто-ширина колонок
|
||||
const colWidths = Object.keys(data[0] || {}).map(key => {
|
||||
const maxLen = data.reduce((max, row) => {
|
||||
const val = String(row[key] ?? '');
|
||||
return Math.max(max, val.length);
|
||||
}, key.length);
|
||||
return { wch: Math.min(maxLen + 2, 40) };
|
||||
});
|
||||
ws['!cols'] = colWidths;
|
||||
XLSX.utils.book_append_sheet(wb, ws, 'Сверка');
|
||||
const wbOut = XLSX.write(wb, { bookType: 'xlsx', type: 'array' });
|
||||
downloadFile(wbOut, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Форматировать число в рубли (с пробелами как разделителями разрядов)
|
||||
* @param {number} num
|
||||
* @returns {string}
|
||||
*/
|
||||
export function formatMoney(num) {
|
||||
if (num === null || num === undefined || isNaN(num)) return '—';
|
||||
return num.toLocaleString('ru-RU', { minimumFractionDigits: 0, maximumFractionDigits: 0 });
|
||||
}
|
||||
Reference in New Issue
Block a user