forked from wangziqi/gongxue-base
feat: add practice session resume
This commit is contained in:
@@ -4,6 +4,7 @@ import { Button, Text, Textarea, View } from '@tarojs/components';
|
||||
import { loadCollectionQuestions, loadQuestions } from '@/services/catalog';
|
||||
import {
|
||||
createPracticeSession,
|
||||
loadPracticeSessionDetail,
|
||||
submitAnswer,
|
||||
submitPracticeSession,
|
||||
toggleQuestionFavorite,
|
||||
@@ -66,6 +67,27 @@ function answerLabel(state?: AnswerState) {
|
||||
return state.selfJudged ? '已自评' : '已答';
|
||||
}
|
||||
|
||||
function answersFromBackend(answers?: Record<string, AnswerResult>): Record<string, AnswerState> {
|
||||
const result: Record<string, AnswerState> = {};
|
||||
for (const [questionId, answer] of Object.entries(answers || {})) {
|
||||
result[questionId] = {
|
||||
selectedOptions: Array.isArray(answer.selectedOptions) ? answer.selectedOptions : [],
|
||||
answerText: answer.answerText || '',
|
||||
isCorrect: answer.isCorrect,
|
||||
answeredAt: answer.answeredAt,
|
||||
selfJudged: answer.selfJudged,
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function secondsUntil(value?: string | null) {
|
||||
if (!value) return null;
|
||||
const parsed = new Date(value).getTime();
|
||||
if (!Number.isFinite(parsed)) return null;
|
||||
return Math.max(0, Math.ceil((parsed - Date.now()) / 1000));
|
||||
}
|
||||
|
||||
export default function StudentPracticePage() {
|
||||
const router = useRouter();
|
||||
const params = router.params || {};
|
||||
@@ -85,6 +107,7 @@ export default function StudentPracticePage() {
|
||||
const [error, setError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const practiceSessionId = params.practiceSessionId || undefined;
|
||||
const collectionId = params.collectionId || undefined;
|
||||
const body = {
|
||||
blueprintId: params.blueprintId || undefined,
|
||||
@@ -94,6 +117,27 @@ export default function StudentPracticePage() {
|
||||
mode: params.mode || 'sequential',
|
||||
questionLimit: 50,
|
||||
};
|
||||
|
||||
if (practiceSessionId) {
|
||||
loadPracticeSessionDetail(practiceSessionId)
|
||||
.then(payload => {
|
||||
const nextSession = payload.item;
|
||||
const backendAnswers = answersFromBackend(nextSession.answersByQuestion);
|
||||
setSession(nextSession);
|
||||
setQuestions(nextSession.questions || []);
|
||||
setAnswerByQuestion(backendAnswers);
|
||||
const savedIndex = getStorage<number>(indexStorageKey(nextSession.id));
|
||||
const firstUnanswered = (nextSession.questionIds || []).findIndex(questionId => !backendAnswers[questionId]);
|
||||
setIndex(typeof savedIndex === 'number' ? savedIndex : Math.max(0, firstUnanswered));
|
||||
const remaining = secondsUntil(nextSession.expiresAt);
|
||||
if (remaining !== null) setTimeLeft(remaining);
|
||||
if (nextSession.status === 'finished') setCompleted(true);
|
||||
})
|
||||
.catch(nextError => setError(nextError instanceof Error ? nextError.message : '练习恢复失败'))
|
||||
.finally(() => setLoading(false));
|
||||
return;
|
||||
}
|
||||
|
||||
createPracticeSession(body)
|
||||
.then(async payload => {
|
||||
const nextSession = payload.item;
|
||||
|
||||
Reference in New Issue
Block a user