|
|
@@ -80,6 +80,12 @@ interface ExamAnswer {
|
|
|
result: 0 | 1 | 2;
|
|
|
}
|
|
|
|
|
|
+interface MemoryStudentOption {
|
|
|
+ id: string;
|
|
|
+ name: string;
|
|
|
+ taskCount: number;
|
|
|
+}
|
|
|
+
|
|
|
const WORD_CATALOG_CATEGORIES = [
|
|
|
{ label: '小学', pid: 8 },
|
|
|
{ label: '初中', pid: 9 },
|
|
|
@@ -133,6 +139,7 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
readonly seen = signal<Set<string>>(new Set());
|
|
|
readonly recordRevealed = signal<Set<string>>(new Set());
|
|
|
readonly calendarItems = signal<SourceItem[]>([]);
|
|
|
+ readonly memoryStudentId = signal('');
|
|
|
readonly memoryMonth = signal(new Date(new Date().getFullYear(), new Date().getMonth(), 1, 12));
|
|
|
readonly memorySelectedDate = signal('');
|
|
|
readonly orderInfo = signal<SourceItem>({});
|
|
|
@@ -208,24 +215,40 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
? ((this.wordPreviewPage() - 1) * this.wordPreviewPageSize) + 1
|
|
|
: 0);
|
|
|
readonly wordPreviewRangeEnd = computed(() => Math.min(this.wordPreviewPage() * this.wordPreviewPageSize, this.wordPreviewTotal()));
|
|
|
- readonly memoryView = computed(() => buildAntiForgetView(this.calendarItems()));
|
|
|
+ readonly memoryStudents = computed(() => {
|
|
|
+ const students = new Map<string, MemoryStudentOption>();
|
|
|
+ for (const item of this.calendarItems()) {
|
|
|
+ const id = String(item['yhid'] ?? '').trim();
|
|
|
+ if (!id) continue;
|
|
|
+ const current = students.get(id);
|
|
|
+ if (current) current.taskCount += 1;
|
|
|
+ else students.set(id, { id, name: this.calendarStudent(item) || `学员 ${id}`, taskCount: 1 });
|
|
|
+ }
|
|
|
+ return [...students.values()].sort((left, right) => left.name.localeCompare(right.name, 'zh-CN'));
|
|
|
+ });
|
|
|
+ readonly memorySelectedStudentName = computed(() => this.memoryStudents().find((student) => student.id === this.memoryStudentId())?.name || '全部学员');
|
|
|
+ readonly memoryFilteredItems = computed(() => {
|
|
|
+ const studentId = this.memoryStudentId();
|
|
|
+ return studentId ? this.calendarItems().filter((item) => String(item['yhid'] ?? '') === studentId) : this.calendarItems();
|
|
|
+ });
|
|
|
+ readonly memoryView = computed(() => buildAntiForgetView(this.memoryFilteredItems()));
|
|
|
readonly memorySummary = computed(() => this.memoryView().summary);
|
|
|
readonly memoryCalendar = computed(() => buildAntiForgetCalendar(
|
|
|
- this.calendarItems(),
|
|
|
+ this.memoryFilteredItems(),
|
|
|
this.memoryMonth(),
|
|
|
this.memorySelectedDate(),
|
|
|
));
|
|
|
- readonly memorySelectedTasks = computed(() => antiForgetTasksOnDate(this.calendarItems(), this.memorySelectedDate()));
|
|
|
+ readonly memorySelectedTasks = computed(() => antiForgetTasksOnDate(this.memoryFilteredItems(), this.memorySelectedDate()));
|
|
|
readonly memorySelectedLabel = computed(() => {
|
|
|
const value = this.memorySelectedDate();
|
|
|
if (!value) return '';
|
|
|
const [year, month, day] = value.split('-').map(Number);
|
|
|
return new Intl.DateTimeFormat('zh-CN', { month: 'long', day: 'numeric', weekday: 'short' }).format(new Date(year, month - 1, day, 12));
|
|
|
});
|
|
|
- readonly memoryCompletedCount = computed(() => this.calendarItems().filter(antiForgetCompleted).length);
|
|
|
- readonly memoryDueCount = computed(() => this.calendarItems().filter((item) => !antiForgetCompleted(item) && antiForgetDate(item) <= this.dateOnly()).length);
|
|
|
- readonly memoryProgress = computed(() => this.calendarItems().length
|
|
|
- ? Math.round((this.memoryCompletedCount() / this.calendarItems().length) * 100)
|
|
|
+ readonly memoryCompletedCount = computed(() => this.memoryFilteredItems().filter(antiForgetCompleted).length);
|
|
|
+ readonly memoryDueCount = computed(() => this.memoryFilteredItems().filter((item) => !antiForgetCompleted(item) && antiForgetDate(item) <= this.dateOnly()).length);
|
|
|
+ readonly memoryProgress = computed(() => this.memoryFilteredItems().length
|
|
|
+ ? Math.round((this.memoryCompletedCount() / this.memoryFilteredItems().length) * 100)
|
|
|
: 0);
|
|
|
readonly progress = computed(() => {
|
|
|
const total = this.isMatchingPage ? this.words().length : this.words().length || this.questions().length;
|
|
|
@@ -912,6 +935,14 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
this.memorySelectedDate.set(today);
|
|
|
}
|
|
|
|
|
|
+ selectMemoryStudent(event: Event): void {
|
|
|
+ this.memoryStudentId.set((event.target as HTMLSelectElement).value);
|
|
|
+ const selectedDate = nearestAntiForgetDate(this.memoryFilteredItems());
|
|
|
+ const [year, month] = selectedDate.split('-').map(Number);
|
|
|
+ this.memorySelectedDate.set(selectedDate);
|
|
|
+ this.memoryMonth.set(new Date(year, month - 1, 1, 12));
|
|
|
+ }
|
|
|
+
|
|
|
memoryTaskStatus(item: SourceItem): string {
|
|
|
if (this.calendarCompleted(item)) return '已完成';
|
|
|
return this.calendarReady(item) ? '待复习' : '未到期';
|
|
|
@@ -1734,6 +1765,7 @@ export class LearningPageComponent implements OnInit, OnDestroy {
|
|
|
this.seen.set(new Set());
|
|
|
this.recordRevealed.set(new Set());
|
|
|
this.calendarItems.set([]);
|
|
|
+ this.memoryStudentId.set('');
|
|
|
this.examStarted.set(false);
|
|
|
this.examSubmitted.set(false);
|
|
|
}
|