Przeglądaj źródła

将陪练记录学员搜索改为老师关联学员下拉筛选

彭峰 5 dni temu
rodzic
commit
d4cfb593e6

+ 12 - 8
projects/xiaoshu-mobile/src/app/core/home-learning-modules.integration.spec.ts

@@ -217,15 +217,16 @@ class LearningModulesApiService {
         { GeneralID: 903, bxrq: '2099-01-01 00:00:00', sdsd: '18:00', Title: '未来计划', plxm: '王老师', dszt: 0 },
       ];
       const historySchedules = [
-        { GeneralID: 911, bxrq: '2026-07-14 00:00:00', sdsd: '22:00', Title: '谢晨晨(60分钟练习)', plxm: '张老师', dszt: 30 },
-        { GeneralID: 912, bxrq: '2026-07-14 00:00:00', sdsd: '17:00', Title: '谢谢(60分钟练习)', plxm: '张老师', dszt: 30 },
-        { GeneralID: 913, bxrq: '2026-03-09 00:00:00', sdsd: '10:00', Title: '花花(60分钟练习)', plxm: '张老师', dszt: 30 },
-        { GeneralID: 914, bxrq: '2026-01-18 00:00:00', sdsd: '16:30', Title: '小赵(60分钟练习)', plxm: '张老师', dszt: 30 },
-        { GeneralID: 915, bxrq: '2026-01-18 00:00:00', sdsd: '16:00', Title: '小黄(60分钟练习)', plxm: '张老师', dszt: 30 },
+        { GeneralID: 911, szyh:100, bxrq: '2026-07-14 00:00:00', sdsd: '22:00', Title: '谢晨晨(60分钟练习)', plxm: '张老师', dszt: 30 },
+        { GeneralID: 912, szyh:101, bxrq: '2026-07-14 00:00:00', sdsd: '17:00', Title: '谢谢(60分钟练习)', plxm: '张老师', dszt: 30 },
+        { GeneralID: 913, szyh:102, bxrq: '2026-03-09 00:00:00', sdsd: '10:00', Title: '花花(60分钟练习)', plxm: '张老师', dszt: 30 },
+        { GeneralID: 914, szyh:103, bxrq: '2026-01-18 00:00:00', sdsd: '16:30', Title: '小赵(60分钟练习)', plxm: '张老师', dszt: 30 },
+        { GeneralID: 915, szyh:104, bxrq: '2026-01-18 00:00:00', sdsd: '16:00', Title: '小黄(60分钟练习)', plxm: '张老师', dszt: 30 },
       ];
       const rangeStart = String(params['rangeStart'] ?? '');
       const rangeEnd = String(params['rangeEnd'] ?? '');
       return this.result<T>({
+        studentOptions: params['history'] ? [{id:'100',name:'谢晨晨',count:1},{id:'101',name:'谢谢',count:1},{id:'102',name:'花花',count:1},{id:'103',name:'小赵',count:1},{id:'104',name:'小黄',count:1}] : [],
         courses: [
           { GeneralID: 801, id: 701, kcid: 801, Title: '初中英语|七年级上册@同步词汇' },
           { GeneralID: 802, id: 702, Title2: '【初中英语】阅读训练', syjd: '{"811":"811@Unit 1@1"}' },
@@ -1529,9 +1530,12 @@ describe('home learning modules', () => {
     expect(harness.routeNativeElement?.querySelectorAll('.schedule-list article').length).toBe(5);
     monthFilter.value = '2026-03';
     monthFilter.dispatchEvent(new Event('change'));
-    const studentSearch = harness.routeNativeElement?.querySelector('[aria-label="按学生姓名筛选陪练记录"]') as HTMLInputElement;
-    studentSearch.value = '花';
-    studentSearch.dispatchEvent(new Event('input'));
+    const studentSelect = harness.routeNativeElement?.querySelector('select[aria-label="按学员筛选陪练记录"]') as HTMLSelectElement;
+    expect(harness.routeNativeElement?.querySelector('input[type="search"]')).toBeNull();
+    studentSelect.value = '102';
+    studentSelect.dispatchEvent(new Event('change'));
+    expect(memoryApi.lastScheduleParams['studentId']).toBe('102');
+    expect(memoryApi.lastScheduleParams['search']).toBeUndefined();
     harness.fixture.detectChanges();
     expect(harness.routeNativeElement?.querySelectorAll('.schedule-list article').length).toBe(1);
     expect(harness.routeNativeElement?.querySelector('.schedule-list')?.textContent).toContain('花花');

+ 5 - 5
projects/xiaoshu-mobile/src/app/features/course-center/course-center-page.component.html

@@ -32,10 +32,10 @@
               </div>
             </label>
             <label>
-              <span>学生姓名</span>
-              <div class="history-filter-control name-control">
-                <lucide-icon [img]="icons.Search" [size]="18" />
-                <input type="search" [ngModel]="historyStudentQuery()" (ngModelChange)="setHistoryStudentQuery($event)" placeholder="输入姓名查找" autocomplete="off" aria-label="按学生姓名筛选陪练记录" />
+              <span>学员姓名</span>
+              <div class="history-filter-control student-control">
+                <lucide-icon [img]="icons.Users" [size]="18" />
+                <select [ngModel]="selectedStudent()" (ngModelChange)="setStudentFilter($event)" aria-label="按学员筛选陪练记录"><option value="all">全部学员</option>@for(student of studentOptions(); track student.id){<option [value]="student.id">{{student.name}}</option>}</select>
               </div>
             </label>
           </div>
@@ -47,7 +47,7 @@
         </section>
         <section class="fee-summary-wrap" aria-label="陪练费用汇总" aria-live="polite" [attr.aria-busy]="loading()">
           <div class="fee-summary-card">
-            <div class="fee-summary-top"><span>{{historyMonth()==='all'?'全部月份':historyMonth().replace('-', '年')+'月'}}</span><span class="fee-summary-tag">{{historyStudentQuery().trim()?'已筛选学员':'全部学员'}}</span></div>
+            <div class="fee-summary-top"><span>{{historyMonth()==='all'?'全部月份':historyMonth().replace('-', '年')+'月'}}</span><span class="fee-summary-tag">{{historyStudentName()}}</span></div>
             <span class="fee-summary-label">陪练费用合计</span>
             <strong class="fee-summary-amount">{{loading() || error() || !earningsSummary() ? '—' : '¥' + (earningsSummary()!.amount | number:'1.2-2')}}</strong>
             <div class="fee-summary-bottom"><span>{{loading()?'正在核对费用…':'共 '+listTotal()+' 条陪练记录'}}</span>@if(!loading() && !error() && earningsSummary()?.pendingCount){<span>{{earningsSummary()!.pendingCount}} 条待核对</span>}</div>

+ 7 - 10
projects/xiaoshu-mobile/src/app/features/course-center/course-center-page.component.ts

@@ -4,7 +4,7 @@ import { CommonModule } from '@angular/common';
 import { ChangeDetectionStrategy, Component, computed, inject, NgZone, OnDestroy, OnInit, signal } from '@angular/core';
 import { FormsModule } from '@angular/forms';
 import { ActivatedRoute, Router } from '@angular/router';
-import { AlertCircle, BarChart3, BookOpen, CalendarDays, ChevronDown, ChevronRight, GraduationCap, LoaderCircle, LucideAngularModule, Search, X } from 'lucide-angular';
+import { AlertCircle, BarChart3, BookOpen, CalendarDays, ChevronDown, ChevronRight, GraduationCap, LoaderCircle, LucideAngularModule, Users, X } from 'lucide-angular';
 import { catchError, finalize, map, of, Subscription, switchMap } from 'rxjs';
 import { allFeeRows, lessonFeeSummary } from '../../core/fee-summary';
 import { HomeDailyCacheService } from '../../core/home-daily-cache.service';
@@ -84,7 +84,6 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
   readonly feeSummaryError = signal('');
   readonly earningsSummary = signal<{amount:number;pendingCount:number}|null>(null);
   readonly historyMonth = signal('all');
-  readonly historyStudentQuery = signal('');
   readonly calendarMonth = signal(this.firstOfMonth(new Date()));
   readonly loading = signal(false);
   readonly liveChecking = signal(false);
@@ -93,8 +92,9 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
   readonly syncNoticeVisible = signal(false);
   readonly error = signal('');
   readonly studentOptions = computed(() => this.serverStudents().map(student => ({...student, id: String(student.id), name: String(student.name || '').trim() || `学员 ${student.id}`})));
+  readonly historyStudentName = computed(() => this.studentOptions().find(student => student.id === this.selectedStudent())?.name || '全部学员');
   readonly historyMonthOptions = computed(() => this.buildHistoryMonthOptions());
-  readonly historyFilterActive = computed(() => this.historyMonth() !== 'all' || Boolean(this.historyStudentQuery().trim()));
+  readonly historyFilterActive = computed(() => this.historyMonth() !== 'all' || this.selectedStudent() !== 'all');
   readonly scopedSchedules = computed(() => this.schedules().filter((item) => this.matchesStudent(item)));
   readonly filteredSchedulePool = computed(() => this.scopedSchedules().filter((item) => this.matchesStatus(item)));
   readonly visibleSchedules = computed(() => this.filteredSchedulePool().filter((item) => this.matchesRange(item) && this.matchesHistoryFilters(item)));
@@ -107,7 +107,7 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
     if (this.scheduleRange() === 'week') return `${this.selectedDate()} 所在周`;
     return this.selectedDate();
   });
-  readonly icons = { AlertCircle, BarChart3, BookOpen, CalendarDays, ChevronDown, ChevronRight, GraduationCap, LoaderCircle, Search, X };
+  readonly icons = { AlertCircle, BarChart3, BookOpen, CalendarDays, ChevronDown, ChevronRight, GraduationCap, LoaderCircle, Users, X };
 
   private readonly api = inject(ApiService);
   private readonly dailyCache = inject(HomeDailyCacheService);
@@ -176,7 +176,7 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
       uid,
       mode: this.isCoach ? 'coach' : 'student',
       history: this.isHistory,
-      page:this.listPage(),pageSize:20,studentId:this.selectedStudent()==='all'?undefined:this.selectedStudent(),filter:this.scheduleFilter(),month:this.historyMonth()==='all'?undefined:this.historyMonth(),search:this.historyStudentQuery(),
+      page:this.listPage(),pageSize:20,studentId:this.selectedStudent()==='all'?undefined:this.selectedStudent(),filter:this.scheduleFilter(),month:this.historyMonth()==='all'?undefined:this.historyMonth(),
       dateStart:this.isHistory||this.scheduleRange()==='all'?undefined:this.scheduleRange()==='week'?this.weekRange(this.selectedDate())[0]:this.selectedDate(),
       dateEnd:this.isHistory||this.scheduleRange()==='all'?undefined:this.scheduleRange()==='week'?this.weekRange(this.selectedDate())[1]:this.selectedDate(),
       rangeStart: range?.start,
@@ -353,11 +353,9 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
 
   setHistoryMonth(value: string): void { this.historyMonth.set(value || 'all'); this.load(); }
 
-  setHistoryStudentQuery(value: string): void { this.historyStudentQuery.set(value); this.load(); }
-
   clearHistoryFilters(): void {
     this.historyMonth.set('all');
-    this.historyStudentQuery.set('');
+    this.selectedStudent.set('all');
     this.load();
   }
 
@@ -560,8 +558,7 @@ export class CourseCenterPageComponent implements OnInit, OnDestroy {
     if (!this.isHistory) return true;
     const selectedMonth = this.historyMonth();
     if (selectedMonth !== 'all' && !this.itemDate(item).startsWith(`${selectedMonth}-`)) return false;
-    const query = this.historyStudentQuery().trim().toLocaleLowerCase('zh-CN');
-    return !query || this.studentName(item).toLocaleLowerCase('zh-CN').includes(query);
+    return true;
   }
 
   private sortedVisibleSchedules(): Item[] {

+ 2 - 1
projects/xiaoshu-mobile/src/styles.scss

@@ -209,7 +209,8 @@ select:focus {
 
 /* The course-history month picker has a leading calendar icon outside the
    shared dropdown trigger. Keep independent space for the icon and arrow. */
-body app-course-center-page .history-filter-control.month-control > button.xs-dropdown-trigger {
+body app-course-center-page .history-filter-control.month-control > button.xs-dropdown-trigger,
+body app-course-center-page .history-filter-control.student-control > button.xs-dropdown-trigger {
   height: 46px;
   min-height: 46px;
   padding-right: 18px;