diff --git a/src/resource/notification.mp3 b/public/resource/notification.mp3
similarity index 100%
rename from src/resource/notification.mp3
rename to public/resource/notification.mp3
diff --git a/src/api/studySessions.ts b/src/api/studySessions.ts
new file mode 100644
index 0000000..ff62727
--- /dev/null
+++ b/src/api/studySessions.ts
@@ -0,0 +1,19 @@
+// src/api/studySession.ts
+import request from "@/utils/request";
+
+export const continueSession = (sessionNum: string) => {
+ return request.post(`/study-sessions/${sessionNum}/study-sessions/continue`);
+};
+
+export const pauseSession = (sessionNum: string, endTime?: Date) => {
+ const params = endTime ? { endTime: endTime.toISOString() } : null;
+ return request.post(`/study-sessions/${sessionNum}/study-sessions/pause`, null, { params });
+};
+
+export const endSession = (sessionNum: string, content: string = "任务结束") => {
+ return request.post(`/study-sessions/${sessionNum}/study-sessions/ended`, { content });
+};
+
+export const startOrContinueStudySession = (taskNum: string) => {
+ return request.get(`/tasks/${taskNum}/study-sessions/start-or-continue`);
+};
diff --git a/src/components/StartTask.vue b/src/components/StartTask.vue
index d4c1cd4..0a3d2e8 100644
--- a/src/components/StartTask.vue
+++ b/src/components/StartTask.vue
@@ -1,38 +1,50 @@
+
@@ -180,17 +131,19 @@ onUnmounted(() => {
有效时间:{{ taskInfo.effectiveTime / 60 }}分钟
本次运行时间:{{ formatTime(elapsedTime) }}
-
- {{ timerMinutes.toString().padStart(2, '0') }} : {{ timerSeconds.toString().padStart(2, '0') }}
+
+ {{ timerMinutes.toString().padStart(2, '0') }} :
+ {{ timerSeconds.toString().padStart(2, '0') }}
+
-
开始
- 暂停
- 结束
+ 暂停
+ 休息
+ 结束
@@ -203,16 +156,13 @@ onUnmounted(() => {
justify-content: center;
margin: 20px;
}
-
.task-info {
font-size: 18px;
margin-bottom: 30px;
}
-
.timer-section {
margin: 20px;
}
-
.actions {
display: flex;
gap: 10px;
diff --git a/src/components/Study.vue b/src/components/Study.vue
index ab1ff95..a43326b 100644
--- a/src/components/Study.vue
+++ b/src/components/Study.vue
@@ -84,7 +84,7 @@ onMounted(() => {
任务描述
-
+
任务优先级
diff --git a/src/components/composables/useTimer.ts b/src/components/composables/useTimer.ts
new file mode 100644
index 0000000..36460f2
--- /dev/null
+++ b/src/components/composables/useTimer.ts
@@ -0,0 +1,99 @@
+// src/composables/useTimer.ts
+import { ref } from 'vue';
+import { ElMessageBox, ElMessage } from 'element-plus';
+
+export function useTimer(audioUrl: string = '/public/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 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((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,
+ clear,
+ checkAudioPermission,
+ requestAudioPermission,
+ audioActivated,
+ };
+}
diff --git a/src/utils/request.ts b/src/utils/request.ts
index 211426d..1d56b77 100644
--- a/src/utils/request.ts
+++ b/src/utils/request.ts
@@ -1,7 +1,7 @@
import axios from 'axios';
import { ElMessage } from "element-plus";
-const basic_url = "http://localhost:8081";
+const basic_url = "http://localhost:5157";
const axiosInstance = axios.create({
baseURL: basic_url,
@@ -27,12 +27,15 @@ const validateResponse = (res: any) => {
return result;
};
-const get = (url: string, params: {}) => {
+function get(url: string, params: Record): Promise;
+function get(url: string): Promise;
+
+function get(url: string, params: Record = {}) {
console.log("开始GET请求", basic_url + url, "参数:", params);
return axiosInstance.get(url, { params })
.then(validateResponse)
.catch(handleError);
-};
+}
const post = (url: string, data: any = null, config: any = {}) => {
console.log("开始POST请求", url, "参数:", data, "配置:", config);