|
@@ -1,4 +1,5 @@
|
|
|
import { DropdownDirective } from '../../shared/dropdown.directive';
|
|
import { DropdownDirective } from '../../shared/dropdown.directive';
|
|
|
|
|
+import { beijingDate } from '../../core/appointment-time';
|
|
|
import { CommonModule } from '@angular/common';
|
|
import { CommonModule } from '@angular/common';
|
|
|
import { ChangeDetectionStrategy, Component, computed, inject, NgZone, OnDestroy, OnInit, signal } from '@angular/core';
|
|
import { ChangeDetectionStrategy, Component, computed, inject, NgZone, OnDestroy, OnInit, signal } from '@angular/core';
|
|
|
import { FormsModule } from '@angular/forms';
|
|
import { FormsModule } from '@angular/forms';
|
|
@@ -70,13 +71,13 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
|
|
|
readonly schedules = signal<Item[]>([]);
|
|
readonly schedules = signal<Item[]>([]);
|
|
|
readonly scheduleFilter = signal<ScheduleFilter>('all');
|
|
readonly scheduleFilter = signal<ScheduleFilter>('all');
|
|
|
readonly scheduleRange = signal<ScheduleRange>('day');
|
|
readonly scheduleRange = signal<ScheduleRange>('day');
|
|
|
|
|
+ readonly now = signal(Date.now());
|
|
|
readonly selectedDate = signal(this.today());
|
|
readonly selectedDate = signal(this.today());
|
|
|
readonly selectedStudent = signal('all');
|
|
readonly selectedStudent = signal('all');
|
|
|
readonly allStudentCount = computed(() => this.studentOptions().reduce((sum, student) => sum + student.count, 0));
|
|
readonly allStudentCount = computed(() => this.studentOptions().reduce((sum, student) => sum + student.count, 0));
|
|
|
readonly historyMonth = signal('all');
|
|
readonly historyMonth = signal('all');
|
|
|
readonly historyStudentQuery = signal('');
|
|
readonly historyStudentQuery = signal('');
|
|
|
readonly calendarMonth = signal(this.firstOfMonth(new Date()));
|
|
readonly calendarMonth = signal(this.firstOfMonth(new Date()));
|
|
|
- readonly now = signal(Date.now());
|
|
|
|
|
readonly loading = signal(false);
|
|
readonly loading = signal(false);
|
|
|
readonly liveChecking = signal(false);
|
|
readonly liveChecking = signal(false);
|
|
|
readonly refreshedAt = signal('');
|
|
readonly refreshedAt = signal('');
|
|
@@ -360,7 +361,9 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
|
|
|
void this.router.navigate(['/pages/shop/stu_get_order'], { queryParams: { id: this.scheduleId(item) }, state: { appointmentSnapshot: item } });
|
|
void this.router.navigate(['/pages/shop/stu_get_order'], { queryParams: { id: this.scheduleId(item) }, state: { appointmentSnapshot: item } });
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- this.loadStudentAndNavigate(item, '/pages/shop/get_order', 'id');
|
|
|
|
|
|
|
+ // The verified detail loads the appointment's student; a profile request must not delay opening it.
|
|
|
|
|
+ this.storeAppointmentSnapshot(item);
|
|
|
|
|
+ void this.router.navigate(['/pages/shop/get_order'], { queryParams: { id: this.scheduleId(item) }, state: { appointmentSnapshot: item } });
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
clearScheduleFilters(): void {
|
|
clearScheduleFilters(): void {
|
|
@@ -533,8 +536,6 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
|
|
|
|
|
|
|
|
private isOverdueUnfinished(item: Item): boolean {
|
|
private isOverdueUnfinished(item: Item): boolean {
|
|
|
if (!this.isPendingRaw(item)) return false;
|
|
if (!this.isPendingRaw(item)) return false;
|
|
|
- const end = this.lessonEnd(item);
|
|
|
|
|
- if (end) return end.getTime() < this.now();
|
|
|
|
|
const date = this.itemDate(item);
|
|
const date = this.itemDate(item);
|
|
|
return Boolean(date && date < this.today());
|
|
return Boolean(date && date < this.today());
|
|
|
}
|
|
}
|
|
@@ -553,24 +554,6 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
|
|
|
return new Date(year, month - 1, day, time.hour, time.minute);
|
|
return new Date(year, month - 1, day, time.hour, time.minute);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private lessonEnd(item: Item): Date | null {
|
|
|
|
|
- const start = this.lessonStart(item);
|
|
|
|
|
- if (!start) return null;
|
|
|
|
|
- return new Date(start.getTime() + this.lessonMinutes(item) * 60_000);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- private lessonMinutes(item: Item): number {
|
|
|
|
|
- if (Number(item['durationMinutes'])>0) return Number(item['durationMinutes']);
|
|
|
|
|
- const text = `${item['Title'] ?? ''} ${item['Title2'] ?? ''} ${item['Subtitle'] ?? ''}`;
|
|
|
|
|
- const matched = text.match(/(\d{1,3})\s*分钟/);
|
|
|
|
|
- if (matched) return Number(matched[1]);
|
|
|
|
|
- const type = Number(item['dslx'] ?? 0);
|
|
|
|
|
- if (type === 1) return 30;
|
|
|
|
|
- if (type === 2) return 60;
|
|
|
|
|
- if (type === 3) return 60;
|
|
|
|
|
- return 0;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
private timeParts(value: unknown): { hour: number; minute: number } | null {
|
|
private timeParts(value: unknown): { hour: number; minute: number } | null {
|
|
|
const matched = String(value ?? '').match(/(?:^|\s)(\d{1,2}):(\d{2})/);
|
|
const matched = String(value ?? '').match(/(?:^|\s)(\d{1,2}):(\d{2})/);
|
|
|
if (!matched) return null;
|
|
if (!matched) return null;
|
|
@@ -643,8 +626,7 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
today(): string {
|
|
today(): string {
|
|
|
- const now = new Date();
|
|
|
|
|
- return this.dateKey(now);
|
|
|
|
|
|
|
+ return beijingDate(this.now());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
tomorrow(): string {
|
|
tomorrow(): string {
|