client / static /js /timer.js
P01yH3dr0n's picture
launch
774fe36
Raw
History Blame Contribute Delete
3.04 kB
/* ===== Task Timer ===== */
window.NAITimer = {
startTime: null,
timerInterval: null,
history: [], // recent task durations for ETA
MAX_HISTORY: 10,
start() {
this.startTime = Date.now();
this._updateDisplay();
this.timerInterval = setInterval(() => this._updateDisplay(), 100);
this._showTimer(true);
},
stop(completed = true) {
if (this.startTime && completed) {
const duration = Date.now() - this.startTime;
this.history.push(duration);
if (this.history.length > this.MAX_HISTORY) this.history.shift();
}
clearInterval(this.timerInterval);
this.timerInterval = null;
this.startTime = null;
// Show final time briefly, then hide
setTimeout(() => this._showTimer(false), 3000);
},
_getAvgDuration() {
if (this.history.length === 0) return 0;
return this.history.reduce((a, b) => a + b, 0) / this.history.length;
},
_formatTime(ms) {
const s = Math.floor(ms / 1000);
const m = Math.floor(s / 60);
const sec = s % 60;
const tenths = Math.floor((ms % 1000) / 100);
if (m > 0) return `${m}:${String(sec).padStart(2, '0')}.${tenths}`;
return `${sec}.${tenths}s`;
},
_updateDisplay() {
const el = document.getElementById('task-timer');
if (!el || !this.startTime) return;
const elapsed = Date.now() - this.startTime;
const avg = this._getAvgDuration();
let text = this._formatTime(elapsed);
if (avg > 0) {
const remaining = Math.max(0, avg - elapsed);
if (remaining > 0) {
text += ` / 预计 ${this._formatTime(avg)}`;
} else {
text += ` / 预计 ${this._formatTime(avg)}`;
}
}
el.textContent = text;
// Progress bar
const bar = document.getElementById('task-timer-bar');
if (bar && avg > 0) {
const pct = Math.min(100, (elapsed / avg) * 100);
bar.style.width = pct + '%';
bar.className = 'task-timer-bar-fill' + (pct >= 100 ? ' overtime' : '');
}
},
_showTimer(show) {
const wrap = document.getElementById('task-timer-wrap');
if (wrap) wrap.style.display = show ? 'flex' : 'none';
},
init() {
// Create timer UI in header
const headerRight = document.querySelector('.header-right');
if (!headerRight) return;
const wrap = document.createElement('div');
wrap.id = 'task-timer-wrap';
wrap.className = 'task-timer-wrap';
wrap.style.display = 'none';
wrap.innerHTML = `
<div class="task-timer-bar-bg">
<div id="task-timer-bar" class="task-timer-bar-fill" style="width:0%"></div>
</div>
<span id="task-timer" class="task-timer-text"></span>
`;
headerRight.insertBefore(wrap, headerRight.firstChild);
},
};