Fix script paths and move assets to public/ folder for Vite build compatibility

This commit is contained in:
Marcos
2026-03-22 20:45:20 -03:00
parent 304504b758
commit 57ba9d1c5f
155 changed files with 10614 additions and 26 deletions

View File

@@ -0,0 +1,669 @@
/**
* BackupManager - Gerenciador de Backup e Restauração
* Responsável por criar, gerenciar e restaurar backups do sistema
*/
class BackupManager {
constructor() {
this.backupKey = 'acoCalcPro_backups';
this.maxBackups = 5;
this.autoBackupKey = 'acoCalcPro_auto_backup';
this.version = '1.0.0';
// Inicializar
this.initialize();
}
/**
* Inicializa o gerenciador de backup
*/
initialize() {
try {
// Limpar backups antigos se necessário
this.cleanupOldBackups();
console.log('🔄 BackupManager inicializado com sucesso');
} catch (error) {
console.error('❌ Erro ao inicializar BackupManager:', error);
}
}
/**
* Cria um backup completo do sistema
* @param {string} description - Descrição opcional do backup
* @returns {Object} Backup criado
*/
async createBackup(description = 'Backup manual') {
try {
console.log('📦 Criando backup do sistema...');
// Coletar todos os dados necessários
const now = Date.now();
const backupData = {
id: `bkp-${now}`,
timestamp: Number(now),
createdAt: Number(now),
type: description && description.toLowerCase().includes('auto') ? 'automatic' : 'manual',
version: this.version,
description: description,
data: {
// Configurações administrativas
adminConfig: window.adminConfigManager ? window.adminConfigManager.getConfig() : null,
// Preferências do usuário
userPreferences: this.getUserPreferences(),
// Cache stats do DataManager
cacheStats: window.dataManager ? window.dataManager.getCacheStats() : null,
// Estado da aplicação
appState: this.getAppState(),
// Dados do State Manager
stateData: window.stateManager ? window.stateManager.getAllState() : null,
// Dados do Cache Manager
cacheData: window.cacheManager ? await this.getCacheData() : null
}
};
const sizeBytes = Number(JSON.stringify(backupData).length);
backupData.sizeBytes = sizeBytes;
backupData.size = this.formatBytes(sizeBytes);
// Obter backups existentes
const backups = this.getBackups();
// Adicionar novo backup no início
backups.unshift(backupData);
// Limitar número de backups
if (backups.length > this.maxBackups) {
const removed = backups.splice(this.maxBackups);
console.log(`🗑️ ${removed.length} backup(s) antigo(s) removido(s)`);
}
// Salvar no localStorage
localStorage.setItem(this.backupKey, JSON.stringify(backups));
// Atualizar último backup nas configurações
if (window.adminConfigManager) {
window.adminConfigManager.updateConfig('lastBackup', backupData.timestamp);
}
console.log('✅ Backup criado com sucesso:', new Date(backupData.timestamp).toLocaleString());
// Notificar sucesso
if (window.toastManager) {
window.toastManager.success('Backup criado com sucesso!');
}
return backupData;
} catch (error) {
console.error('❌ Erro ao criar backup:', error);
// Notificar erro
if (window.toastManager) {
window.toastManager.error('Erro ao criar backup: ' + error.message);
}
throw new Error('Falha ao criar backup: ' + error.message);
}
}
/**
* Obtém todos os backups salvos
* @returns {Array} Lista de backups
*/
getBackups() {
try {
const saved = localStorage.getItem(this.backupKey);
if (saved) {
const raw = JSON.parse(saved);
if (Array.isArray(raw)) {
const normalized = raw.map(b => {
const tsRaw = (b && b.timestamp != null) ? b.timestamp : Date.now();
let ts;
if (typeof tsRaw === 'number') {
ts = tsRaw;
} else if (typeof tsRaw === 'string') {
const parsed = Date.parse(tsRaw);
ts = isNaN(parsed) ? Number(tsRaw) : parsed;
} else {
ts = Date.now();
}
if (isNaN(ts)) ts = Date.now();
const id = (b && b.id) ? b.id : `bkp-${ts}`;
const createdAtRaw = (b && b.createdAt != null) ? b.createdAt : ts;
let createdAt;
if (typeof createdAtRaw === 'number') {
createdAt = createdAtRaw;
} else if (typeof createdAtRaw === 'string') {
const parsedCA = Date.parse(createdAtRaw);
createdAt = isNaN(parsedCA) ? Number(createdAtRaw) : parsedCA;
} else {
createdAt = ts;
}
if (isNaN(createdAt)) createdAt = ts;
const type = b.type || 'manual';
const version = b.version || this.version;
const description = b.description || '';
const data = b.data || {};
let sizeBytes = Number(b.sizeBytes);
if (isNaN(sizeBytes) || !sizeBytes) {
sizeBytes = JSON.stringify(b).length;
}
const size = b.size || this.formatBytes(sizeBytes);
return { id, timestamp: ts, createdAt, type, version, description, data, sizeBytes, size };
});
return normalized.filter(backup => this.isValidBackup(backup));
}
}
} catch (error) {
console.warn('⚠️ Erro ao carregar backups:', error);
}
return [];
}
/**
* Restaura um backup específico
* @param {Object|string} backup - Backup a restaurar ou timestamp
* @returns {boolean} Sucesso da restauração
*/
async restoreBackup(backup) {
try {
let backupToRestore;
// Se for timestamp, encontrar o backup correspondente
if (typeof backup === 'string' || typeof backup === 'number') {
const backups = this.getBackups();
if (typeof backup === 'string' && isNaN(parseInt(backup))) {
backupToRestore = backups.find(b => b.id === backup);
} else {
const timestamp = typeof backup === 'string' ? parseInt(backup) : backup;
backupToRestore = backups.find(b => b.timestamp === timestamp);
}
if (!backupToRestore) {
throw new Error('Backup não encontrado');
}
} else {
backupToRestore = backup;
}
console.log('📤 Restaurando backup de:', new Date(backupToRestore.createdAt || backupToRestore.timestamp).toLocaleString());
// Confirmar com usuário se for restauração manual
const isConfirmed = await this.confirmRestoration(backupToRestore);
if (!isConfirmed) {
console.log('❌ Restauração cancelada pelo usuário');
return false;
}
// Criar backup antes de restaurar (precaução)
await this.createBackup('Backup pré-restauração');
// Restaurar configurações administrativas
if (backupToRestore.data.adminConfig && window.adminConfigManager) {
window.adminConfigManager.saveConfig(backupToRestore.data.adminConfig);
console.log('✅ Configurações administrativas restauradas');
}
// Restaurar preferências do usuário
if (backupToRestore.data.userPreferences) {
this.setUserPreferences(backupToRestore.data.userPreferences);
console.log('✅ Preferências do usuário restauradas');
}
// Restaurar estado da aplicação
if (backupToRestore.data.appState) {
this.setAppState(backupToRestore.data.appState);
console.log('✅ Estado da aplicação restaurado');
}
// Restaurar dados do State Manager
if (backupToRestore.data.stateData && window.stateManager) {
window.stateManager.setAllState(backupToRestore.data.stateData);
console.log('✅ Dados do State Manager restaurados');
}
// Notificar sucesso
if (window.toastManager) {
window.toastManager.success('Backup restaurado com sucesso!');
}
console.log('✅ Backup restaurado com sucesso');
// Disparar evento de restauração
this.notifyRestorationComplete(backupToRestore);
return true;
} catch (error) {
console.error('❌ Erro ao restaurar backup:', error);
// Notificar erro
if (window.toastManager) {
window.toastManager.error('Erro ao restaurar backup: ' + error.message);
}
throw new Error('Falha ao restaurar backup: ' + error.message);
}
}
/**
* Remove um backup específico
* @param {string|number} timestamp - Timestamp do backup a remover
* @returns {boolean} Sucesso da remoção
*/
removeBackup(idOrTimestamp) {
try {
const backups = this.getBackups();
let filteredBackups;
if (typeof idOrTimestamp === 'string' && isNaN(parseInt(idOrTimestamp))) {
filteredBackups = backups.filter(backup => backup.id !== idOrTimestamp);
} else {
const timestampNum = typeof idOrTimestamp === 'string' ? parseInt(idOrTimestamp) : idOrTimestamp;
filteredBackups = backups.filter(backup => backup.timestamp !== timestampNum);
}
if (filteredBackups.length === backups.length) {
throw new Error('Backup não encontrado');
}
localStorage.setItem(this.backupKey, JSON.stringify(filteredBackups));
console.log('🗑️ Backup removido');
if (window.toastManager) {
window.toastManager.info('Backup removido com sucesso');
}
return true;
} catch (error) {
console.error('❌ Erro ao remover backup:', error);
throw new Error('Falha ao remover backup: ' + error.message);
}
}
/**
* Limpa todos os backups
* @returns {boolean} Sucesso da limpeza
*/
clearAllBackups() {
try {
localStorage.removeItem(this.backupKey);
console.log('🗑️ Todos os backups foram removidos');
if (window.toastManager) {
window.toastManager.info('Todos os backups foram removidos');
}
return true;
} catch (error) {
console.error('❌ Erro ao limpar backups:', error);
throw new Error('Falha ao limpar backups: ' + error.message);
}
}
/**
* Exporta um backup como arquivo JSON
* @param {Object|string} backup - Backup a exportar ou timestamp
*/
exportBackup(backup) {
try {
let backupToExport;
// Se for timestamp, encontrar o backup correspondente
if (typeof backup === 'string' || typeof backup === 'number') {
const timestamp = typeof backup === 'string' ? parseInt(backup) : backup;
const backups = this.getBackups();
backupToExport = backups.find(b => b.timestamp === timestamp);
if (!backupToExport) {
throw new Error('Backup não encontrado');
}
} else {
backupToExport = backup;
}
const jsonString = JSON.stringify(backupToExport, null, 2);
const blob = new Blob([jsonString], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `steelbase-backup-${backupToExport.timestamp}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
console.log('📤 Backup exportado com sucesso');
if (window.toastManager) {
window.toastManager.success('Backup exportado com sucesso!');
}
} catch (error) {
console.error('❌ Erro ao exportar backup:', error);
if (window.toastManager) {
window.toastManager.error('Erro ao exportar backup: ' + error.message);
}
throw new Error('Falha ao exportar backup: ' + error.message);
}
}
/**
* Importa um backup de arquivo JSON
* @param {File} file - Arquivo JSON a importar
* @returns {Object} Backup importado
*/
async importBackup(file) {
try {
console.log('📥 Importando backup de arquivo...');
const text = await file.text();
const backup = JSON.parse(text);
if (!this.isValidBackup(backup)) {
throw new Error('Arquivo de backup inválido');
}
// Adicionar aos backups existentes
const backups = this.getBackups();
backups.unshift(backup);
// Limitar número de backups
if (backups.length > this.maxBackups) {
backups.splice(this.maxBackups);
}
localStorage.setItem(this.backupKey, JSON.stringify(backups));
console.log('✅ Backup importado com sucesso');
if (window.toastManager) {
window.toastManager.success('Backup importado com sucesso!');
}
return backup;
} catch (error) {
console.error('❌ Erro ao importar backup:', error);
if (window.toastManager) {
window.toastManager.error('Erro ao importar backup: ' + error.message);
}
throw new Error('Falha ao importar backup: ' + error.message);
}
}
/**
* Configura backup automático
* @param {boolean} enabled - Se deve estar ativado
* @param {number} intervalHours - Intervalo em horas
*/
setupAutoBackup(enabled, intervalHours = 24) {
try {
const autoBackupConfig = {
enabled: enabled,
intervalHours: intervalHours,
lastBackup: null
};
localStorage.setItem(this.autoBackupKey, JSON.stringify(autoBackupConfig));
if (enabled) {
console.log(`🔄 Backup automático configurado: a cada ${intervalHours} horas`);
this.startAutoBackupTimer();
} else {
console.log('⏹️ Backup automático desativado');
this.stopAutoBackupTimer();
}
} catch (error) {
console.error('❌ Erro ao configurar backup automático:', error);
}
}
/**
* Inicia o timer de backup automático
*/
startAutoBackupTimer() {
// Implementar timer de backup automático
// Isso seria chamado na inicialização da aplicação
console.log('⏰ Timer de backup automático iniciado');
}
/**
* Para o timer de backup automático
*/
stopAutoBackupTimer() {
console.log('⏹️ Timer de backup automático parado');
}
/**
* Valida se um backup é válido
* @param {Object} backup - Backup a validar
* @returns {boolean} Se é válido
*/
isValidBackup(backup) {
if (!backup || typeof backup !== 'object') {
return false;
}
// Verificar campos obrigatórios
const requiredFields = ['timestamp', 'version', 'data'];
for (const field of requiredFields) {
if (!backup[field]) {
console.warn(`⚠️ Campo obrigatório ausente no backup: ${field}`);
return false;
}
}
// Verificar estrutura de dados
if (typeof backup.timestamp !== 'number' ||
typeof backup.version !== 'string' ||
typeof backup.data !== 'object') {
return false;
}
return true;
}
/**
* Limpa backups antigos (mantém apenas os mais recentes)
*/
cleanupOldBackups() {
try {
const backups = this.getBackups();
if (backups.length > this.maxBackups) {
const keptBackups = backups.slice(0, this.maxBackups);
localStorage.setItem(this.backupKey, JSON.stringify(keptBackups));
console.log(`🗑️ ${backups.length - keptBackups.length} backup(s) antigo(s) removido(s)`);
}
} catch (error) {
console.warn('⚠️ Erro ao limpar backups antigos:', error);
}
}
/**
* Obtém preferências do usuário
* @returns {Object} Preferências
*/
getUserPreferences() {
try {
const saved = localStorage.getItem('acoCalcPreferences');
return saved ? JSON.parse(saved) : null;
} catch (error) {
console.warn('⚠️ Erro ao obter preferências do usuário:', error);
return null;
}
}
/**
* Define preferências do usuário
* @param {Object} preferences - Preferências a definir
*/
setUserPreferences(preferences) {
try {
localStorage.setItem('acoCalcPreferences', JSON.stringify(preferences));
} catch (error) {
console.warn('⚠️ Erro ao definir preferências do usuário:', error);
}
}
/**
* Obtém estado da aplicação
* @returns {Object} Estado da aplicação
*/
getAppState() {
try {
// Coletar estado relevante da aplicação
const state = {
currentSection: window.currentSection || null,
lastUpdate: window.lastUpdate || null,
userSession: window.userSession || null
};
return state;
} catch (error) {
console.warn('⚠️ Erro ao obter estado da aplicação:', error);
return {};
}
}
/**
* Define estado da aplicação
* @param {Object} state - Estado a definir
*/
setAppState(state) {
try {
if (state.currentSection) window.currentSection = state.currentSection;
if (state.lastUpdate) window.lastUpdate = state.lastUpdate;
if (state.userSession) window.userSession = state.userSession;
} catch (error) {
console.warn('⚠️ Erro ao definir estado da aplicação:', error);
}
}
/**
* Obtém dados do cache
* @returns {Promise<Object>} Dados do cache
*/
async getCacheData() {
try {
if (!window.cacheManager) {
return null;
}
// Obter dados relevantes do cache
const cacheData = {
metadata: window.cacheManager.getMetadata ? window.cacheManager.getMetadata() : null,
stats: window.cacheManager.getStats ? window.cacheManager.getStats() : null
};
return cacheData;
} catch (error) {
console.warn('⚠️ Erro ao obter dados do cache:', error);
return null;
}
}
/**
* Confirma restauração com o usuário
* @param {Object} backup - Backup a restaurar
* @returns {Promise<boolean>} Confirmação
*/
async confirmRestoration(backup) {
// Em ambiente real, isso seria um modal/dialog
// Por enquanto, retorna true para testes
return new Promise((resolve) => {
console.log(`🔄 Confirmando restauração do backup: ${new Date(backup.timestamp).toLocaleString()}`);
// Simular confirmação após 1 segundo
setTimeout(() => {
resolve(true);
}, 1000);
});
}
/**
* Notifica conclusão da restauração
* @param {Object} backup - Backup restaurado
*/
notifyRestorationComplete(backup) {
const event = new CustomEvent('backupRestored', {
detail: { backup: backup },
bubbles: true
});
document.dispatchEvent(event);
}
/**
* Obtém estatísticas dos backups
* @returns {Object} Estatísticas
*/
getStats() {
const backups = this.getBackups();
const totalSize = backups.reduce((total, backup) => {
return total + JSON.stringify(backup).length;
}, 0);
return {
totalBackups: backups.length,
oldestBackup: backups.length > 0 ? backups[backups.length - 1].timestamp : null,
newestBackup: backups.length > 0 ? backups[0].timestamp : null,
totalSize: totalSize,
maxBackups: this.maxBackups
};
}
/**
* Retorna um backup específico por id ou timestamp
* @param {string|number} idOrTimestamp
* @returns {Object|null}
*/
getBackup(idOrTimestamp) {
const backups = this.getBackups();
if (typeof idOrTimestamp === 'string' && isNaN(parseInt(idOrTimestamp))) {
return backups.find(b => b.id === idOrTimestamp) || null;
}
const ts = typeof idOrTimestamp === 'string' ? Number(parseInt(idOrTimestamp)) : Number(idOrTimestamp);
return backups.find(b => b.timestamp === ts) || null;
}
/**
* Formata bytes em string legível (KB, MB, GB)
* @param {number} bytes
* @returns {string}
*/
formatBytes(bytes) {
if (!bytes || bytes < 1024) return `${bytes || 0} B`;
const units = ['KB', 'MB', 'GB'];
let value = bytes / 1024;
let idx = 0;
while (value >= 1024 && idx < units.length - 1) {
value /= 1024;
idx++;
}
return `${value.toFixed(1)} ${units[idx]}`;
}
}
// Criar instância global
window.backupManager = new BackupManager();
console.log('🔄 BackupManager inicializado com sucesso');