From 2569d4c23da0a2a779ba06364b6e9b776bf71a80 Mon Sep 17 00:00:00 2001 From: host Date: Thu, 30 Jul 2026 16:51:19 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A1=D0=BE=D0=B7=D0=B4=D0=B0=D0=BD=20utils.js?= =?UTF-8?q?=20=E2=80=94=20=D1=83=D1=82=D0=B8=D0=BB=D0=B8=D1=82=D1=8B:=20?= =?UTF-8?q?=D1=87=D1=82=D0=B5=D0=BD=D0=B8=D0=B5=20Excel,=20CSV,=20=D1=81?= =?UTF-8?q?=D0=BA=D0=B0=D1=87=D0=B8=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5,=20?= =?UTF-8?q?=D1=84=D0=BE=D1=80=D0=BC=D0=B0=D1=82=D0=B8=D1=80=D0=BE=D0=B2?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D0=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils.js | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) create mode 100644 utils.js diff --git a/utils.js b/utils.js new file mode 100644 index 0000000..23fb721 --- /dev/null +++ b/utils.js @@ -0,0 +1,95 @@ +/** + * utils.js — Вспомогательные утилиты + * Чтение Excel, работа с CSV, скачивание файлов + */ + +/** + * Прочитать Excel-файл и вернуть массив листов + * @param {File} file - файл .xlsx/.xls + * @returns {Promise>} + */ +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 }); +}