fix: 学习会话按钮补防抖加载
This commit is contained in:
@@ -88,4 +88,25 @@ describe('useStudyFragment', () => {
|
|||||||
expect(result).toBe(false)
|
expect(result).toBe(false)
|
||||||
expect(ElMessage.error).toHaveBeenCalledWith('网络超时')
|
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)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ const {
|
|||||||
openFragmentDialog,
|
openFragmentDialog,
|
||||||
closeFragmentDialog,
|
closeFragmentDialog,
|
||||||
confirmGenerateFragment,
|
confirmGenerateFragment,
|
||||||
|
creatingFragment,
|
||||||
} = useStudyFragment();
|
} = useStudyFragment();
|
||||||
|
|
||||||
const pageLoading = ref(true);
|
const pageLoading = ref(true);
|
||||||
|
const timerActionLoading = ref(false);
|
||||||
|
const endingSession = ref(false);
|
||||||
|
|
||||||
const summaryDialogVisible = ref(false);
|
const summaryDialogVisible = ref(false);
|
||||||
const summaryContent = ref("");
|
const summaryContent = ref("");
|
||||||
@@ -309,6 +312,9 @@ const statusText = computed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const startTimer = async () => {
|
const startTimer = async () => {
|
||||||
|
if (timerActionLoading.value) return;
|
||||||
|
timerActionLoading.value = true;
|
||||||
|
try {
|
||||||
if (taskInfo.value.sessionState === "PAUSED") {
|
if (taskInfo.value.sessionState === "PAUSED") {
|
||||||
const res = await continueSession(taskInfo.value.sessionNum);
|
const res = await continueSession(taskInfo.value.sessionNum);
|
||||||
if (res.code === 200) ElMessage.success("任务继续");
|
if (res.code === 200) ElMessage.success("任务继续");
|
||||||
@@ -319,9 +325,15 @@ const startTimer = async () => {
|
|||||||
isBreak.value = false;
|
isBreak.value = false;
|
||||||
const duration = taskInfo.value.pointerPosition || 25 * 60 * 1000;
|
const duration = taskInfo.value.pointerPosition || 25 * 60 * 1000;
|
||||||
runCountdown(duration);
|
runCountdown(duration);
|
||||||
|
} finally {
|
||||||
|
timerActionLoading.value = false;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopTimer = async () => {
|
const stopTimer = async () => {
|
||||||
|
if (timerActionLoading.value) return;
|
||||||
|
timerActionLoading.value = true;
|
||||||
|
try {
|
||||||
const res = await pauseSession(taskInfo.value.sessionNum);
|
const res = await pauseSession(taskInfo.value.sessionNum);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success("任务暂停");
|
ElMessage.success("任务暂停");
|
||||||
@@ -343,6 +355,9 @@ const stopTimer = async () => {
|
|||||||
taskInfo.value.sessionState = "PAUSED";
|
taskInfo.value.sessionState = "PAUSED";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
timerActionLoading.value = false;
|
||||||
|
}
|
||||||
clear();
|
clear();
|
||||||
clearBreakState();
|
clearBreakState();
|
||||||
};
|
};
|
||||||
@@ -367,6 +382,8 @@ const endTimer = async (content: string) => {
|
|||||||
// 用户取消结束会话,不做任何操作
|
// 用户取消结束会话,不做任何操作
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (endingSession.value) return;
|
||||||
|
endingSession.value = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const res = await endSession(taskInfo.value.sessionNum, content);
|
const res = await endSession(taskInfo.value.sessionNum, content);
|
||||||
@@ -385,6 +402,8 @@ const endTimer = async (content: string) => {
|
|||||||
await router.push("/study");
|
await router.push("/study");
|
||||||
} catch {
|
} catch {
|
||||||
ElMessage.error("结束会话失败,请重试");
|
ElMessage.error("结束会话失败,请重试");
|
||||||
|
} finally {
|
||||||
|
endingSession.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -741,10 +760,10 @@ defineExpose({
|
|||||||
<el-button @click="openFragmentDialog">生成残片</el-button>
|
<el-button @click="openFragmentDialog">生成残片</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<el-button type="success" @click="startTimer" :disabled="timerRunning">开始</el-button>
|
<el-button type="success" @click="startTimer" :disabled="timerRunning" :loading="timerActionLoading">开始</el-button>
|
||||||
<el-button @click="stopTimer" :disabled="!timerRunning" v-if="!timerIsOver">暂停</el-button>
|
<el-button @click="stopTimer" :disabled="!timerRunning" :loading="timerActionLoading" v-if="!timerIsOver">暂停</el-button>
|
||||||
<el-button @click="openFragmentDialog">生成残片</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>
|
</template>
|
||||||
<el-button type="danger" plain @click="openSummaryDialog">结束会话</el-button>
|
<el-button type="danger" plain @click="openSummaryDialog">结束会话</el-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -827,7 +846,7 @@ defineExpose({
|
|||||||
/>
|
/>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="closeFragmentDialog">取消</el-button>
|
<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>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
@@ -887,7 +906,7 @@ defineExpose({
|
|||||||
</div>
|
</div>
|
||||||
<template #footer>
|
<template #footer>
|
||||||
<el-button @click="closeSummaryDialog">取消</el-button>
|
<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>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {createFragments} from '@/api/reportFragments';
|
|||||||
export const useStudyFragment = () => {
|
export const useStudyFragment = () => {
|
||||||
const fragmentsDialogVisible = ref(false);
|
const fragmentsDialogVisible = ref(false);
|
||||||
const fragmentContent = ref('');
|
const fragmentContent = ref('');
|
||||||
|
const creatingFragment = ref(false);
|
||||||
|
|
||||||
const openFragmentDialog = () => {
|
const openFragmentDialog = () => {
|
||||||
fragmentContent.value = '';
|
fragmentContent.value = '';
|
||||||
@@ -26,6 +27,7 @@ export const useStudyFragment = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const confirmGenerateFragment = async (sessionNum: string): Promise<boolean> => {
|
const confirmGenerateFragment = async (sessionNum: string): Promise<boolean> => {
|
||||||
|
if (creatingFragment.value) return false;
|
||||||
if (!fragmentContent.value.trim()) {
|
if (!fragmentContent.value.trim()) {
|
||||||
ElMessage.warning('请输入学习内容!');
|
ElMessage.warning('请输入学习内容!');
|
||||||
return false;
|
return false;
|
||||||
@@ -43,6 +45,7 @@ export const useStudyFragment = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
creatingFragment.value = true;
|
||||||
const res = await createFragments(sessionNum, fragmentContent.value);
|
const res = await createFragments(sessionNum, fragmentContent.value);
|
||||||
if (res.code === 200) {
|
if (res.code === 200) {
|
||||||
ElMessage.success('学习残片生成成功!');
|
ElMessage.success('学习残片生成成功!');
|
||||||
@@ -55,12 +58,15 @@ export const useStudyFragment = () => {
|
|||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
ElMessage.error(error.message || '请求失败');
|
ElMessage.error(error.message || '请求失败');
|
||||||
return false;
|
return false;
|
||||||
|
} finally {
|
||||||
|
creatingFragment.value = false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fragmentsDialogVisible,
|
fragmentsDialogVisible,
|
||||||
fragmentContent,
|
fragmentContent,
|
||||||
|
creatingFragment,
|
||||||
openFragmentDialog,
|
openFragmentDialog,
|
||||||
closeFragmentDialog,
|
closeFragmentDialog,
|
||||||
confirmGenerateFragment,
|
confirmGenerateFragment,
|
||||||
|
|||||||
Reference in New Issue
Block a user