/** * 计时器服务模块 * 负责答题计时相关逻辑 */ /** * 格式化时间显示(秒数转为 HH:MM:SS 格式) * @param {Number} totalSeconds - 总秒数 * @returns {String} 格式化后的时间字符串 */ export function formatTime(totalSeconds) { if (totalSeconds < 0) totalSeconds = 0; const hours = Math.floor(totalSeconds / 3600); const minutes = Math.floor((totalSeconds % 3600) / 60); const seconds = totalSeconds % 60; const formatNumber = (num) => { return num < 10 ? '0' + num : String(num); }; if (hours > 0) { return `${formatNumber(hours)}:${formatNumber(minutes)}:${formatNumber(seconds)}`; } else { return `${formatNumber(minutes)}:${formatNumber(seconds)}`; } } /** * 启动计时器 * @param {Object} context - 页面上下文 * @param {Number} durationMinutes - 考试时长(分钟) * @param {String} startTime - 开始时间(ISO 字符串) * @param {Function} onTimeUp - 时间到回调 * @returns {Number} 定时器ID */ export function startTimer(context, durationMinutes, startTime, onTimeUp) { if (context.timerInterval) { clearInterval(context.timerInterval); } const startTimestamp = new Date(startTime).getTime(); const durationMs = durationMinutes * 60 * 1000; const endTimestamp = startTimestamp + durationMs; const updateTimer = () => { const now = Date.now(); const remainingMs = Math.max(0, endTimestamp - now); const remainingSeconds = Math.floor(remainingMs / 1000); if (remainingSeconds <= 0) { clearInterval(context.timerInterval); context.timerInterval = null; context.setData({ timerText: '00:00', isPaused: false }); if (onTimeUp) { onTimeUp(); } return; } context.setData({ timerText: formatTime(remainingSeconds) }); }; updateTimer(); context.timerInterval = setInterval(updateTimer, 1000); return context.timerInterval; } /** * 暂停计时器 * @param {Object} context - 页面上下文 * @returns {Number} 暂停时的剩余秒数 */ export function pauseTimer(context) { if (context.timerInterval) { clearInterval(context.timerInterval); context.timerInterval = null; } const timerText = context.data.timerText || '00:00:00'; const parts = timerText.split(':'); let totalSeconds = 0; if (parts.length === 3) { totalSeconds = parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]); } else if (parts.length === 2) { totalSeconds = parseInt(parts[0]) * 60 + parseInt(parts[1]); } context.setData({ isPaused: true, pauseStartTime: Date.now() }); return totalSeconds; } /** * 恢复计时器 * @param {Object} context - 页面上下文 * @param {Number} pausedSeconds - 暂停时的剩余秒数 * @param {Function} onTimeUp - 时间到回调 */ export function resumeTimer(context, pausedSeconds, onTimeUp) { if (context.timerInterval) { clearInterval(context.timerInterval); } const pauseDuration = context.data.pauseStartTime ? Math.floor((Date.now() - context.data.pauseStartTime) / 1000) : 0; const remainingSeconds = Math.max(0, pausedSeconds - pauseDuration); if (remainingSeconds <= 0) { context.setData({ timerText: '00:00', isPaused: false }); if (onTimeUp) { onTimeUp(); } return; } context.setData({ isPaused: false, pauseStartTime: null }); let currentSeconds = remainingSeconds; context.timerInterval = setInterval(() => { currentSeconds--; if (currentSeconds <= 0) { clearInterval(context.timerInterval); context.timerInterval = null; context.setData({ timerText: '00:00', isPaused: false }); if (onTimeUp) { onTimeUp(); } return; } context.setData({ timerText: formatTime(currentSeconds) }); }, 1000); } /** * 停止计时器 * @param {Object} context - 页面上下文 */ export function stopTimer(context) { if (context.timerInterval) { clearInterval(context.timerInterval); context.timerInterval = null; } }