|
@@ -1,25 +1,33 @@
|
|
|
-// recite-words.page.ts 完整修正版
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * 背单词页面组件
|
|
|
|
|
+ * 负责单词学习的主流程控制,包含三种学习模式:
|
|
|
|
|
+ * 模式1:第一次学习(看单词选释义)
|
|
|
|
|
+ * 模式2:第二次学习(听音辨义)
|
|
|
|
|
+ * 模式3:第三次学习(词汇检测)
|
|
|
|
|
+ * 以及学习完成后的拼写练习导航
|
|
|
|
|
+ */
|
|
|
|
|
|
|
|
import { Component, OnInit, AfterViewInit, ViewChild, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
|
import { Component, OnInit, AfterViewInit, ViewChild, OnDestroy, ChangeDetectorRef } from '@angular/core';
|
|
|
import { CommonModule } from '@angular/common';
|
|
import { CommonModule } from '@angular/common';
|
|
|
import { FormsModule } from '@angular/forms';
|
|
import { FormsModule } from '@angular/forms';
|
|
|
import { Router } from '@angular/router';
|
|
import { Router } from '@angular/router';
|
|
|
|
|
+import { WordDetailService } from '../word-detail/word-detail.service';
|
|
|
import {
|
|
import {
|
|
|
IonButton,
|
|
IonButton,
|
|
|
IonContent,
|
|
IonContent,
|
|
|
IonHeader,
|
|
IonHeader,
|
|
|
- IonTitle,
|
|
|
|
|
IonToolbar,
|
|
IonToolbar,
|
|
|
IonSpinner,
|
|
IonSpinner,
|
|
|
IonIcon,
|
|
IonIcon,
|
|
|
IonButtons,
|
|
IonButtons,
|
|
|
AlertController,
|
|
AlertController,
|
|
|
|
|
+ NavController
|
|
|
} from '@ionic/angular/standalone';
|
|
} from '@ionic/angular/standalone';
|
|
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
import { HttpClient, HttpClientModule } from '@angular/common/http';
|
|
|
import { addIcons } from 'ionicons';
|
|
import { addIcons } from 'ionicons';
|
|
|
import {
|
|
import {
|
|
|
chevronBackOutline,
|
|
chevronBackOutline,
|
|
|
- trophyOutline,
|
|
|
|
|
|
|
+ trophy,
|
|
|
homeOutline,
|
|
homeOutline,
|
|
|
flameOutline,
|
|
flameOutline,
|
|
|
addCircleOutline,
|
|
addCircleOutline,
|
|
@@ -36,11 +44,12 @@ import { WordDetailComponent } from '../word-detail/word-detail.component';
|
|
|
import { WordProcessingService } from './word-processing.service';
|
|
import { WordProcessingService } from './word-processing.service';
|
|
|
import { WordGroupService } from './word-group.service';
|
|
import { WordGroupService } from './word-group.service';
|
|
|
import { Word, WordOption } from './word-interfaces';
|
|
import { Word, WordOption } from './word-interfaces';
|
|
|
|
|
+import { finalize } from 'rxjs/operators'; // 导入finalize操作符
|
|
|
|
|
|
|
|
-
|
|
|
|
|
|
|
+// 注册Ionic图标
|
|
|
addIcons({
|
|
addIcons({
|
|
|
chevronBackOutline,
|
|
chevronBackOutline,
|
|
|
- trophyOutline,
|
|
|
|
|
|
|
+ trophy,
|
|
|
homeOutline,
|
|
homeOutline,
|
|
|
flameOutline,
|
|
flameOutline,
|
|
|
addCircleOutline,
|
|
addCircleOutline,
|
|
@@ -57,64 +66,94 @@ addIcons({
|
|
|
styleUrls: ['./recite-words.page.scss'],
|
|
styleUrls: ['./recite-words.page.scss'],
|
|
|
standalone: true,
|
|
standalone: true,
|
|
|
imports: [
|
|
imports: [
|
|
|
- IonContent, IonHeader, IonTitle, IonToolbar,
|
|
|
|
|
|
|
+ IonContent, IonHeader, IonToolbar,
|
|
|
CommonModule, FormsModule, IonButton, HttpClientModule,
|
|
CommonModule, FormsModule, IonButton, HttpClientModule,
|
|
|
IonSpinner, IonIcon, IonButtons, PronunciationButtonComponent,
|
|
IonSpinner, IonIcon, IonButtons, PronunciationButtonComponent,
|
|
|
WordDetailComponent,
|
|
WordDetailComponent,
|
|
|
],
|
|
],
|
|
|
- providers: [WordProcessingService, WordGroupService]
|
|
|
|
|
|
|
+ providers: [WordProcessingService, WordGroupService,WordDetailService]
|
|
|
})
|
|
})
|
|
|
export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
|
- @ViewChild(IonContent) ionContent!: IonContent;
|
|
|
|
|
- @ViewChild(PronunciationButtonComponent) pronunciationButton!: PronunciationButtonComponent;
|
|
|
|
|
-
|
|
|
|
|
- words: Word[] = [];
|
|
|
|
|
- currentWord: Word | null = null;
|
|
|
|
|
-
|
|
|
|
|
- // 模式1的状态变量(原模式)
|
|
|
|
|
- selectedOption: WordOption | null = null;
|
|
|
|
|
- isAnswered: boolean = false;
|
|
|
|
|
- isCorrect: boolean = false;
|
|
|
|
|
- isCorrectAnswerShown: boolean = false;
|
|
|
|
|
- showContinueButton: boolean = false;
|
|
|
|
|
- showWordDetail: boolean = false;
|
|
|
|
|
-
|
|
|
|
|
- // 模式2和模式3的状态变量
|
|
|
|
|
- mode2Options: WordOption[] = [];
|
|
|
|
|
- selectedMode2Option: WordOption | null = null;
|
|
|
|
|
- mode2Answered: boolean = false;
|
|
|
|
|
- mode2Correct: boolean = false;
|
|
|
|
|
-
|
|
|
|
|
- // 模式3的状态变量(词汇检测)
|
|
|
|
|
- mode3Answered: boolean = false;
|
|
|
|
|
-
|
|
|
|
|
- // 通用状态
|
|
|
|
|
- isLoading: boolean = true;
|
|
|
|
|
- isAmericanPronunciation: boolean = true;
|
|
|
|
|
|
|
+ // ==================== ViewChild 引用 ====================
|
|
|
|
|
+ @ViewChild(IonContent) ionContent!: IonContent; // 内容区域引用,用于滚动控制
|
|
|
|
|
+ @ViewChild(PronunciationButtonComponent) pronunciationButton!: PronunciationButtonComponent; // 发音按钮组件引用
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 核心数据 ====================
|
|
|
|
|
+ words: Word[] = []; // 所有加载的单词
|
|
|
|
|
+ currentWord: Word | null = null; // 当前正在学习的单词
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 模式1的状态变量 ====================
|
|
|
|
|
+ selectedOption: WordOption | null = null; // 用户选择的选项
|
|
|
|
|
+ isAnswered: boolean = false; // 是否已作答
|
|
|
|
|
+ isCorrect: boolean = false; // 回答是否正确
|
|
|
|
|
+ isCorrectAnswerShown: boolean = false; // 是否显示了正确答案
|
|
|
|
|
+ showContinueButton: boolean = false; // 是否显示继续按钮
|
|
|
|
|
+ showWordDetail: boolean = false; // 是否显示单词详情
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 模式2(第二次学习:听音辨义)的状态变量 ====================
|
|
|
|
|
+ mode2Options: WordOption[] = []; // 模式2的选项列表
|
|
|
|
|
+ selectedMode2Option: WordOption | null = null; // 模式2中用户选择的选项
|
|
|
|
|
+ mode2Answered: boolean = false; // 模式2是否已作答
|
|
|
|
|
+ mode2Correct: boolean = false; // 模式2回答是否正确
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 模式3(第三次学习:词汇检测)的状态变量 ====================
|
|
|
|
|
+ mode3Answered: boolean = false; // 模式3是否已作答
|
|
|
|
|
+
|
|
|
|
|
+ // ==================== 通用状态 ====================
|
|
|
|
|
+ isLoading: boolean = true; // 是否正在加载数据
|
|
|
|
|
+ isAmericanPronunciation: boolean = true; // 是否使用美式发音(true-美式,false-英式)
|
|
|
autoPlayEnabled: boolean = true; // 默认开启自动发音
|
|
autoPlayEnabled: boolean = true; // 默认开启自动发音
|
|
|
|
|
|
|
|
- // 完成页面数据
|
|
|
|
|
- showGroupCompleted: boolean = false;
|
|
|
|
|
- completedWordsCount: number = 0;
|
|
|
|
|
- studyTime: string = '0分钟';
|
|
|
|
|
- masteryRate: number = 0;
|
|
|
|
|
- groupStartTime: Date | null = null;
|
|
|
|
|
|
|
+ // ==================== 完成页面数据 ====================
|
|
|
|
|
+ showGroupCompleted: boolean = false; // 是否显示组完成页面
|
|
|
|
|
+ completedWordsCount: number = 0; // 已完成的单词数量
|
|
|
|
|
+ studyTime: string = '0分钟'; // 学习时间
|
|
|
|
|
+ masteryRate: number = 0; // 掌握率(百分比)
|
|
|
|
|
+ groupStartTime: Date | null = null; // 组开始学习的时间
|
|
|
|
|
+
|
|
|
|
|
+ completedWordsCountInGroup: number = 0; // 当前组中已完成3次学习的单词数
|
|
|
|
|
+ totalWordsInGroup: number = 0; // 当前组总单词数
|
|
|
|
|
+
|
|
|
|
|
+ wordOptions: WordOption[] | null = null; // 当前显示的选项列表
|
|
|
|
|
|
|
|
constructor(
|
|
constructor(
|
|
|
- private http: HttpClient,
|
|
|
|
|
- private router: Router,
|
|
|
|
|
- private cdr: ChangeDetectorRef,
|
|
|
|
|
- private alertController: AlertController,
|
|
|
|
|
- private wordProcessingService: WordProcessingService,
|
|
|
|
|
- private wordGroupService: WordGroupService
|
|
|
|
|
|
|
+ private http: HttpClient, // HTTP客户端,用于加载单词文件
|
|
|
|
|
+ private router: Router, // 路由服务,用于页面导航
|
|
|
|
|
+ private cdr: ChangeDetectorRef, // 变更检测引用,用于手动触发视图更新
|
|
|
|
|
+ private alertController: AlertController, // 提示框控制器
|
|
|
|
|
+ private wordProcessingService: WordProcessingService, // 单词处理服务(解析、生成选项等)
|
|
|
|
|
+ private wordGroupService: WordGroupService, // 单词组服务(管理学习进度)
|
|
|
|
|
+ private navCtrl: NavController, // 导航控制器,用于页面导航
|
|
|
|
|
+ private wordDetailService: WordDetailService, // 单词详情服务(获取单词详细信息)
|
|
|
) {}
|
|
) {}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Angular 生命周期钩子:组件初始化时调用
|
|
|
|
|
+ * 加载单词数据
|
|
|
|
|
+ */
|
|
|
ngOnInit() {
|
|
ngOnInit() {
|
|
|
console.log('背单词页面已初始化');
|
|
console.log('背单词页面已初始化');
|
|
|
- this.groupStartTime = new Date();
|
|
|
|
|
this.loadWords();
|
|
this.loadWords();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Ionic 生命周期钩子:每次进入页面时都会调用
|
|
|
|
|
+ * 用于处理页面重新进入时的逻辑
|
|
|
|
|
+ */
|
|
|
|
|
+ ionViewWillEnter() {
|
|
|
|
|
+ console.log('ionViewWillEnter 被调用');
|
|
|
|
|
+
|
|
|
|
|
+ // 如果当前显示完成页面,强制开始新组
|
|
|
|
|
+ if (this.showGroupCompleted) {
|
|
|
|
|
+ console.log('检测到学习完成页面,自动开始新组');
|
|
|
|
|
+ this.startNextGroup();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Angular 生命周期钩子:视图初始化完成后调用
|
|
|
|
|
+ * 滚动页面到顶部
|
|
|
|
|
+ */
|
|
|
ngAfterViewInit() {
|
|
ngAfterViewInit() {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
if (this.ionContent) {
|
|
if (this.ionContent) {
|
|
@@ -123,40 +162,30 @@ export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
|
}, 100);
|
|
}, 100);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Angular 生命周期钩子:组件销毁时调用
|
|
|
|
|
+ * 执行清理工作
|
|
|
|
|
+ */
|
|
|
ngOnDestroy() {
|
|
ngOnDestroy() {
|
|
|
- // 清理工作
|
|
|
|
|
|
|
+ // 清理工作(目前为空)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 公共辅助方法 ====================
|
|
// ==================== 公共辅助方法 ====================
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * 获取页面标题
|
|
|
|
|
- */
|
|
|
|
|
- getPageTitle(): string {
|
|
|
|
|
- if (this.showGroupCompleted) return '学习完成';
|
|
|
|
|
- if (this.currentWord) {
|
|
|
|
|
- switch (this.currentWord.studyCount) {
|
|
|
|
|
- case 0: return '单词学习';
|
|
|
|
|
- case 1: return '听音辨义';
|
|
|
|
|
- case 2: return '词汇检测';
|
|
|
|
|
- default: return '背单词';
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- return '背单词';
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取进度文本
|
|
* 获取进度文本
|
|
|
|
|
+ * 显示当前学习进度(如:5/20)
|
|
|
|
|
+ * @returns 进度文本字符串
|
|
|
*/
|
|
*/
|
|
|
getProgressText(): string {
|
|
getProgressText(): string {
|
|
|
- if (!this.wordGroupService.getCurrentGroup()) return '';
|
|
|
|
|
- const progress = this.wordGroupService.getProgressInfo();
|
|
|
|
|
- return `${progress.current}/${progress.total}`;
|
|
|
|
|
|
|
+ if (this.totalWordsInGroup === 0) return '';
|
|
|
|
|
+ return `${this.completedWordsCountInGroup}/${this.totalWordsInGroup}`;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取是否自动播放发音
|
|
* 获取是否自动播放发音
|
|
|
* 所有模式都需要自动发音
|
|
* 所有模式都需要自动发音
|
|
|
|
|
+ * @returns 是否自动播放
|
|
|
*/
|
|
*/
|
|
|
getAutoPlay(): boolean {
|
|
getAutoPlay(): boolean {
|
|
|
// 所有模式都需要自动发音
|
|
// 所有模式都需要自动发音
|
|
@@ -165,6 +194,8 @@ export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取提示文本
|
|
* 获取提示文本
|
|
|
|
|
+ * 根据当前学习模式返回相应的提示语
|
|
|
|
|
+ * @returns 提示文本字符串
|
|
|
*/
|
|
*/
|
|
|
getHintText(): string {
|
|
getHintText(): string {
|
|
|
if (!this.currentWord) return '先回想词义再选择,想不起来「看答案」';
|
|
if (!this.currentWord) return '先回想词义再选择,想不起来「看答案」';
|
|
@@ -173,7 +204,7 @@ export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
|
case 0:
|
|
case 0:
|
|
|
return '先回想词义再选择,想不起来「看答案」';
|
|
return '先回想词义再选择,想不起来「看答案」';
|
|
|
case 1:
|
|
case 1:
|
|
|
- return '根据发音选择正确的意思';
|
|
|
|
|
|
|
+ return '根据发音选择正确的意思,想不起来「看答案」';
|
|
|
case 2:
|
|
case 2:
|
|
|
return '根据单词判断是否认识';
|
|
return '根据单词判断是否认识';
|
|
|
default:
|
|
default:
|
|
@@ -183,140 +214,166 @@ export class ReciteWordsPage implements OnInit, AfterViewInit, OnDestroy {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 获取当前选项
|
|
* 获取当前选项
|
|
|
|
|
+ * 根据学习模式返回对应的选项数组
|
|
|
|
|
+ * @returns 选项数组
|
|
|
*/
|
|
*/
|
|
|
getCurrentOptions(): any[] {
|
|
getCurrentOptions(): any[] {
|
|
|
if (!this.currentWord) return [];
|
|
if (!this.currentWord) return [];
|
|
|
|
|
|
|
|
- // 模式2(studyCount === 2)不显示选项,而是显示认识/不认识按钮
|
|
|
|
|
- if (this.currentWord.studyCount > 2) {
|
|
|
|
|
|
|
+ // 模式2(studyCount === 2)不显示选项
|
|
|
|
|
+ if (this.currentWord.studyCount >= 2) {
|
|
|
return [];
|
|
return [];
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 模式0和1都使用单词的选项
|
|
|
|
|
- return this.currentWord.options || [];
|
|
|
|
|
|
|
+ const originalOptions = this.wordProcessingService.shuffleArray(this.currentWord.options);
|
|
|
|
|
+ return originalOptions;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 单词选项显示方法 ====================
|
|
// ==================== 单词选项显示方法 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取选项颜色
|
|
|
|
|
+ * @param option 选项对象
|
|
|
|
|
+ * @returns 颜色字符串
|
|
|
|
|
+ */
|
|
|
getOptionColor(option: WordOption): string {
|
|
getOptionColor(option: WordOption): string {
|
|
|
return 'medium';
|
|
return 'medium';
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取选项词性
|
|
|
|
|
+ * @param option 选项对象
|
|
|
|
|
+ * @returns 词性字符串
|
|
|
|
|
+ */
|
|
|
getOptionType(option: WordOption): string {
|
|
getOptionType(option: WordOption): string {
|
|
|
return option.type;
|
|
return option.type;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取选项显示文本
|
|
|
|
|
+ * @param option 选项对象
|
|
|
|
|
+ * @returns 显示文本
|
|
|
|
|
+ */
|
|
|
getOptionDisplayText(option: WordOption): string {
|
|
getOptionDisplayText(option: WordOption): string {
|
|
|
return option.displayText || this.wordProcessingService.truncateToSingleLine(option.text);
|
|
return option.displayText || this.wordProcessingService.truncateToSingleLine(option.text);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取选项英文单词
|
|
|
|
|
+ * @param option 选项对象
|
|
|
|
|
+ * @returns 英文释义
|
|
|
|
|
+ */
|
|
|
getOptionEnglish(option: WordOption): string {
|
|
getOptionEnglish(option: WordOption): string {
|
|
|
return option.english;
|
|
return option.english;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 模式0:第一次学习 ====================
|
|
// ==================== 模式0:第一次学习 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 选择选项(通用方法)
|
|
|
|
|
+ * 处理用户点击选项的事件,根据学习模式分发到不同的处理方法
|
|
|
|
|
+ * @param option 用户选择的选项
|
|
|
|
|
+ */
|
|
|
selectOption(option: WordOption) {
|
|
selectOption(option: WordOption) {
|
|
|
- if (this.isAnswered || this.isCorrectAnswerShown) return;
|
|
|
|
|
-
|
|
|
|
|
- this.selectedOption = option;
|
|
|
|
|
- this.isAnswered = true;
|
|
|
|
|
- this.isCorrect = option.isCorrect;
|
|
|
|
|
|
|
+ if (this.isAnswered || this.isCorrectAnswerShown) return;
|
|
|
|
|
+
|
|
|
|
|
+ this.selectedOption = option;
|
|
|
|
|
+ this.isAnswered = true;
|
|
|
|
|
+ this.isCorrect = option.isCorrect;
|
|
|
|
|
|
|
|
// 根据不同的学习模式处理不同的逻辑
|
|
// 根据不同的学习模式处理不同的逻辑
|
|
|
- const studyCount = this.currentWord?.studyCount || 0;
|
|
|
|
|
-
|
|
|
|
|
- switch (studyCount) {
|
|
|
|
|
- case 0: // 模式0:第一次学习
|
|
|
|
|
- this.handleMode0(option.isCorrect);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ const studyCount = this.currentWord?.studyCount || 0;
|
|
|
|
|
+
|
|
|
|
|
+ switch (studyCount) {
|
|
|
|
|
+ case 0: // 模式0:第一次学习
|
|
|
|
|
+ this.handleMode0(option.isCorrect);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case 1: // 模式1:第二次学习(听音辨义)
|
|
|
|
|
+ this.handleMode1(option.isCorrect);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ default:
|
|
|
|
|
+ console.warn('未知的学习模式:', studyCount);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理模式0(第一次学习)的选择结果
|
|
|
|
|
+ * @param isCorrect 回答是否正确
|
|
|
|
|
+ */
|
|
|
|
|
+ private handleMode0(isCorrect: boolean) {
|
|
|
|
|
+ if (isCorrect) {
|
|
|
|
|
+ console.log('模式0:回答正确!');
|
|
|
|
|
+ // 停留2秒后进入单词详情
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ this.showWordDetail = true;
|
|
|
|
|
+ this.scrollToTop(300);
|
|
|
|
|
+
|
|
|
|
|
+ //进入详情后自动发音
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.playPronunciation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 300); // 稍微延迟,确保页面切换完成
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
|
|
|
- case 1: // 模式1:第二次学习(听音辨义)
|
|
|
|
|
- //console.log(`${option.isCorrect }`);
|
|
|
|
|
- this.handleMode1(option.isCorrect);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log('模式0:回答错误!');
|
|
|
|
|
|
|
|
- default:
|
|
|
|
|
- console.warn('未知的学习模式:', studyCount);
|
|
|
|
|
- break;
|
|
|
|
|
|
|
+ // 显示正确答案
|
|
|
|
|
+ this.showCorrectAnswer();
|
|
|
|
|
|
|
|
|
|
+ // 模式0回答错误后,显示继续按钮
|
|
|
|
|
+ this.showContinueButton = true; // 只有错误时才显示继续按钮
|
|
|
|
|
+ this.isAnswered = true;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
-/**
|
|
|
|
|
- * 处理模式0(第一次学习)的选择结果
|
|
|
|
|
- */
|
|
|
|
|
-private handleMode0(isCorrect: boolean) {
|
|
|
|
|
- if (isCorrect) {
|
|
|
|
|
- console.log('模式0:回答正确!');
|
|
|
|
|
-// 停留2秒后进入单词详情
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.showWordDetail = true;
|
|
|
|
|
- this.scrollToTop(300);
|
|
|
|
|
-
|
|
|
|
|
- // 新增:进入详情后自动发音
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 处理模式1(第二次学习)的选择结果
|
|
|
|
|
+ * @param isCorrect 回答是否正确
|
|
|
|
|
+ */
|
|
|
|
|
+ private handleMode1(isCorrect: boolean) {
|
|
|
|
|
+ if (isCorrect) {
|
|
|
|
|
+ console.log('模式1:回答正确!');
|
|
|
|
|
+ this.showContinueButton = false; // 确保继续按钮不显示
|
|
|
|
|
+ // 停留2秒后进入单词详情
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.playPronunciation();
|
|
|
|
|
- }
|
|
|
|
|
- }, 300); // 稍微延迟,确保页面切换完成
|
|
|
|
|
- }, 2000);
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- console.log('模式0:回答错误!');
|
|
|
|
|
-
|
|
|
|
|
- // 显示正确答案
|
|
|
|
|
- this.showCorrectAnswer();
|
|
|
|
|
-
|
|
|
|
|
- // 模式0回答错误后,显示继续按钮
|
|
|
|
|
- this.showContinueButton = true; // 只有错误时才显示继续按钮
|
|
|
|
|
- this.isAnswered = true;
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-/**
|
|
|
|
|
- * 处理模式1(第二次学习)的选择结果
|
|
|
|
|
- */
|
|
|
|
|
-private handleMode1(isCorrect: boolean) {
|
|
|
|
|
- if (isCorrect) {
|
|
|
|
|
- console.log('模式1:回答正确!');
|
|
|
|
|
- this.showContinueButton = false; // 确保继续按钮不显示
|
|
|
|
|
-// 停留2秒后进入单词详情
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- this.showWordDetail = true;
|
|
|
|
|
- this.scrollToTop(300);
|
|
|
|
|
|
|
+ this.showWordDetail = true;
|
|
|
|
|
+ this.scrollToTop(300);
|
|
|
|
|
+
|
|
|
|
|
+ // 新增:进入详情后自动发音
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.playPronunciation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 350); // 稍微延迟,确保页面切换完成
|
|
|
|
|
+ }, 1500);
|
|
|
|
|
|
|
|
- // 新增:进入详情后自动发音
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.playPronunciation();
|
|
|
|
|
- }
|
|
|
|
|
- }, 350); // 稍微延迟,确保页面切换完成
|
|
|
|
|
- }, 2000);
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- console.log('模式1:回答错误!');
|
|
|
|
|
-
|
|
|
|
|
- // 显示正确答案
|
|
|
|
|
- this.showCorrectAnswer();
|
|
|
|
|
-
|
|
|
|
|
- // 模式1回答错误后,显示继续按钮
|
|
|
|
|
- this.showContinueButton = true; // 只有错误时才显示继续按钮
|
|
|
|
|
|
|
+ } else {
|
|
|
|
|
+ console.log('模式1:回答错误!');
|
|
|
|
|
+
|
|
|
|
|
+ // 显示正确答案
|
|
|
|
|
+ this.showCorrectAnswer();
|
|
|
|
|
+
|
|
|
|
|
+ // 模式1回答错误后,显示继续按钮
|
|
|
|
|
+ this.showContinueButton = true; // 只有错误时才显示继续按钮
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
-}
|
|
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 显示正确答案
|
|
* 显示正确答案
|
|
|
|
|
+ * 标记为已显示正确答案
|
|
|
*/
|
|
*/
|
|
|
showCorrectAnswer() {
|
|
showCorrectAnswer() {
|
|
|
this.isCorrectAnswerShown = true;
|
|
this.isCorrectAnswerShown = true;
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 显示答案 - 用户点击"看答案"
|
|
* 显示答案 - 用户点击"看答案"
|
|
|
|
|
+ * 处理用户主动查看答案的情况
|
|
|
*/
|
|
*/
|
|
|
showAnswer() {
|
|
showAnswer() {
|
|
|
if (this.isAnswered) return;
|
|
if (this.isAnswered) return;
|
|
@@ -335,26 +392,35 @@ private handleMode1(isCorrect: boolean) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
this.selectedOption = this.currentWord?.options.find((opt: WordOption) => opt.isCorrect) || null;
|
|
this.selectedOption = this.currentWord?.options.find((opt: WordOption) => opt.isCorrect) || null;
|
|
|
|
|
+
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ console.log('看答案后自动播放发音');
|
|
|
|
|
+ this.pronunciationButton.playPronunciation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 继续下一步
|
|
* 继续下一步
|
|
|
|
|
+ * 从选项选择页面进入单词详情页面
|
|
|
*/
|
|
*/
|
|
|
continueToNext() {
|
|
continueToNext() {
|
|
|
- // 模式0:显示单词详情
|
|
|
|
|
- this.showWordDetail = true;
|
|
|
|
|
- // 延迟播放发音
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.playPronunciation();
|
|
|
|
|
- }
|
|
|
|
|
- }, 100);
|
|
|
|
|
|
|
+ // 模式0:显示单词详情
|
|
|
|
|
+ this.showWordDetail = true;
|
|
|
|
|
+ // 延迟播放发音
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.playPronunciation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 模式2:第二次学习 ====================
|
|
// ==================== 模式2:第二次学习 ====================
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 准备模式二的选项
|
|
|
|
|
|
|
+ * 准备模式1的选项
|
|
|
|
|
+ * 为听音辨义模式准备选项列表
|
|
|
*/
|
|
*/
|
|
|
prepareMode2Options() {
|
|
prepareMode2Options() {
|
|
|
if (!this.currentWord) return;
|
|
if (!this.currentWord) return;
|
|
@@ -366,16 +432,18 @@ private handleMode1(isCorrect: boolean) {
|
|
|
// 如果没有选项,需要生成
|
|
// 如果没有选项,需要生成
|
|
|
const options = this.wordProcessingService.generateOptions(this.currentWord);
|
|
const options = this.wordProcessingService.generateOptions(this.currentWord);
|
|
|
this.mode2Options = options.map(option => ({
|
|
this.mode2Options = options.map(option => ({
|
|
|
- ...option,
|
|
|
|
|
|
|
+ ...option, // // 展开运算符:复制原对象的所有属性
|
|
|
displayText: option.displayText || this.wordProcessingService.truncateToSingleLine(option.text)
|
|
displayText: option.displayText || this.wordProcessingService.truncateToSingleLine(option.text)
|
|
|
}));
|
|
}));
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // ==================== 模式3:第三次学习(词汇检测) ====================
|
|
|
|
|
|
|
+ // ==================== 模式2:第三次学习(词汇检测) ====================
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 认识单词
|
|
* 认识单词
|
|
|
|
|
+ * 处理用户在词汇检测模式下的选择
|
|
|
|
|
+ * @param know true-认识该单词,false-不认识
|
|
|
*/
|
|
*/
|
|
|
recognizeWord(know: boolean) {
|
|
recognizeWord(know: boolean) {
|
|
|
if (this.mode3Answered) return;
|
|
if (this.mode3Answered) return;
|
|
@@ -384,56 +452,60 @@ private handleMode1(isCorrect: boolean) {
|
|
|
this.isAnswered = true;
|
|
this.isAnswered = true;
|
|
|
this.isCorrect = know; // 认识视为正确,不认识视为错误
|
|
this.isCorrect = know; // 认识视为正确,不认识视为错误
|
|
|
this.showWordDetail = true; // 直接显示单词详情
|
|
this.showWordDetail = true; // 直接显示单词详情
|
|
|
- // 延迟播放发音
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.playPronunciation();
|
|
|
|
|
- }
|
|
|
|
|
- }, 100);
|
|
|
|
|
|
|
+ // 延迟播放发音
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.playPronunciation();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100);
|
|
|
this.cdr.detectChanges(); // 强制更新视图,确保显示单词详情
|
|
this.cdr.detectChanges(); // 强制更新视图,确保显示单词详情
|
|
|
-
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 通用导航方法 ====================
|
|
// ==================== 通用导航方法 ====================
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 进入下一个学习阶段
|
|
* 进入下一个学习阶段
|
|
|
|
|
+ * 处理从一个单词到下一个单词的过渡
|
|
|
*/
|
|
*/
|
|
|
goToNextStudy() {
|
|
goToNextStudy() {
|
|
|
- // 在进入下一个单词前,更新当前单词的学习次数
|
|
|
|
|
- if (this.currentWord) {
|
|
|
|
|
- // 根据当前回答是否正确来更新学习次数
|
|
|
|
|
- // 注意:这里需要判断当前回答是否正确
|
|
|
|
|
- if (this.isCorrect !== undefined) {
|
|
|
|
|
- this.wordGroupService.updateWordStudyCount(this.currentWord!, this.isCorrect);
|
|
|
|
|
|
|
+ // 在进入下一个单词前,更新当前单词的学习次数
|
|
|
|
|
+ if (this.currentWord) {
|
|
|
|
|
+ // 根据当前回答是否正确来更新学习次数
|
|
|
|
|
+ if (this.isCorrect !== undefined) {
|
|
|
|
|
+ this.wordGroupService.updateWordStudyCount(this.currentWord!, this.isCorrect);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // 重置当前单词的状态
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // 重置状态
|
|
|
this.resetCurrentWordState();
|
|
this.resetCurrentWordState();
|
|
|
|
|
|
|
|
// 检查是否还有未完成的单词
|
|
// 检查是否还有未完成的单词
|
|
|
const hasNext = this.wordGroupService.nextWord();
|
|
const hasNext = this.wordGroupService.nextWord();
|
|
|
|
|
|
|
|
- if (hasNext) {
|
|
|
|
|
- this.currentWord = this.wordGroupService.getCurrentWord();
|
|
|
|
|
- this.initializeForCurrentWord();
|
|
|
|
|
- this.scrollToTop();
|
|
|
|
|
-
|
|
|
|
|
- // 手动触发重新播放发音
|
|
|
|
|
- setTimeout(() => {
|
|
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.replayAudio();
|
|
|
|
|
- }
|
|
|
|
|
- }, 100);
|
|
|
|
|
- } else {
|
|
|
|
|
- // 所有单词都完成了
|
|
|
|
|
- this.completeGroup();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ if (hasNext) {
|
|
|
|
|
+ this.currentWord = this.wordGroupService.getCurrentWord();
|
|
|
|
|
+ this.wordOptions = this.getCurrentOptions();
|
|
|
|
|
+ this.initializeForCurrentWord();
|
|
|
|
|
+ this.scrollToTop();
|
|
|
|
|
+
|
|
|
|
|
+ this.loadWordDetails();// 加载单词详情
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ // 手动触发重新播放发音
|
|
|
|
|
+ setTimeout(() => {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.replayAudio();
|
|
|
|
|
+ }
|
|
|
|
|
+ }, 100);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 所有单词都完成了
|
|
|
|
|
+ this.completeGroup();
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 重置当前单词状态
|
|
|
|
|
|
|
+ * 重置当前单词学习页面状态
|
|
|
|
|
+ * 清除所有与当前单词相关的状态变量
|
|
|
*/
|
|
*/
|
|
|
resetCurrentWordState() {
|
|
resetCurrentWordState() {
|
|
|
this.selectedOption = null;
|
|
this.selectedOption = null;
|
|
@@ -443,18 +515,19 @@ private handleMode1(isCorrect: boolean) {
|
|
|
this.showContinueButton = false;
|
|
this.showContinueButton = false;
|
|
|
this.showWordDetail = false;
|
|
this.showWordDetail = false;
|
|
|
|
|
|
|
|
- // 模式2状态
|
|
|
|
|
|
|
+ // 模式1状态
|
|
|
this.mode2Options = [];
|
|
this.mode2Options = [];
|
|
|
this.selectedMode2Option = null;
|
|
this.selectedMode2Option = null;
|
|
|
this.mode2Answered = false;
|
|
this.mode2Answered = false;
|
|
|
this.mode2Correct = false;
|
|
this.mode2Correct = false;
|
|
|
|
|
|
|
|
- // 模式3状态
|
|
|
|
|
|
|
+ // 模式2状态
|
|
|
this.mode3Answered = false;
|
|
this.mode3Answered = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 初始化当前单词
|
|
* 初始化当前单词
|
|
|
|
|
+ * 根据单词的学习次数准备相应的学习模式
|
|
|
*/
|
|
*/
|
|
|
initializeForCurrentWord() {
|
|
initializeForCurrentWord() {
|
|
|
if (!this.currentWord) return;
|
|
if (!this.currentWord) return;
|
|
@@ -462,13 +535,13 @@ private handleMode1(isCorrect: boolean) {
|
|
|
// 根据学习次数准备不同的模式
|
|
// 根据学习次数准备不同的模式
|
|
|
switch (this.currentWord.studyCount) {
|
|
switch (this.currentWord.studyCount) {
|
|
|
case 1:
|
|
case 1:
|
|
|
- // 模式二:听音辨义
|
|
|
|
|
|
|
+ // 模式1:听音辨义
|
|
|
this.prepareMode2Options();
|
|
this.prepareMode2Options();
|
|
|
console.log(`模式二初始化完成,单词: ${this.currentWord.word}`);
|
|
console.log(`模式二初始化完成,单词: ${this.currentWord.word}`);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
|
case 2:
|
|
case 2:
|
|
|
- // 模式三:词汇检测
|
|
|
|
|
|
|
+ // 模式2:词汇检测
|
|
|
console.log(`模式三初始化完成,单词: ${this.currentWord.word}`);
|
|
console.log(`模式三初始化完成,单词: ${this.currentWord.word}`);
|
|
|
break;
|
|
break;
|
|
|
|
|
|
|
@@ -477,10 +550,12 @@ private handleMode1(isCorrect: boolean) {
|
|
|
console.log(`模式一初始化完成,单词: ${this.currentWord.word}`);
|
|
console.log(`模式一初始化完成,单词: ${this.currentWord.word}`);
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
|
|
+ this.loadWordDetails();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 完成当前单词组
|
|
* 完成当前单词组
|
|
|
|
|
+ * 处理一组单词学习完成后的逻辑
|
|
|
*/
|
|
*/
|
|
|
completeGroup() {
|
|
completeGroup() {
|
|
|
this.showGroupCompleted = true;
|
|
this.showGroupCompleted = true;
|
|
@@ -507,6 +582,7 @@ private handleMode1(isCorrect: boolean) {
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* 初始化单词组
|
|
* 初始化单词组
|
|
|
|
|
+ * 创建新的单词组并开始学习
|
|
|
*/
|
|
*/
|
|
|
initializeGroup() {
|
|
initializeGroup() {
|
|
|
this.groupStartTime = new Date();
|
|
this.groupStartTime = new Date();
|
|
@@ -516,13 +592,19 @@ private handleMode1(isCorrect: boolean) {
|
|
|
const group = this.wordGroupService.createGroup(this.words);
|
|
const group = this.wordGroupService.createGroup(this.words);
|
|
|
if (group && group.words.length > 0) {
|
|
if (group && group.words.length > 0) {
|
|
|
this.currentWord = group.words[0];
|
|
this.currentWord = group.words[0];
|
|
|
|
|
+ this.wordOptions = this.getCurrentOptions();
|
|
|
this.initializeForCurrentWord();
|
|
this.initializeForCurrentWord();
|
|
|
|
|
+ this.loadWordDetails();
|
|
|
console.log(`开始学习组 #${group.id},第一个单词: "${this.currentWord.word}"`);
|
|
console.log(`开始学习组 #${group.id},第一个单词: "${this.currentWord.word}"`);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ==================== 单词加载方法 ====================
|
|
// ==================== 单词加载方法 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加载单词
|
|
|
|
|
+ * 从assets/words.txt文件加载单词数据
|
|
|
|
|
+ */
|
|
|
loadWords() {
|
|
loadWords() {
|
|
|
this.isLoading = true;
|
|
this.isLoading = true;
|
|
|
this.http.get('assets/words.txt', { responseType: 'text' }).subscribe({
|
|
this.http.get('assets/words.txt', { responseType: 'text' }).subscribe({
|
|
@@ -556,9 +638,7 @@ private handleMode1(isCorrect: boolean) {
|
|
|
|
|
|
|
|
if (this.words.length > 0) {
|
|
if (this.words.length > 0) {
|
|
|
console.log(`成功为 ${this.words.length} 个单词生成有效选项`);
|
|
console.log(`成功为 ${this.words.length} 个单词生成有效选项`);
|
|
|
-
|
|
|
|
|
- // 初始化单词组
|
|
|
|
|
- this.initializeGroup();
|
|
|
|
|
|
|
+ this.initializeGroup(); // 初始化单词组学习
|
|
|
} else {
|
|
} else {
|
|
|
console.warn('没有能够生成有效选项的单词');
|
|
console.warn('没有能够生成有效选项的单词');
|
|
|
this.currentWord = null;
|
|
this.currentWord = null;
|
|
@@ -583,6 +663,10 @@ private handleMode1(isCorrect: boolean) {
|
|
|
|
|
|
|
|
// ==================== 完成页面操作方法 ====================
|
|
// ==================== 完成页面操作方法 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 返回首页
|
|
|
|
|
+ * 显示确认对话框后返回首页
|
|
|
|
|
+ */
|
|
|
async goToHome() {
|
|
async goToHome() {
|
|
|
const alert = await this.alertController.create({
|
|
const alert = await this.alertController.create({
|
|
|
header: '确认返回',
|
|
header: '确认返回',
|
|
@@ -604,20 +688,39 @@ private handleMode1(isCorrect: boolean) {
|
|
|
await alert.present();
|
|
await alert.present();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 继续练习
|
|
|
|
|
+ * 导航到拼写练习页面
|
|
|
|
|
+ */
|
|
|
async continuePractice() {
|
|
async continuePractice() {
|
|
|
- const alert = await this.alertController.create({
|
|
|
|
|
- header: '功能开发中',
|
|
|
|
|
- message: '趁热打铁功能正在开发中,敬请期待!',
|
|
|
|
|
- buttons: ['确定']
|
|
|
|
|
- });
|
|
|
|
|
|
|
+ // 获取当前单词组
|
|
|
|
|
+ const currentGroup = this.wordGroupService.getCurrentGroup();
|
|
|
|
|
|
|
|
- await alert.present();
|
|
|
|
|
|
|
+ if (!currentGroup || !currentGroup.words || currentGroup.words.length === 0) {
|
|
|
|
|
+ console.log('没有可拼写的单词');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 导航到拼写页面,并传递当前单词组
|
|
|
|
|
+ this.router.navigate(['/spelling-practice'], {
|
|
|
|
|
+ state: {
|
|
|
|
|
+ wordGroup: currentGroup,
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 开始下一组
|
|
|
|
|
+ * 初始化新的单词组继续学习
|
|
|
|
|
+ */
|
|
|
startNextGroup() {
|
|
startNextGroup() {
|
|
|
this.initializeGroup();
|
|
this.initializeGroup();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 显示无更多单词提示
|
|
|
|
|
+ * 当所有单词都已学完时显示提示
|
|
|
|
|
+ */
|
|
|
async showNoMoreWordsAlert() {
|
|
async showNoMoreWordsAlert() {
|
|
|
const alert = await this.alertController.create({
|
|
const alert = await this.alertController.create({
|
|
|
header: '恭喜完成!',
|
|
header: '恭喜完成!',
|
|
@@ -650,11 +753,20 @@ private handleMode1(isCorrect: boolean) {
|
|
|
|
|
|
|
|
// ==================== 辅助方法 ====================
|
|
// ==================== 辅助方法 ====================
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 发音切换处理
|
|
|
|
|
+ * 处理英式/美式发音切换事件
|
|
|
|
|
+ * @param isAmerican true-美式发音,false-英式发音
|
|
|
|
|
+ */
|
|
|
onPronunciationToggled(isAmerican: boolean) {
|
|
onPronunciationToggled(isAmerican: boolean) {
|
|
|
console.log(`接收到发音切换事件: ${isAmerican ? '美式' : '英式'}`);
|
|
console.log(`接收到发音切换事件: ${isAmerican ? '美式' : '英式'}`);
|
|
|
this.isAmericanPronunciation = isAmerican;
|
|
this.isAmericanPronunciation = isAmerican;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 滚动到页面顶部
|
|
|
|
|
+ * @param duration 滚动动画持续时间(毫秒)
|
|
|
|
|
+ */
|
|
|
scrollToTop(duration: number = 0) {
|
|
scrollToTop(duration: number = 0) {
|
|
|
setTimeout(() => {
|
|
setTimeout(() => {
|
|
|
if (this.ionContent) {
|
|
if (this.ionContent) {
|
|
@@ -663,6 +775,10 @@ private handleMode1(isCorrect: boolean) {
|
|
|
}, duration === 0 ? 50 : 0);
|
|
}, duration === 0 ? 50 : 0);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 重置当前单词
|
|
|
|
|
+ * 将当前单词的学习次数重置为0(调试用)
|
|
|
|
|
+ */
|
|
|
resetCurrentWord() {
|
|
resetCurrentWord() {
|
|
|
if (this.currentWord) {
|
|
if (this.currentWord) {
|
|
|
this.currentWord.studyCount = 0;
|
|
this.currentWord.studyCount = 0;
|
|
@@ -672,21 +788,67 @@ private handleMode1(isCorrect: boolean) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 返回上一页
|
|
|
|
|
+ */
|
|
|
goBack() {
|
|
goBack() {
|
|
|
this.router.navigate(['/tabs/tab1']);
|
|
this.router.navigate(['/tabs/tab1']);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 播放选项单词的发音(用于模板点击)
|
|
|
|
|
|
|
+ * 播放选项单词的发音
|
|
|
|
|
+ * @param option 选项对象
|
|
|
|
|
+ */
|
|
|
|
|
+ playOptionSound(option: WordOption): void {
|
|
|
|
|
+ if (option.english) {
|
|
|
|
|
+ if (this.pronunciationButton) {
|
|
|
|
|
+ this.pronunciationButton.playPronunciation(option.english);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 加载当前单词的详细信息
|
|
|
|
|
+ * 包括例句、短语、派生词、近义词
|
|
|
*/
|
|
*/
|
|
|
-playOptionSound(option: WordOption): void {
|
|
|
|
|
- // 正确选项不发音
|
|
|
|
|
- if (option.isCorrect) return;
|
|
|
|
|
|
|
+private loadWordDetails(): void {
|
|
|
|
|
+ if (!this.currentWord) return;
|
|
|
|
|
|
|
|
- if (option.english) {
|
|
|
|
|
- if (this.pronunciationButton) {
|
|
|
|
|
- this.pronunciationButton.playPronunciation(option.english);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 检查是否已经有详细信息(避免重复请求)
|
|
|
|
|
+ if (this.currentWord.phrases ||
|
|
|
|
|
+ this.currentWord.relWords ||
|
|
|
|
|
+ this.currentWord.sentences ||
|
|
|
|
|
+ this.currentWord.synonyms) {
|
|
|
|
|
+ console.log(`单词 "${this.currentWord.word}" 已有详细信息,跳过请求`);
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`获取单词 "${this.currentWord.word}" 的详细信息...`);
|
|
|
|
|
+
|
|
|
|
|
+ // 显示加载状态(可选)
|
|
|
|
|
+ this.isLoading = true;
|
|
|
|
|
+
|
|
|
|
|
+ this.wordDetailService.fetchWordDetails(this.currentWord.word).subscribe({
|
|
|
|
|
+ next: (details) => {
|
|
|
|
|
+ console.log(`单词 "${this.currentWord?.word}" 详细信息获取成功`);
|
|
|
|
|
+
|
|
|
|
|
+ if (this.currentWord) {
|
|
|
|
|
+ // 更新当前单词的详细信息
|
|
|
|
|
+ this.currentWord.phrases = details.phrases;
|
|
|
|
|
+ this.currentWord.relWords = details.relWords;
|
|
|
|
|
+ this.currentWord.sentences = details.sentences;
|
|
|
|
|
+ this.currentWord.synonyms = details.synonyms;
|
|
|
|
|
+
|
|
|
|
|
+ // 手动触发变更检测
|
|
|
|
|
+ this.cdr.detectChanges();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ this.isLoading = false;
|
|
|
|
|
+ },
|
|
|
|
|
+ error: (error) => {
|
|
|
|
|
+ console.error(`获取单词 "${this.currentWord?.word}" 详细信息失败:`, error);
|
|
|
|
|
+ this.isLoading = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ });
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|