|
|
@@ -7,7 +7,9 @@ import { SessionService } from '../../core/session.service';
|
|
|
import { EnglishReadingService } from './english-reading.service';
|
|
|
import { ReadingCloudService } from './reading-cloud.service';
|
|
|
import { ReadingArticle, ReadingHistoryEntry, ReadingProgress, ReadingQuestion, ReadingRouteParams } from './reading.models';
|
|
|
-import { highlightWords, isCompleteReadingQuestionSet, normalizeReadingParams, normalizeReadingReturnUrl, readingStudentName, shuffle } from './reading.utils';
|
|
|
+import { highlightWords, isCompleteReadingQuestionSet, normalizeReadingParams, normalizeReadingReturnUrl, readingStudentName, normalizeReadingPresentationVersion } from './reading.utils';
|
|
|
+
|
|
|
+import { presentReadingQuestions } from './reading-presentation';
|
|
|
|
|
|
interface ReadingDialog {
|
|
|
title: string;
|
|
|
@@ -49,6 +51,7 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
readonly loadingTip = signal('');
|
|
|
answers: string[] = [];
|
|
|
params!: ReadingRouteParams;
|
|
|
+ private sourceQuestions: ReadingQuestion[] = [];
|
|
|
private retryCount = 0;
|
|
|
private readonly maxRetry = 5;
|
|
|
private historyPageIndex = 0;
|
|
|
@@ -144,14 +147,26 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
await this.submit();
|
|
|
}
|
|
|
|
|
|
- reset(): void {
|
|
|
- if (this.saving() || this.legacyIncomplete()) return;
|
|
|
- this.questions.set(shuffle(this.questions()).map((question) => ({ ...question, options: shuffle(question.options) })));
|
|
|
- this.answers = new Array(this.questions().length).fill('');
|
|
|
- this.score.set(0);
|
|
|
- this.submitted.set(false);
|
|
|
- this.saveFailed.set(false);
|
|
|
- this.dialog.set(null);
|
|
|
+ async reset(): Promise<void> {
|
|
|
+ if (this.saving() || this.legacyIncomplete() || !this.article()) return;
|
|
|
+ const presentationVersion = `v1-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
|
+ const params = { ...this.params, presentationVersion };
|
|
|
+ this.saving.set(true);
|
|
|
+ try {
|
|
|
+ const questions = presentReadingQuestions(this.sourceQuestions, `${this.article()!.objectId}:${presentationVersion}`);
|
|
|
+ const navigated = await this.router.navigate(['/words/reading'], {
|
|
|
+ queryParams: { ...params, wordList: params.wordList.join(',') }, replaceUrl: true,
|
|
|
+ });
|
|
|
+ if (!navigated) return;
|
|
|
+ this.params = params;
|
|
|
+ this.questions.set(questions);
|
|
|
+ this.answers = new Array(questions.length).fill('');
|
|
|
+ this.score.set(0);
|
|
|
+ this.submitted.set(false);
|
|
|
+ this.saveFailed.set(false);
|
|
|
+ this.dialog.set(null);
|
|
|
+ } catch (error) { this.showError(error); }
|
|
|
+ finally { this.saving.set(false); }
|
|
|
}
|
|
|
|
|
|
async print(): Promise<void> {
|
|
|
@@ -163,17 +178,17 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
|
|
|
async createNewArticle(): Promise<void> {
|
|
|
if (this.legacyIncomplete()) {
|
|
|
- const params = { ...this.params, sid: undefined, renew: true, wordList: this.params.wordList.join(','), t: Date.now() };
|
|
|
+ const params = { ...this.params, presentationVersion: 'v1', sid: undefined, renew: true, wordList: this.params.wordList.join(','), t: Date.now() };
|
|
|
const navigated = await this.router.navigate(['/words/reading'], { queryParams: params, replaceUrl: true });
|
|
|
if (navigated) {
|
|
|
- this.params = { ...this.params, sid: undefined, renew: true };
|
|
|
+ this.params = { ...this.params, presentationVersion: 'v1', sid: undefined, renew: true };
|
|
|
await this.load();
|
|
|
}
|
|
|
return;
|
|
|
}
|
|
|
if (!this.remainingArticles()) return;
|
|
|
await this.router.navigate(['/words/go-reading'], {
|
|
|
- queryParams: { ...this.params, wordList: this.params.wordList.join(','), type: '随机', theme: '随机', renew: true, t: Date.now() },
|
|
|
+ queryParams: { ...this.params, presentationVersion: 'v1', wordList: this.params.wordList.join(','), type: '随机', theme: '随机', renew: true, t: Date.now() },
|
|
|
});
|
|
|
}
|
|
|
|
|
|
@@ -224,7 +239,7 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
replaceUrl: true,
|
|
|
});
|
|
|
if (!navigated) return;
|
|
|
- this.params = { ...this.params, ...values, sid: entry.article.objectId, renew:false };
|
|
|
+ this.params = { ...this.params, ...values, sid: entry.article.objectId, renew:false, presentationVersion: 'v1' };
|
|
|
await this.load();
|
|
|
}
|
|
|
|
|
|
@@ -249,6 +264,7 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
this.error.set('');
|
|
|
this.article.set(null);
|
|
|
this.questions.set([]);
|
|
|
+ this.sourceQuestions = [];
|
|
|
this.answers = [];
|
|
|
this.submitted.set(false);
|
|
|
this.saving.set(false);
|
|
|
@@ -291,7 +307,9 @@ export class ReadingExerciseComponent implements OnInit {
|
|
|
} else if (!isCompleteReadingQuestionSet(questions)) {
|
|
|
this.legacyIncomplete.set(true);
|
|
|
}
|
|
|
- this.questions.set(shuffle(questions).map((question) => ({ ...question, options: shuffle(question.options) })));
|
|
|
+ this.sourceQuestions = questions;
|
|
|
+ this.params.presentationVersion = normalizeReadingPresentationVersion(this.params.presentationVersion);
|
|
|
+ this.questions.set(this.legacyIncomplete() ? questions : presentReadingQuestions(questions, `${article.objectId}:${this.params.presentationVersion}`));
|
|
|
this.answers = new Array(questions.length).fill('');
|
|
|
if (latest) this.restoreAttempt(latest.answer);
|
|
|
this.retryCount = 0;
|