/**
* @file js/ui/glossary-progress.js
* @description 术语库导入进度条组件
*/
(function() {
let progressModal = null;
/**
* 显示导入进度条
* @param {string} title - 标题
*/
function showImportProgress(title = '正在导入术语库...') {
// 如果已存在,先移除
hideImportProgress();
// 创建进度条 Modal
progressModal = document.createElement('div');
progressModal.id = 'glossaryImportProgressModal';
progressModal.className = 'fixed inset-0 z-[9999] flex items-center justify-center bg-black/50 backdrop-blur-sm';
progressModal.innerHTML = `
${title}
已处理:
0
总计:
0
速度:
-
预计剩余:
-
请勿关闭页面,数据正在保存中...
`;
document.body.appendChild(progressModal);
// 重置状态
progressState = {
startTime: Date.now(),
lastUpdateTime: Date.now(),
lastProcessed: 0
};
}
let progressState = {
startTime: 0,
lastUpdateTime: 0,
lastProcessed: 0
};
/**
* 更新进度条
* @param {number} current - 当前进度
* @param {number} total - 总数
* @param {string} message - 自定义消息
*/
function updateImportProgress(current, total, message) {
if (!progressModal) return;
const percent = Math.min(100, Math.round((current / total) * 100));
const now = Date.now();
const elapsed = now - progressState.startTime;
const recentElapsed = now - progressState.lastUpdateTime;
const processed = current - progressState.lastProcessed;
// 更新进度条
const progressBar = document.getElementById('glossaryProgressBar');
const progressPercent = document.getElementById('glossaryProgressPercent');
const progressText = document.getElementById('glossaryProgressText');
const progressCurrent = document.getElementById('glossaryProgressCurrent');
const progressTotal = document.getElementById('glossaryProgressTotal');
const progressSpeed = document.getElementById('glossaryProgressSpeed');
const progressETA = document.getElementById('glossaryProgressETA');
if (progressBar) progressBar.style.width = percent + '%';
if (progressPercent) progressPercent.textContent = percent + '%';
if (progressText) progressText.textContent = message || `正在保存 (${current.toLocaleString()} / ${total.toLocaleString()})`;
if (progressCurrent) progressCurrent.textContent = current.toLocaleString();
if (progressTotal) progressTotal.textContent = total.toLocaleString();
// 计算速度(条/秒)
if (recentElapsed > 0 && processed > 0) {
const speed = Math.round(processed / (recentElapsed / 1000));
if (progressSpeed) progressSpeed.textContent = speed.toLocaleString() + ' 条/秒';
// 计算预计剩余时间
const remaining = total - current;
const eta = Math.ceil(remaining / speed);
if (progressETA && eta > 0) {
if (eta < 60) {
progressETA.textContent = eta + ' 秒';
} else {
const minutes = Math.floor(eta / 60);
const seconds = eta % 60;
progressETA.textContent = `${minutes} 分 ${seconds} 秒`;
}
}
}
// 更新状态
progressState.lastUpdateTime = now;
progressState.lastProcessed = current;
}
/**
* 隐藏进度条
*/
function hideImportProgress() {
if (progressModal) {
progressModal.remove();
progressModal = null;
}
}
/**
* 显示完成消息
* @param {string} message - 消息内容
* @param {boolean} success - 是否成功
*/
function showImportComplete(message, success = true) {
if (!progressModal) return;
const icon = success ? 'carbon:checkmark-filled' : 'carbon:error-filled';
const iconColor = success ? 'text-green-500' : 'text-red-500';
progressModal.innerHTML = `
${success ? '导入完成' : '导入失败'}
${message}
`;
// 自动关闭
if (success) {
setTimeout(() => {
hideImportProgress();
}, 2000);
}
}
// 暴露到全局
window.glossaryProgress = {
show: showImportProgress,
update: updateImportProgress,
hide: hideImportProgress,
complete: showImportComplete
};
console.log('[GlossaryProgress] Progress component loaded');
})();