diff --git a/src/api/studySessions.ts b/src/api/studySessions.ts index 9fa8477..a75bde0 100644 --- a/src/api/studySessions.ts +++ b/src/api/studySessions.ts @@ -21,3 +21,18 @@ export const startOrContinueStudySession = (taskNum: string) => { export const getSessionDetail = (sessionNum: string) => { return request.get(`/study-sessions/${sessionNum}`); }; + +/** 获取会话的学习预期 */ +export const getExpectation = (sessionNum: string) => { + return request.get(`/study-sessions/${sessionNum}/expectation`); +}; + +/** 创建/更新会话的学习预期 */ +export const upsertExpectation = (sessionNum: string, description: string) => { + return request.put(`/study-sessions/${sessionNum}/expectation`, { description }); +}; + +/** 获取报告草稿(AI 聚合残片,不可用时为拼接) */ +export const getReportDraft = (sessionNum: string) => { + return request.get(`/study-sessions/${sessionNum}/report-draft`); +}; diff --git a/src/api/tasks.ts b/src/api/tasks.ts index b4af7ef..f5dd0b1 100644 --- a/src/api/tasks.ts +++ b/src/api/tasks.ts @@ -42,3 +42,22 @@ export const updateTaskApplication = ( export const deleteTaskApplication = (id: number) => { return request.del(`/tasks/applications/${id}`); }; + +// ============ 优先级权重配置 ============ + +export interface PriorityWeights { + urgencyWeight: number; + importanceWeight: number; + contentDifficultyWeight: number; + futureValueWeight: number; + subjectivePriorityWeight: number; +} + +export const getPriorityWeights = () => { + return request.get("/tasks/priority-weights"); +}; + +/** 保存权重配置并触发全部任务优先级重算 */ +export const savePriorityWeights = (weights: PriorityWeights) => { + return request.put("/tasks/priority-weights", weights); +}; diff --git a/src/components/StartTask.vue b/src/components/StartTask.vue index a017f2f..4a4eb09 100644 --- a/src/components/StartTask.vue +++ b/src/components/StartTask.vue @@ -11,6 +11,7 @@ import { } from "@/api/studySessions"; import { useStudyFragment } from "@/components/composables/fragment"; import { getFragmentsBySession, updateFragments } from "@/api/reportFragments"; +import { getExpectation, getReportDraft, upsertExpectation } from "@/api/studySessions"; import router from "@/router"; const { @@ -23,6 +24,13 @@ const { const summaryDialogVisible = ref(false); const summaryContent = ref(""); +const summaryLoading = ref(false); + +// 学习预期 +const expectationDialogVisible = ref(false); +const expectationContent = ref(""); +const expectationSaved = ref(""); +const savingExpectation = ref(false); // 当前会话碎片列表 interface FragmentItem { @@ -209,8 +217,22 @@ const endTimer = async (content: string) => { } }; -const openSummaryDialog = () => { +const openSummaryDialog = async () => { summaryDialogVisible.value = true; + // 有残片且未填写过总结时,用 AI 聚合草稿作为编辑起点 + if (!summaryContent.value.trim() && fragmentsList.value.length > 0) { + summaryLoading.value = true; + try { + const res = await getReportDraft(taskInfo.value.sessionNum); + if (res?.code === 200 && res.data) { + summaryContent.value = res.data; + } + } catch { + // 草稿失败不阻塞手写 + } finally { + summaryLoading.value = false; + } + } }; const closeSummaryDialog = () => { @@ -226,6 +248,7 @@ const loadTaskSession = async () => { try { const res = await startOrContinueStudySession(taskNum); Object.assign(taskInfo.value, res.data); + await loadExpectation(); if (taskInfo.value.sessionState === "ONGOING") { startTimer(); } else { @@ -237,6 +260,41 @@ const loadTaskSession = async () => { } }; +// 学习预期:会话必须有预期才能开始计时 +const loadExpectation = async () => { + if (!taskInfo.value.sessionNum) return; + try { + const res = await getExpectation(taskInfo.value.sessionNum); + expectationSaved.value = res?.data?.description || ""; + } catch { + expectationSaved.value = ""; + } + if (!expectationSaved.value) { + expectationDialogVisible.value = true; + } +}; + +const saveExpectation = async () => { + if (!expectationContent.value.trim()) { + ElMessage.warning("学习预期不可为空"); + return; + } + savingExpectation.value = true; + try { + const res = await upsertExpectation(taskInfo.value.sessionNum, expectationContent.value); + if (res?.code === 200) { + expectationSaved.value = expectationContent.value; + expectationDialogVisible.value = false; + } else { + ElMessage.error(res?.message || "保存失败"); + } + } catch (e: any) { + ElMessage.error(e.message || "请求失败"); + } finally { + savingExpectation.value = false; + } +}; + const initPage = async () => { const hasPermission = await checkAudioPermission(); if (!hasPermission) { @@ -323,6 +381,19 @@ onUnmounted(() => { 状态:{{ statusText }} + +
+ 本次预期 + {{ expectationSaved }} + + 修改 + +
+ { - + +

开始学习前,写下这次想学会什么。结束时会与实际学习内容对照。

+ +
+ + +
+ 本次预期 + {{ expectationSaved }} +
+