fix: 学习会话按钮补防抖加载

This commit is contained in:
2026-08-05 21:42:45 +08:00
parent 9ed53aa4bc
commit c95e593cf1
3 changed files with 78 additions and 32 deletions
@@ -88,4 +88,25 @@ describe('useStudyFragment', () => {
expect(result).toBe(false)
expect(ElMessage.error).toHaveBeenCalledWith('网络超时')
})
it('prevents duplicate submission while creating fragment', async () => {
let resolveCreate!: (value: any) => void
vi.mocked(createFragments).mockImplementation(
() => new Promise((resolve) => { resolveCreate = resolve }),
)
const { fragmentContent, creatingFragment, confirmGenerateFragment } = useStudyFragment()
fragmentContent.value = '学习内容'
const first = confirmGenerateFragment('S001')
const second = confirmGenerateFragment('S001')
await Promise.resolve()
expect(createFragments).toHaveBeenCalledTimes(1)
expect(creatingFragment.value).toBe(true)
resolveCreate({ code: 200 })
await Promise.all([first, second])
expect(creatingFragment.value).toBe(false)
})
})
+24 -5
View File
@@ -25,9 +25,12 @@ const {
openFragmentDialog,
closeFragmentDialog,
confirmGenerateFragment,
creatingFragment,
} = useStudyFragment();
const pageLoading = ref(true);
const timerActionLoading = ref(false);
const endingSession = ref(false);
const summaryDialogVisible = ref(false);
const summaryContent = ref("");
@@ -309,6 +312,9 @@ const statusText = computed(() => {
});
const startTimer = async () => {
if (timerActionLoading.value) return;
timerActionLoading.value = true;
try {
if (taskInfo.value.sessionState === "PAUSED") {
const res = await continueSession(taskInfo.value.sessionNum);
if (res.code === 200) ElMessage.success("任务继续");
@@ -319,9 +325,15 @@ const startTimer = async () => {
isBreak.value = false;
const duration = taskInfo.value.pointerPosition || 25 * 60 * 1000;
runCountdown(duration);
} finally {
timerActionLoading.value = false;
}
};
const stopTimer = async () => {
if (timerActionLoading.value) return;
timerActionLoading.value = true;
try {
const res = await pauseSession(taskInfo.value.sessionNum);
if (res.code === 200) {
ElMessage.success("任务暂停");
@@ -343,6 +355,9 @@ const stopTimer = async () => {
taskInfo.value.sessionState = "PAUSED";
}
}
} finally {
timerActionLoading.value = false;
}
clear();
clearBreakState();
};
@@ -367,6 +382,8 @@ const endTimer = async (content: string) => {
// 用户取消结束会话,不做任何操作
return;
}
if (endingSession.value) return;
endingSession.value = true;
try {
const res = await endSession(taskInfo.value.sessionNum, content);
@@ -385,6 +402,8 @@ const endTimer = async (content: string) => {
await router.push("/study");
} catch {
ElMessage.error("结束会话失败,请重试");
} finally {
endingSession.value = false;
}
};
@@ -741,10 +760,10 @@ defineExpose({
<el-button @click="openFragmentDialog">生成残片</el-button>
</template>
<template v-else>
<el-button type="success" @click="startTimer" :disabled="timerRunning">开始</el-button>
<el-button @click="stopTimer" :disabled="!timerRunning" v-if="!timerIsOver">暂停</el-button>
<el-button type="success" @click="startTimer" :disabled="timerRunning" :loading="timerActionLoading">开始</el-button>
<el-button @click="stopTimer" :disabled="!timerRunning" :loading="timerActionLoading" v-if="!timerIsOver">暂停</el-button>
<el-button @click="openFragmentDialog">生成残片</el-button>
<el-button v-if="timerIsOver" plain type="success" @click="restTimer">休息</el-button>
<el-button v-if="timerIsOver" plain type="success" @click="restTimer" :loading="timerActionLoading">休息</el-button>
</template>
<el-button type="danger" plain @click="openSummaryDialog">结束会话</el-button>
</div>
@@ -827,7 +846,7 @@ defineExpose({
/>
<template #footer>
<el-button @click="closeFragmentDialog">取消</el-button>
<el-button type="success" @click="confirmGenerateFragment(taskInfo.sessionNum)">确定生成</el-button>
<el-button type="success" :loading="creatingFragment" @click="confirmGenerateFragment(taskInfo.sessionNum)">确定生成</el-button>
</template>
</el-dialog>
@@ -887,7 +906,7 @@ defineExpose({
</div>
<template #footer>
<el-button @click="closeSummaryDialog">取消</el-button>
<el-button type="success" @click="endTimer(summaryContent)">确认结束</el-button>
<el-button type="success" :loading="endingSession" @click="endTimer(summaryContent)">确认结束</el-button>
</template>
</el-dialog>
</div>
+6
View File
@@ -5,6 +5,7 @@ import {createFragments} from '@/api/reportFragments';
export const useStudyFragment = () => {
const fragmentsDialogVisible = ref(false);
const fragmentContent = ref('');
const creatingFragment = ref(false);
const openFragmentDialog = () => {
fragmentContent.value = '';
@@ -26,6 +27,7 @@ export const useStudyFragment = () => {
};
const confirmGenerateFragment = async (sessionNum: string): Promise<boolean> => {
if (creatingFragment.value) return false;
if (!fragmentContent.value.trim()) {
ElMessage.warning('请输入学习内容!');
return false;
@@ -43,6 +45,7 @@ export const useStudyFragment = () => {
}
try {
creatingFragment.value = true;
const res = await createFragments(sessionNum, fragmentContent.value);
if (res.code === 200) {
ElMessage.success('学习残片生成成功!');
@@ -55,12 +58,15 @@ export const useStudyFragment = () => {
} catch (error: any) {
ElMessage.error(error.message || '请求失败');
return false;
} finally {
creatingFragment.value = false;
}
};
return {
fragmentsDialogVisible,
fragmentContent,
creatingFragment,
openFragmentDialog,
closeFragmentDialog,
confirmGenerateFragment,