优化目录结构
This commit is contained in:
84
client/public/shared/logger.js
Normal file
84
client/public/shared/logger.js
Normal file
@@ -0,0 +1,84 @@
|
||||
const LOG_LEVELS = {
|
||||
debug: 10,
|
||||
info: 20,
|
||||
warn: 30,
|
||||
error: 40,
|
||||
silent: 50
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'video_socket_log_level';
|
||||
const DEFAULT_LEVEL = 'warn';
|
||||
|
||||
function normalizeLevel(level) {
|
||||
if (!level) {
|
||||
return DEFAULT_LEVEL;
|
||||
}
|
||||
|
||||
const normalized = String(level).toLowerCase();
|
||||
return Object.prototype.hasOwnProperty.call(LOG_LEVELS, normalized)
|
||||
? normalized
|
||||
: DEFAULT_LEVEL;
|
||||
}
|
||||
|
||||
function getConfiguredLevel() {
|
||||
try {
|
||||
const queryLevel = new URLSearchParams(window.location.search).get('logLevel');
|
||||
if (queryLevel) {
|
||||
return normalizeLevel(queryLevel);
|
||||
}
|
||||
} catch (_error) {
|
||||
}
|
||||
|
||||
try {
|
||||
const storageLevel = localStorage.getItem(STORAGE_KEY);
|
||||
if (storageLevel) {
|
||||
return normalizeLevel(storageLevel);
|
||||
}
|
||||
} catch (_error) {
|
||||
}
|
||||
|
||||
return DEFAULT_LEVEL;
|
||||
}
|
||||
|
||||
function shouldLog(level) {
|
||||
return LOG_LEVELS[level] >= LOG_LEVELS[getConfiguredLevel()];
|
||||
}
|
||||
|
||||
function getConsoleMethod(level) {
|
||||
switch (level) {
|
||||
case 'debug':
|
||||
return console.debug;
|
||||
case 'info':
|
||||
return console.info;
|
||||
case 'warn':
|
||||
return console.warn;
|
||||
case 'error':
|
||||
return console.error;
|
||||
default:
|
||||
return console.log;
|
||||
}
|
||||
}
|
||||
|
||||
function emit(level, scope, args) {
|
||||
if (!shouldLog(level)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prefix = scope ? `[${scope}]` : '[app]';
|
||||
getConsoleMethod(level)(prefix, ...args);
|
||||
}
|
||||
|
||||
export function createLogger(scope) {
|
||||
return {
|
||||
debug: (...args) => emit('debug', scope, args),
|
||||
info: (...args) => emit('info', scope, args),
|
||||
warn: (...args) => emit('warn', scope, args),
|
||||
error: (...args) => emit('error', scope, args)
|
||||
};
|
||||
}
|
||||
|
||||
export function setBrowserLogLevel(level) {
|
||||
const normalized = normalizeLevel(level);
|
||||
localStorage.setItem(STORAGE_KEY, normalized);
|
||||
return normalized;
|
||||
}
|
||||
103
client/public/shared/utils.js
Normal file
103
client/public/shared/utils.js
Normal file
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 工具函数
|
||||
*/
|
||||
|
||||
/**
|
||||
* 格式化时间为 MM:SS 格式
|
||||
* @param {number} seconds - 秒数
|
||||
* @returns {string} 格式化后的时间字符串
|
||||
*/
|
||||
export function formatTime(seconds) {
|
||||
const mins = Math.floor(seconds / 60);
|
||||
const secs = seconds % 60;
|
||||
return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化时间戳为 HH:MM 格式
|
||||
* @param {string} timestamp - ISO 8601 时间戳
|
||||
* @returns {string} 格式化后的时间字符串
|
||||
*/
|
||||
export function formatTimestamp(timestamp) {
|
||||
const date = new Date(timestamp);
|
||||
const hours = date.getHours().toString().padStart(2, '0');
|
||||
const minutes = date.getMinutes().toString().padStart(2, '0');
|
||||
return `${hours}:${minutes}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成唯一ID
|
||||
* @returns {string} 唯一ID
|
||||
*/
|
||||
export function generateId() {
|
||||
return 'id-' + Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示通知
|
||||
* @param {string} message - 通知内容
|
||||
* @param {number} duration - 显示时长(毫秒)
|
||||
*/
|
||||
export function showNotification(message, duration = 3000) {
|
||||
const notification = document.getElementById('notification');
|
||||
const notificationText = document.getElementById('notificationText');
|
||||
|
||||
if (notification && notificationText) {
|
||||
notificationText.textContent = message;
|
||||
notification.classList.remove('opacity-0', 'translate-y-[-20px]');
|
||||
notification.classList.add('opacity-100', 'translate-y-0');
|
||||
|
||||
setTimeout(() => {
|
||||
notification.classList.remove('opacity-100', 'translate-y-0');
|
||||
notification.classList.add('opacity-0', 'translate-y-[-20px]');
|
||||
}, duration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换元素的显示/隐藏
|
||||
* @param {HTMLElement} element - DOM元素
|
||||
* @param {boolean} show - 是否显示
|
||||
*/
|
||||
export function toggleElement(element, show) {
|
||||
if (element) {
|
||||
if (show) {
|
||||
element.classList.remove('hidden');
|
||||
} else {
|
||||
element.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换按钮状态
|
||||
* @param {HTMLElement} button - 按钮元素
|
||||
* @param {boolean} active - 是否激活
|
||||
*/
|
||||
export function toggleButtonState(button, active) {
|
||||
if (button) {
|
||||
button.dataset.active = active;
|
||||
|
||||
const defaultIcon = button.querySelector('[data-icon="default"]');
|
||||
const activeIcon = button.querySelector('[data-icon="active"]');
|
||||
|
||||
if (defaultIcon && activeIcon) {
|
||||
if (active) {
|
||||
defaultIcon.classList.add('hidden');
|
||||
activeIcon.classList.remove('hidden');
|
||||
} else {
|
||||
defaultIcon.classList.remove('hidden');
|
||||
activeIcon.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 生成随机会议ID
|
||||
* @returns {string} 随机会议ID
|
||||
*/
|
||||
export function randomMeetingId() {
|
||||
const part = () => Math.floor(100 + Math.random() * 900);
|
||||
return `${part()}-${part()}-${part()}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user