2026-04-29 15:18:30 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 工具函数
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 格式化时间为 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');
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-05-17 20:59:34 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 生成随机会议ID
|
|
|
|
|
|
* @returns {string} 随机会议ID
|
|
|
|
|
|
*/
|
|
|
|
|
|
export function randomMeetingId() {
|
|
|
|
|
|
const part = () => Math.floor(100 + Math.random() * 900);
|
|
|
|
|
|
return `${part()}-${part()}-${part()}`;
|
|
|
|
|
|
}
|
|
|
|
|
|
|