Te voy a guiar paso a paso para convertir tu HTML en un software instalable, con la carpeta exactamente en C:\Users\migue\mysalon
Paso 1: Preparar la carpeta y archivos
- Crear la carpeta:
- Ve a
C:\Users\migue\ - Crea una nueva carpeta llamada
mysalon(exactamente así)
- Dentro de
C:\Users\migue\mysalon\, crea estos archivos:
Archivo 1: index.html (pega TODO tu código HTML aquí)
Archivo 2: package.json
{
"name": "mysalon",
"version": "1.0.0",
"description": "Sistema de gestión para peluquería MySalon",
"main": "main.js",
"scripts": {
"start": "electron .",
"build": "electron-builder"
},
"author": "migue",
"license": "MIT",
"devDependencies": {
"electron": "^22.0.0",
"electron-builder": "^23.0.0"
},
"build": {
"appId": "com.migue.mysalon",
"productName": "MySalon",
"directories": {
"output": "dist"
},
"files": [
"**/*",
"!dist",
"!node_modules"
],
"win": {
"target": "nsis",
"icon": "icon.ico"
},
"nsis": {
"oneClick": false,
"allowToChangeInstallationDirectory": true,
"createDesktopShortcut": true,
"createStartMenuShortcut": true
}
}
}
Archivo 3: main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const mainWindow = new BrowserWindow({
width: 1400,
height: 900,
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
},
icon: path.join(__dirname, 'icon.ico'),
title: 'MySalon - Sistema de Gestión'
});
mainWindow.loadFile('index.html');
// Opcional: quita el comentario de la siguiente línea para ver las herramientas de desarrollo
// mainWindow.webContents.openDevTools();
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
Paso 2: Instalar Node.js (si no lo tienes)
- Ve a nodejs.org
- Descarga la versión LTS (la recomendada)
- Instálalo con todos los valores por defecto
Paso 3: Abrir la terminal y ejecutar comandos
- Abrir Symbolo del sistema:
- Presiona
Windows + R - Escribe
cmdy presiona Enter
- Navegar a la carpeta:
cd C:\Users\migue\mysalon
- Instalar Electron:
npm install
Paso 4: Probar la aplicación
npm start
Si todo funciona correctamente, debería abrirse una ventana con tu aplicación MySalon.
Paso 5: Crear el instalador
npm run build
Paso 6: Encontrar el instalador
- Después del paso anterior, se creará una carpeta
distdentro deC:\Users\migue\mysalon\ - En
C:\Users\migue\mysalon\dist\encontrarás:
MySalon Setup 1.0.0.exe– El instaladorwin-unpacked– La versión portable (no necesita instalación)
Estructura final de tu carpeta:
C:\Users\migue\mysalon\
├── index.html (tu código)
├── package.json (configuración)
├── main.js (archivo principal)
├── node_modules\ (se crea automáticamente)
├── dist\ (se crea después de build)
│ ├── MySalon Setup 1.0.0.exe
│ └── win-unpacked\
└── package-lock.json (se crea automáticamente)
Para distribuir tu software:
- Opción Instalador: Entrega
MySalon Setup 1.0.0.exe - Opción Portable: Comprime la carpeta
win-unpackedy entrégala como ZIP
Comandos rápidos de referencia:
cd C:\Users\migue\mysalon
npm install # Solo la primera vez
npm start # Para probar
npm run build # Para crear instalador
Solución de problemas comunes:
- Error de permisos: Ejecuta el Symbolo del sistema como Administrador
- Error de npm: Asegúrate de que Node.js esté instalado correctamente
- La aplicación no se abre: Verifica que todos los archivos estén en la carpeta correcta
¡Excelente pregunta! Esta es una diferencia CRUCIAL.
📊 RESPUESTA CORTA:
NO, el portable NO guarda la información automáticamente entre sesiones (con la configuración actual).
🔍 EXPLICACIÓN DETALLADA:
PROBLEMA ACTUAL:
Tu código HTML usa variables en memoria (let employees = [...], let services = [...]), que:
- Se guardan SOLO mientras la aplicación esté abierta
- Se PIERDEN cuando cierras el programa
- No se guardan en archivos
DIFERENCIAS EN LA PRÁCTICA:
| Escenario | Instalador | Portable |
|---|---|---|
| Agregas empleados | ❌ Se pierden al cerrar | ❌ Se pierden al cerrar |
| Agregas servicios | ❌ Se pierden al cerrar | ❌ Se pierden al cerrar |
| Programas citas | ❌ Se pierden al cerrar | ❌ Se pierden al cerrar |
| Cierras y reabres | Todo vacío | Todo vacío |
🛠 SOLUCIÓN NECESARIA:
Necesitas modificar el código para que guarde los datos en archivos. Te muestro cómo:
Paso 1: Modificar el código para guardar datos
En tu archivo index.html, busca esta línea:
// Sample data
let roles = ["Peluquero/a", "Manicurista", "Estilista", "Colorista"];
Y REEMPLÁZALA con este código:
// Sistema de guardado de datos
const fs = require('fs');
const path = require('path');
// Rutas de archivos de datos
const dataDir = path.join(__dirname, 'data');
const employeesFile = path.join(dataDir, 'employees.json');
const servicesFile = path.join(dataDir, 'services.json');
const rolesFile = path.join(dataDir, 'roles.json');
const appointmentsFile = path.join(dataDir, 'appointments.json');
const settingsFile = path.join(dataDir, 'settings.json');
// Crear carpeta de datos si no existe
if (!fs.existsSync(dataDir)) {
fs.mkdirSync(dataDir);
}
// Función para cargar datos
function loadData(file, defaultValue = []) {
try {
if (fs.existsSync(file)) {
const data = fs.readFileSync(file, 'utf8');
return JSON.parse(data);
}
} catch (error) {
console.error('Error loading data:', error);
}
return defaultValue;
}
// Función para guardar datos
function saveData(file, data) {
try {
fs.writeFileSync(file, JSON.stringify(data, null, 2));
return true;
} catch (error) {
console.error('Error saving data:', error);
return false;
}
}
// Cargar datos existentes o usar valores por defecto
let roles = loadData(rolesFile, ["Peluquero/a", "Manicurista", "Estilista", "Colorista"]);
let employees = loadData(employeesFile, [
{
id: 1,
name: "María González",
role: "Peluquero/a",
phone: "+1 234 567 890",
email: "maria@beautystyle.com",
photo: null,
services: ["Corte de cabello", "Tinte", "Peinado"],
earnings: [
{ date: "2023-05-15", time: "10:30", service: "Corte de cabello", amount: 25 },
{ date: "2023-05-15", time: "14:00", service: "Tinte", amount: 50 }
],
attendance: [
{ date: "2023-05-15", checkIn: "09:00", checkOut: "18:00" }
],
isClockedIn: false,
workingHours: {
start: "09:00",
end: "18:00",
breaks: [
{ start: "13:00", end: "14:00" }
]
},
daysOff: []
}
]);
let services = loadData(servicesFile, [
{ id: 1, name: "Corte de cabello", duration: 30, color: "#8a6d3b" },
{ id: 2, name: "Tinte", duration: 60, color: "#d4b483" },
{ id: 3, name: "Peinado", duration: 45, color: "#f9f2e8" },
{ id: 4, name: "Manicure", duration: 30, color: "#e74c3c" },
{ id: 5, name: "Pedicure", duration: 45, color: "#3498db" }
]);
let appointments = loadData(appointmentsFile, []);
let salonSettings = loadData(settingsFile, {
name: "MySalon",
address: "Calle Principal 123, Ciudad",
phone: "+1 234 567 890"
});
// Función para guardar todos los datos
function saveAllData() {
saveData(employeesFile, employees);
saveData(servicesFile, services);
saveData(rolesFile, roles);
saveData(appointmentsFile, appointments);
saveData(settingsFile, salonSettings);
}
// Guardar datos automáticamente cada 30 segundos
setInterval(saveAllData, 30000);
// También guardar cuando se cierre la aplicación
window.addEventListener('beforeunload', saveAllData);
Paso 2: Modificar las funciones que cambian datos
Cada vez que modifiques datos, añade saveAllData():
Ejemplo en la función de agregar empleado:
// Busca esta función y añádele la última línea:
employeeForm.addEventListener('submit', function(e) {
e.preventDefault();
// ... todo tu código actual ...
employees.push(newEmployee);
updateEmployeesGrid();
updateEmployeesTable();
updateReportEmployeeSelect();
updateCalendarEmployeeFilter();
employeeForm.reset();
// AÑADE ESTA LÍNEA:
saveAllData();
alert('Empleado agregado exitosamente');
});
Haz lo mismo en estas funciones:
addServiceBtn.addEventListener('click', ...)– añadesaveAllData()deleteService()– añadesaveAllData()deleteEmployee()– añadesaveAllData()settingsForm.addEventListener('submit', ...)– añadesaveAllData()saveAppointment()– añadesaveAllData()deleteAppointment()– añadesaveAllData()addRoleBtn.addEventListener('click', ...)– añadesaveAllData()deleteRole()– añadesaveAllData()
📁 ESTRUCTURA FINAL CON DATOS:
C:\Users\migue\mysalon\
├── index.html
├── package.json
├── main.js
├── data\ (← NUEVA CARPETA)
│ ├── employees.json
│ ├── services.json
│ ├── roles.json
│ ├── appointments.json
│ └── settings.json
├── dist\
│ ├── MySalon Setup.exe
│ └── win-unpacked\
│ ├── MySalon.exe
│ └── data\ (← LOS DATOS VAN AQUÍ TAMBIÉN)
✅ RESULTADO FINAL:
Con esta modificación:
- ✅ PORTABLE: Guarda datos en la carpeta
datajunto al ejecutable - ✅ INSTALADOR: Guarda datos en la carpeta de instalación
- ✅ Los datos PERSISTEN entre sesiones
- ✅ Funciona igual en ambas versiones
Descubre más desde Clasenet
Suscríbete y recibe las últimas entradas en tu correo electrónico.


