Files
lpt-fe/src/components/composables/useTimer.ts
T

109 lines
3.4 KiB
TypeScript

// src/composables/useTimer.ts
import { ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
export function useTimer(audioUrl: string = '/resource/notification.mp3') {
const timerMinutes = ref(25);
const timerSeconds = ref(0);
const remainingTime = ref(25 * 60 * 1000);
const timerRunning = ref(false);
const timerIsOver = ref(false);
const audioActivated = ref(false);
let timerInterval: number;
const audio = new Audio(audioUrl);
const clear = () => {
clearInterval(timerInterval);
timerRunning.value = false;
};
const syncDisplay = (durationMs: number) => {
const safeDuration = Math.max(durationMs, 0);
remainingTime.value = safeDuration;
timerMinutes.value = Math.floor(safeDuration / 1000 / 60);
timerSeconds.value = Math.floor((safeDuration / 1000) % 60);
timerIsOver.value = safeDuration === 0;
};
const handleCountdownComplete = () => {
audio.loop = true;
audio.play();
ElMessageBox.alert('本次番茄钟结束!请点击“休息”按钮开始休息倒计时', '提醒', {
confirmButtonText: '关闭铃声',
callback: () => {
audio.pause();
audio.currentTime = 0;
ElMessage.success('铃声已关闭');
},
});
};
const runCountdown = (durationMs: number, onComplete: () => void = handleCountdownComplete) => {
clearInterval(timerInterval);
const endTimeStamp = Date.now() + durationMs;
remainingTime.value = durationMs;
timerIsOver.value = false;
timerRunning.value = true;
timerInterval = window.setInterval(() => {
const now = Date.now();
remainingTime.value = Math.max(endTimeStamp - now, 0);
timerMinutes.value = Math.floor(remainingTime.value / 1000 / 60);
timerSeconds.value = Math.floor((remainingTime.value / 1000) % 60);
if (remainingTime.value === 0 && !timerIsOver.value) {
timerIsOver.value = true;
timerRunning.value = false;
onComplete();
}
}, 1000);
};
const checkAudioPermission = async () => {
try {
await audio.play();
audio.pause();
audio.currentTime = 0;
audioActivated.value = true;
return true;
} catch {
audioActivated.value = false;
return false;
}
};
const requestAudioPermission = () => {
return new Promise<boolean>((resolve) => {
ElMessageBox.alert('点击确认激活提示音权限。', '权限激活', {
confirmButtonText: '确认',
callback: async () => {
try {
await audio.play();
audio.pause();
audio.currentTime = 0;
audioActivated.value = true;
resolve(true);
} catch {
resolve(false);
}
},
});
});
};
return {
timerMinutes,
timerSeconds,
remainingTime,
timerRunning,
timerIsOver,
runCountdown,
syncDisplay,
clear,
checkAudioPermission,
requestAudioPermission,
audioActivated,
};
}