|
@@ -127,7 +127,7 @@ export function scheduleCoachBusy(
|
|
|
|
|
|
|
|
@Component({ selector:'app-operations-schedule', standalone:true, imports: [AnchoredMenuDirective, DropdownDirective, CommonModule,FormsModule,LucideAngularModule,OperationsDateFilterComponent], templateUrl:'./operations-schedule.component.html', styleUrls:['./operations-professional.scss','./operations-schedule.component.scss'], changeDetection:ChangeDetectionStrategy.OnPush })
|
|
@Component({ selector:'app-operations-schedule', standalone:true, imports: [AnchoredMenuDirective, DropdownDirective, CommonModule,FormsModule,LucideAngularModule,OperationsDateFilterComponent], templateUrl:'./operations-schedule.component.html', styleUrls:['./operations-professional.scss','./operations-schedule.component.scss'], changeDetection:ChangeDetectionStrategy.OnPush })
|
|
|
export class OperationsScheduleComponent implements OnInit, OnDestroy {
|
|
export class OperationsScheduleComponent implements OnInit, OnDestroy {
|
|
|
- readonly data=signal<ScheduleCalendarData|null>(null); readonly loading=signal(true); readonly saving=signal(false); readonly error=signal(''); readonly message=signal(''); readonly drawerOpen=signal(false); readonly feedback=signal<Record<string,unknown>|null>(null); readonly editing=signal<ScheduleAppointment|null>(null); readonly mode=signal<'coach'|'time'>('coach'); readonly view=signal<'day'|'week'|'list'>('day'); readonly date=signal(localDateKey(new Date())); readonly coachFilter=signal(0);
|
|
|
|
|
|
|
+ readonly data=signal<ScheduleCalendarData|null>(null); readonly loading=signal(true); readonly saving=signal(false); readonly error=signal(''); readonly message=signal(''); readonly drawerOpen=signal(false); readonly feedback=signal<Record<string,unknown>|null>(null); readonly detail=signal<ScheduleAppointment|null>(null); readonly cancelReason=signal(''); readonly detailError=signal(''); readonly editing=signal<ScheduleAppointment|null>(null); readonly mode=signal<'coach'|'time'>('coach'); readonly view=signal<'day'|'week'|'list'>('day'); readonly date=signal(localDateKey(new Date())); readonly coachFilter=signal(0);
|
|
|
readonly bindingId=signal(''); private readonly route=inject(ActivatedRoute); readonly studentId=signal(0); readonly courseId=signal(0); readonly coachId=signal(0); readonly classType=signal(1); readonly durationMinutes=signal(30); readonly deliveryMethod=signal('线上'); readonly startTime=signal('19:00'); readonly recurrence=signal('once'); readonly occurrences=signal(1); readonly reason=signal('运营排课'); readonly preview=signal<Record<string,unknown>|null>(null); readonly checking=signal(false);
|
|
readonly bindingId=signal(''); private readonly route=inject(ActivatedRoute); readonly studentId=signal(0); readonly courseId=signal(0); readonly coachId=signal(0); readonly classType=signal(1); readonly durationMinutes=signal(30); readonly deliveryMethod=signal('线上'); readonly startTime=signal('19:00'); readonly recurrence=signal('once'); readonly occurrences=signal(1); readonly reason=signal('运营排课'); readonly preview=signal<Record<string,unknown>|null>(null); readonly checking=signal(false);
|
|
|
readonly memberSearch=signal(''); readonly courseSearch=signal(''); readonly coachSearch=signal(''); readonly selectedMemberObjectId=signal(''); readonly activeSearch=signal<SearchField|null>(null); readonly scheduleSearchInput=signal(''); readonly statusFilterInput=signal<ScheduleStatusFilter>('all'); readonly scheduleSearch=signal(''); readonly statusFilter=signal<ScheduleStatusFilter>('all'); readonly searching=signal(false);
|
|
readonly memberSearch=signal(''); readonly courseSearch=signal(''); readonly coachSearch=signal(''); readonly selectedMemberObjectId=signal(''); readonly activeSearch=signal<SearchField|null>(null); readonly scheduleSearchInput=signal(''); readonly statusFilterInput=signal<ScheduleStatusFilter>('all'); readonly scheduleSearch=signal(''); readonly statusFilter=signal<ScheduleStatusFilter>('all'); readonly searching=signal(false);
|
|
|
readonly icons={CalendarDays,CheckCircle2,ChevronLeft,ChevronRight,CircleAlert,LoaderCircle,Plus,RefreshCw,RotateCcw,Search,X}; private readonly operations=inject(OperationsService); private readonly liveRefresh=inject(OperationsLiveRefreshService);
|
|
readonly icons={CalendarDays,CheckCircle2,ChevronLeft,ChevronRight,CircleAlert,LoaderCircle,Plus,RefreshCw,RotateCcw,Search,X}; private readonly operations=inject(OperationsService); private readonly liveRefresh=inject(OperationsLiveRefreshService);
|
|
@@ -150,6 +150,21 @@ export class OperationsScheduleComponent implements OnInit, OnDestroy {
|
|
|
statusTone(item:ScheduleAppointment):ScheduleStatusTone{return scheduleStatusTone(item);}
|
|
statusTone(item:ScheduleAppointment):ScheduleStatusTone{return scheduleStatusTone(item);}
|
|
|
statusDisplayLabel(item:ScheduleAppointment):string{return scheduleStatusLabel(item);}
|
|
statusDisplayLabel(item:ScheduleAppointment):string{return scheduleStatusLabel(item);}
|
|
|
rowActions(item:ScheduleAppointment):ReturnType<typeof scheduleRowActions>{return scheduleRowActions(item);}
|
|
rowActions(item:ScheduleAppointment):ReturnType<typeof scheduleRowActions>{return scheduleRowActions(item);}
|
|
|
|
|
+ openDetails(item:ScheduleAppointment):void{this.detail.set(item);this.cancelReason.set('');this.detailError.set('');}
|
|
|
|
|
+ closeDetails():void{if(this.saving())return;this.detail.set(null);this.cancelReason.set('');this.detailError.set('');}
|
|
|
|
|
+ editFromDetails(item:ScheduleAppointment):void{this.closeDetails();this.openEdit(item);}
|
|
|
|
|
+ async cancelFromDetails():Promise<void>{
|
|
|
|
|
+ const item=this.detail(),reason=this.cancelReason().trim();
|
|
|
|
|
+ if(!item||this.saving())return;
|
|
|
|
|
+ if(!this.rowActions(item).canCancel){this.detailError.set(item.readOnly?'该排课仍由旧业务系统维护,新后台尚不能安全写回取消状态':'当前状态不能取消排课');return;}
|
|
|
|
|
+ if(!reason){this.detailError.set('请填写取消原因');return;}
|
|
|
|
|
+ this.saving.set(true);this.detailError.set('');
|
|
|
|
|
+ try{
|
|
|
|
|
+ await this.operations.mutate('ops/appointments/cancel',item.targetId,reason,{},item.updatedAt);
|
|
|
|
|
+ this.detail.set(null);this.message.set('排课已取消');await this.load();
|
|
|
|
|
+ }catch(error){this.detailError.set(error instanceof Error?error.message:'取消排课失败');}
|
|
|
|
|
+ finally{this.saving.set(false);}
|
|
|
|
|
+ }
|
|
|
ngOnInit():void{void this.load().then(()=>{const id=Number(this.route.snapshot.queryParamMap.get('studentId'));const member=this.data()?.members.find(m=>m.userId===id);if(member){this.openCreate();this.chooseMember(member);}});this.stopLiveRefresh=this.liveRefresh.watch(['courses','appointments','account'],()=>{if(this.loading()||this.saving()||this.searching())return false;void this.load(true);return true;});}
|
|
ngOnInit():void{void this.load().then(()=>{const id=Number(this.route.snapshot.queryParamMap.get('studentId'));const member=this.data()?.members.find(m=>m.userId===id);if(member){this.openCreate();this.chooseMember(member);}});this.stopLiveRefresh=this.liveRefresh.watch(['courses','appointments','account'],()=>{if(this.loading()||this.saving()||this.searching())return false;void this.load(true);return true;});}
|
|
|
ngOnDestroy():void{this.stopLiveRefresh?.();}
|
|
ngOnDestroy():void{this.stopLiveRefresh?.();}
|
|
|
range():{from:string;to:string}{const from=new Date(`${this.date()}T00:00:00`);const to=new Date(from);if(this.view()==='week')to.setDate(to.getDate()+6);return{from:localDateKey(from),to:localDateKey(to)};}
|
|
range():{from:string;to:string}{const from=new Date(`${this.date()}T00:00:00`);const to=new Date(from);if(this.view()==='week')to.setDate(to.getDate()+6);return{from:localDateKey(from),to:localDateKey(to)};}
|