feat: 完善外部资源备用机制和日志系统
- 在header.php中添加用户角色检测,传递给前端JavaScript - 更新Open Sans字体CSS文件,支持本地woff2字体文件备用 - 修改footer.php中MathJax 3/2和KaTeX加载机制,添加onerror备用处理 - 优化resource-loader.js日志系统,使用ArgonLogger替代console.log - 仅管理员用户显示控制台日志,普通用户和游客不显示调试信息 - 完善资源加载错误处理,统一使用ArgonLogger记录警告信息
This commit is contained in:
266
assets/vendor/external/logger.js
vendored
Normal file
266
assets/vendor/external/logger.js
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
/* Argon 内部日志系统 - 仅管理员可见 */
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
window.ArgonLogger = {
|
||||
// 配置
|
||||
config: {
|
||||
maxLogs: 1000,
|
||||
enableConsole: false, // 默认关闭控制台输出
|
||||
enableStorage: true,
|
||||
storageKey: 'argon_internal_logs'
|
||||
},
|
||||
|
||||
// 日志级别
|
||||
levels: {
|
||||
DEBUG: 0,
|
||||
INFO: 1,
|
||||
WARN: 2,
|
||||
ERROR: 3,
|
||||
CRITICAL: 4
|
||||
},
|
||||
|
||||
// 内部日志存储
|
||||
logs: [],
|
||||
|
||||
// 初始化
|
||||
init: function() {
|
||||
this.checkAdminStatus();
|
||||
this.loadStoredLogs();
|
||||
this.bindEvents();
|
||||
},
|
||||
|
||||
// 检查管理员状态
|
||||
checkAdminStatus: function() {
|
||||
// 检查是否为管理员(通过PHP传递的全局变量)
|
||||
if (typeof window.argonUserRole !== 'undefined' && window.argonUserRole === 'administrator') {
|
||||
this.config.enableConsole = true;
|
||||
this.log('管理员模式:控制台日志已启用', 'INFO');
|
||||
} else {
|
||||
this.config.enableConsole = false;
|
||||
}
|
||||
},
|
||||
|
||||
// 加载存储的日志
|
||||
loadStoredLogs: function() {
|
||||
if (this.config.enableStorage && localStorage) {
|
||||
try {
|
||||
var stored = localStorage.getItem(this.config.storageKey);
|
||||
if (stored) {
|
||||
this.logs = JSON.parse(stored);
|
||||
}
|
||||
} catch (e) {
|
||||
// 静默处理存储错误
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 保存日志到存储
|
||||
saveLogsToStorage: function() {
|
||||
if (this.config.enableStorage && localStorage) {
|
||||
try {
|
||||
// 只保留最新的日志
|
||||
var logsToSave = this.logs.slice(-this.config.maxLogs);
|
||||
localStorage.setItem(this.config.storageKey, JSON.stringify(logsToSave));
|
||||
} catch (e) {
|
||||
// 静默处理存储错误
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// 记录日志
|
||||
log: function(message, level, data) {
|
||||
level = level || 'INFO';
|
||||
var timestamp = new Date().toISOString();
|
||||
var logEntry = {
|
||||
timestamp: timestamp,
|
||||
level: level,
|
||||
message: message,
|
||||
data: data || null,
|
||||
url: window.location.href,
|
||||
userAgent: navigator.userAgent.substring(0, 100) // 截取前100字符
|
||||
};
|
||||
|
||||
// 添加到内部日志
|
||||
this.logs.push(logEntry);
|
||||
|
||||
// 限制日志数量
|
||||
if (this.logs.length > this.config.maxLogs) {
|
||||
this.logs = this.logs.slice(-this.config.maxLogs);
|
||||
}
|
||||
|
||||
// 保存到存储
|
||||
this.saveLogsToStorage();
|
||||
|
||||
// 仅管理员显示控制台日志
|
||||
if (this.config.enableConsole) {
|
||||
var consoleMethod = this.getConsoleMethod(level);
|
||||
consoleMethod('[Argon] ' + message, data || '');
|
||||
}
|
||||
|
||||
// 关键错误需要特殊处理
|
||||
if (level === 'CRITICAL') {
|
||||
this.handleCriticalError(logEntry);
|
||||
}
|
||||
},
|
||||
|
||||
// 获取对应的控制台方法
|
||||
getConsoleMethod: function(level) {
|
||||
switch (level) {
|
||||
case 'DEBUG':
|
||||
return console.debug || console.log;
|
||||
case 'INFO':
|
||||
return console.info || console.log;
|
||||
case 'WARN':
|
||||
return console.warn || console.log;
|
||||
case 'ERROR':
|
||||
case 'CRITICAL':
|
||||
return console.error || console.log;
|
||||
default:
|
||||
return console.log;
|
||||
}
|
||||
},
|
||||
|
||||
// 处理关键错误
|
||||
handleCriticalError: function(logEntry) {
|
||||
// 关键错误需要通知用户联系站长
|
||||
if (this.config.enableConsole) {
|
||||
console.error('发生关键错误,请联系站长处理:', logEntry.message);
|
||||
}
|
||||
|
||||
// 可以在这里添加错误上报逻辑
|
||||
this.reportCriticalError(logEntry);
|
||||
},
|
||||
|
||||
// 上报关键错误
|
||||
reportCriticalError: function(logEntry) {
|
||||
// 这里可以实现错误上报到服务器的逻辑
|
||||
// 暂时只记录到本地存储
|
||||
try {
|
||||
var criticalLogs = JSON.parse(localStorage.getItem('argon_critical_errors') || '[]');
|
||||
criticalLogs.push(logEntry);
|
||||
localStorage.setItem('argon_critical_errors', JSON.stringify(criticalLogs.slice(-50)));
|
||||
} catch (e) {
|
||||
// 静默处理
|
||||
}
|
||||
},
|
||||
|
||||
// 获取日志(仅管理员)
|
||||
getLogs: function(level, limit) {
|
||||
if (!this.config.enableConsole) {
|
||||
return []; // 非管理员返回空数组
|
||||
}
|
||||
|
||||
var filteredLogs = this.logs;
|
||||
|
||||
if (level) {
|
||||
filteredLogs = this.logs.filter(function(log) {
|
||||
return log.level === level;
|
||||
});
|
||||
}
|
||||
|
||||
if (limit) {
|
||||
filteredLogs = filteredLogs.slice(-limit);
|
||||
}
|
||||
|
||||
return filteredLogs;
|
||||
},
|
||||
|
||||
// 清除日志(仅管理员)
|
||||
clearLogs: function() {
|
||||
if (!this.config.enableConsole) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.logs = [];
|
||||
if (localStorage) {
|
||||
localStorage.removeItem(this.config.storageKey);
|
||||
localStorage.removeItem('argon_critical_errors');
|
||||
}
|
||||
return true;
|
||||
},
|
||||
|
||||
// 导出日志(仅管理员)
|
||||
exportLogs: function() {
|
||||
if (!this.config.enableConsole) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var exportData = {
|
||||
timestamp: new Date().toISOString(),
|
||||
site: window.location.origin,
|
||||
logs: this.logs,
|
||||
criticalErrors: JSON.parse(localStorage.getItem('argon_critical_errors') || '[]')
|
||||
};
|
||||
|
||||
return JSON.stringify(exportData, null, 2);
|
||||
},
|
||||
|
||||
// 绑定事件
|
||||
bindEvents: function() {
|
||||
var self = this;
|
||||
|
||||
// 监听页面错误
|
||||
window.addEventListener('error', function(e) {
|
||||
self.log('JavaScript错误: ' + e.message, 'ERROR', {
|
||||
filename: e.filename,
|
||||
lineno: e.lineno,
|
||||
colno: e.colno,
|
||||
stack: e.error ? e.error.stack : null
|
||||
});
|
||||
});
|
||||
|
||||
// 监听未处理的Promise拒绝
|
||||
window.addEventListener('unhandledrejection', function(e) {
|
||||
self.log('未处理的Promise拒绝: ' + e.reason, 'ERROR', {
|
||||
reason: e.reason,
|
||||
promise: e.promise
|
||||
});
|
||||
});
|
||||
|
||||
// 监听资源加载错误
|
||||
window.addEventListener('error', function(e) {
|
||||
if (e.target && e.target !== window) {
|
||||
var resourceType = e.target.tagName || 'unknown';
|
||||
var resourceUrl = e.target.src || e.target.href || 'unknown';
|
||||
self.log('资源加载失败: ' + resourceType + ' - ' + resourceUrl, 'WARN');
|
||||
}
|
||||
}, true);
|
||||
},
|
||||
|
||||
// 便捷方法
|
||||
debug: function(message, data) {
|
||||
this.log(message, 'DEBUG', data);
|
||||
},
|
||||
|
||||
info: function(message, data) {
|
||||
this.log(message, 'INFO', data);
|
||||
},
|
||||
|
||||
warn: function(message, data) {
|
||||
this.log(message, 'WARN', data);
|
||||
},
|
||||
|
||||
error: function(message, data) {
|
||||
this.log(message, 'ERROR', data);
|
||||
},
|
||||
|
||||
critical: function(message, data) {
|
||||
this.log(message, 'CRITICAL', data);
|
||||
}
|
||||
};
|
||||
|
||||
// 自动初始化
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
ArgonLogger.init();
|
||||
});
|
||||
} else {
|
||||
ArgonLogger.init();
|
||||
}
|
||||
|
||||
// 为管理员提供全局访问
|
||||
if (typeof window.argonUserRole !== 'undefined' && window.argonUserRole === 'administrator') {
|
||||
window.ArgonLogs = ArgonLogger;
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user