const { app, BrowserWindow, protocol, ipcMain, globalShortcut } = require('electron'); const path = require('path'); require('dotenv').config({path: path.join(__dirname, 'config.env')}) const isDev = require('electron-is-dev'); const fs = require('fs'); const axios = require('axios'); const { logger } = require('../../backend/src/config/logger'); const config = require('../src/config.json') const { print } = require('pdf-to-printer'); protocol.registerSchemesAsPrivileged([ { scheme: 'app', privileges: { secure: true, standard: true, supportFetchAPI: true, corsEnabled: true } } ]); if (!Promise.withResolvers) { Promise.withResolvers = function () { let resolve, reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; }; } let mainWindow; let appConfig = {}; const configPath = isDev ? path.join(__dirname, '../src/config.json') : path.join(process.resourcesPath, 'config.json'); try { logger.info(`[Config] Trying to load config from: ${configPath}`); if (fs.existsSync(configPath)) { appConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8')); logger.info('[Config] External config loaded successfully:', appConfig); } else { logger.warn('[Config] External config file not found. Using default values.'); } } catch (error) { logger.error('[Config] Could not load external config file:', error); } global.allowClose = false; function createWindow() { const preloadPath = path.join(__dirname, 'preload.js'); try { fs.accessSync(preloadPath); logger.debug(`[DEBUG] Preload script found at: ${preloadPath}`); } catch (e) { logger.error(`[FATAL] Preload script not found at: ${preloadPath}`); app.quit(); return; } mainWindow = new BrowserWindow({ kiosk: true, titleBarStyle: 'hidden', alwaysOnTop: false, webPreferences: { preload: preloadPath, contextIsolation: true, nodeIntegration: false }, }); mainWindow.loadURL( isDev ? `${config.frontUrl}` : `file://${path.join(__dirname, '../build/index.html')}` ); mainWindow.on('close', (e) => { if (!global.allowClose) { e.preventDefault(); } }); mainWindow.on('minimize', (e) => { e.preventDefault(); }); } // ============================================ // 📄 ПЕЧАТЬ PDF ЧЕРЕЗ pdf-to-printer // ============================================ ipcMain.handle('print-pdf', async (event, data = {}) => { let tempFile = null; try { if (!data.pdfUrl) { throw new Error('URL файла PDF не передан'); } const cleanUrl = data.pdfUrl.split('#')[0]; logger.info('[PRINT] Загрузка PDF:', cleanUrl); // ✅ Скачиваем PDF const response = await axios.get(cleanUrl, { responseType: 'arraybuffer', timeout: 30000 }); const pdfBuffer = Buffer.from(response.data); logger.info('[PRINT] Размер PDF:', pdfBuffer.length, 'байт'); if (pdfBuffer.length < 100) { throw new Error('PDF слишком маленький или пустой'); } // ✅ Сохраняем во временный файл const tempDir = app.getPath('temp'); tempFile = path.join(tempDir, `print_${Date.now()}.pdf`); fs.writeFileSync(tempFile, pdfBuffer); logger.info('[PRINT] Временный файл создан:', tempFile); // ✅ ПЕЧАТАЕМ ЧЕРЕЗ pdf-to-printer const printerName = 'GP-80250 Series'; logger.info('[PRINT] Отправляем на печать через pdf-to-printer:', printerName); // ✅ Опции печати const options = { printer: printerName, // scale: 'fit', // Масштабирование // paperSize: 'A4', // landscape: false, // copies: 1, // silent: true // Тихая печать }; const result = await print(tempFile, options); logger.info('[PRINT] Результат печати:', result); // ✅ Удаляем временный файл try { if (tempFile && fs.existsSync(tempFile)) { fs.unlinkSync(tempFile); logger.info('[PRINT] Временный файл удален'); } } catch (e) {} logger.info('[PRINT] ✅ Документ отправлен на печать'); return true; } catch (error) { logger.error('[PRINT] ❌ Ошибка:', error.message); try { if (tempFile && fs.existsSync(tempFile)) { fs.unlinkSync(tempFile); } } catch (e) {} throw error; } }); // ============================================ // 📄 ПОЛУЧЕНИЕ СПИСКА ПРИНТЕРОВ // ============================================ ipcMain.handle('get-printers', async () => { return [ { name: 'GP-80250 Series', displayName: 'GP-80250 Series', isDefault: true, status: 'ready' } ]; }); // ============================================ // 🚀 ЗАПУСК // ============================================ app.whenReady().then(() => { createWindow(); global.allowMinimize = false; globalShortcut.register('Control+Alt+Backspace', () => { global.allowMinimize = true; if (mainWindow) mainWindow.minimize(); }); mainWindow.on('minimize', function (event) { if (global.allowMinimize) { global.allowMinimize = false; return; } event.preventDefault(); setTimeout(() => { if (mainWindow.isMinimized()) { mainWindow.restore(); mainWindow.focus(); } }, 10); }); globalShortcut.register('Control+Alt+Enter', () => { global.allowClose = true; app.quit(); }); globalShortcut.register('F11', () => {}); }); app.on('window-all-closed', () => { if (process.platform !== 'darwin') { app.quit(); } }); app.on('activate', () => { if (mainWindow === null) { createWindow(); } }); app.on('will-quit', () => { globalShortcut.unregisterAll(); }); ipcMain.handle('get-app-config', async (event) => { return appConfig; });