lesson-record-detail.component.html 6.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940
  1. <div class="backdrop" (click)="close()"></div><aside #detailDrawer class="drawer lesson-drawer" role="dialog" aria-modal="true" aria-label="上课记录详情" (keydown.escape)="close()">
  2. <header><div><h2>上课记录详情</h2><p class="muted">课堂反馈与抗遗忘安排</p></div><button class="ui-button secondary" [disabled]="busy()" (click)="close()">关闭</button></header>
  3. @if(error()){<p class="notice error" role="alert">{{error()}}</p>}@if(message()){<p class="notice" role="status">{{message()}}</p>}
  4. @if(busy()){<p role="status">正在处理…</p>}
  5. @if(data();as d){
  6. <section class="lesson-identity"><h3>{{d.studentName}} <small>会员 ID {{d.studentId}}</small></h3><p>{{d.courseName}}</p><p>{{d.lessonAt | date:'yyyy-MM-dd HH:mm':'+0800'}}(北京时间) · {{d.classTypeLabel}}</p><p>授课老师:{{d.coachName}}</p></section>
  7. @if(d.duplicateCount>1){<p class="notice error">发现 {{d.duplicateCount}} 条同课次原始记录,课次数按一节统计,请核对。</p>}
  8. @if(!d.hasReport){<p class="muted">历史课次的原始反馈保留在老师点评中,未分项记录的内容显示“未记录”。</p>}
  9. <div class="feedback-grid">
  10. @if(!d.hasReport){<article class="wide"><h3>老师点评</h3><p>{{d.coachComment||'未记录'}}</p></article>}
  11. @for(field of [['学习内容','contentSummary'],['复习情况','reviewStatus'],['复习说明','reviewSummary'],['训练进度','trainingStatus'],['进度说明','trainingSummary']];track field[1]){<article><h3>{{field[0]}}</h3><p>{{report(field[1])}}</p></article>}
  12. <article><h3>作业</h3><p>{{d.report?.['noHomework'] ? '本次无作业' : report('homework')}}</p></article>
  13. @if(d.hasReport){<article class="wide"><h3>老师点评</h3><p>{{d.coachComment||'未记录'}}</p></article>}
  14. <article class="wide"><h3>学生评价</h3><p>{{d.studentReview.score ? d.studentReview.score+' 分' : '尚未评分'}} · {{d.studentReview.comment||'暂无文字评价'}}</p></article>
  15. <article class="wide"><h3>备注</h3><p>{{report('notes')}}</p></article>
  16. </div>
  17. <section class="review-section"><header><h3>抗遗忘复习安排</h3>@if(d.canTransfer){<button class="ui-button secondary" [disabled]="busy()" (click)="beginTransfer()">更换抗遗忘陪练</button>}</header><p class="muted">已完成任务和工资归属保留原记录。</p>
  18. <div class="table-scroll"><table class="data-table review-table"><thead><tr><th>计划日期</th><th>复习陪练</th><th>状态</th></tr></thead><tbody>@for(t of d.tasks;track t.objectId){<tr><td>{{t.plannedDate}}</td><td>{{t.coachName}}</td><td>{{t.status==='1'?'已完成':'未完成'}}</td></tr>}@empty{<tr><td colspan="3">本课暂无关联复习任务</td></tr>}</tbody></table></div>
  19. </section>
  20. @if(transferring()){
  21. <section class="transfer-panel"><h3>转交未完成复习</h3><p>包含逾期、今天和未来的已有任务;后续新课仍由该课授课老师负责。</p>
  22. <div class="form-grid"><fieldset class="transfer-scope"><legend>范围</legend><label><input type="radio" name="transferScope" value="lesson" [(ngModel)]="scope" (ngModelChange)="resetPreview()" [disabled]="busy()||!d.appointmentId">本节课未完成复习</label><label><input type="radio" name="transferScope" value="student" [(ngModel)]="scope" (ngModelChange)="resetPreview()" [disabled]="busy()">该学员全部未完成复习</label></fieldset>
  23. <div class="coach-picker" (focusout)="closeCoachesOnBlur($event)"><label for="transfer-coach-search">目标陪练</label><input id="transfer-coach-search" type="search" autocomplete="off" placeholder="输入老师姓名或编号搜索" role="combobox" aria-autocomplete="list" aria-controls="transfer-coach-results" [attr.aria-expanded]="coachPickerOpen()" [attr.aria-activedescendant]="coachPickerOpen()&&activeCoach()>=0?'transfer-coach-'+activeCoach():null" [ngModel]="coachQuery()" (ngModelChange)="searchCoach($event)" (focus)="openCoaches()" (click)="openCoaches()" (keydown)="coachKeydown($event)" [disabled]="busy()">
  24. @if(coachPickerOpen()){
  25. <div class="coach-results" id="transfer-coach-results" role="listbox" aria-label="可选陪练老师">
  26. @for(c of filteredCoaches();track c.userId;let i=$index){<button type="button" role="option" [id]="'transfer-coach-'+i" [attr.aria-selected]="coachId===c.userId" [class.keyboard-active]="activeCoach()===i" (mousedown)="$event.preventDefault()" (click)="selectCoach(c)"><span>{{c.displayName}}</span><small>编号 {{c.userId}}</small>@if(coachId===c.userId){<span class="coach-check" aria-hidden="true">✓</span>}</button>}
  27. </div>
  28. @if(!filteredCoaches().length){<p class="coach-empty" role="status">没有匹配的陪练,请换个姓名或编号</p>}
  29. }
  30. <small class="coach-hint">{{coachId?'已选定陪练,可修改搜索重新选择':'支持姓名片段或编号,请从结果中选择'}}</small>
  31. </div>
  32. <label class="wide">转交原因<textarea maxlength="1000" [(ngModel)]="reason" (ngModelChange)="resetPreview()" [disabled]="busy()" placeholder="例如:原老师离岗,由新老师接手复习"></textarea></label></div>
  33. <button class="ui-button secondary" (click)="checkTransfer()" [disabled]="busy()">预览受影响任务</button>
  34. @if(preview();as p){<div class="notice"><strong>将转交 {{p.count}} 次复习,涉及 {{p.lessonCount}} 节课</strong><p>{{p.dateFrom}} 至 {{p.dateTo}}</p>@if(p.unlinkedCount){<p>{{p.unlinkedCount}} 条任务缺少课次关联,但学员归属已核实。</p>}
  35. <details><summary>查看全部任务与原陪练</summary>@for(t of p.tasks;track t.taskId){<p>{{t.plannedDate}} · {{t.coachName}} · 课次 {{t.appointmentId||'未关联'}}</p>}</details></div>
  36. <button class="ui-button" (click)="saveTransfer()" [disabled]="busy()||!p.count">确认保存转交</button>}
  37. <button class="ui-button secondary" [disabled]="busy()" (click)="transferring.set(false)">取消</button></section>}
  38. @if(d.audit.length){<details class="audit-section"><summary>转交审计({{d.audit.length}} 条任务记录)</summary>@for(a of d.audit;track a['objectId']){<p>{{$any(a['createdAt'])|date:'yyyy-MM-dd HH:mm':'+0800'}} · {{a['oldCoachId']}} → {{a['newCoachId']}} · {{a['reason']}}</p>}</details>}
  39. }@else if(!busy()){<button class="ui-button secondary" (click)="load()">重新加载</button>}
  40. </aside>