Skip to content

Commit 0d20ad7

Browse files
committed
refactor(ui): 拆 ClassroomPage 第 3 步 — 页面级横幅
1 parent da21fc8 commit 0d20ad7

2 files changed

Lines changed: 74 additions & 28 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/**
2+
* ClassroomBanners — 课堂助手左栏三条页面级提示横幅(批 0-C2 Task 4 步 3 自
3+
* ClassroomPage.tsx 抽出,纯搬运、行为等价)。
4+
*
5+
* @ai-context: 三条横幅自上而下 = ①ASR 降级(流式引擎静默失效可见化,asr-recovered
6+
* 或会话停止时清除)②目标窗口丢失(画面采集中断提示,唯一带「知道了」
7+
* 手动关闭入口)③画面源停更(WGC 长时间无新帧,恢复帧/停止采集自动
8+
* 清除)。三者的状态源都在 useClassroomHints(事件驱动),本文件只做
9+
* 条件渲染与文案呈现。
10+
* @ai-context: 顶层返回 **fragment** —— 三条横幅必须仍是左栏 div 的直接子元素
11+
* (不得加包裹层:包裹层会改变 borderBottom 堆叠与 flex 高度分配)。
12+
* @ai-context: 耦合逐字保留 —— ⚠/🖼 emoji、全角破折号与括号、内联色值
13+
* (#fef2f2/#fecaca/#b91c1c · #fffbeb/#fcd34d/#b45309 ·
14+
* #eff6ff/#bfdbfe/#1d4ed8)与字号 11 均为现状契约,本批不 token 化、
15+
* 不换 emoji。本文件零 className / 零 id / 零 data-testid。
16+
*/
17+
interface Props {
18+
/** ASR 降级提示文案(null=不显示) */
19+
asrDegraded: string | null;
20+
/** 目标窗口丢失(true=显示;关闭走 onDismissWindowLost) */
21+
windowLost: boolean;
22+
/** 画面源停更秒数(null=未停更) */
23+
frameStalledSecs: number | null;
24+
onDismissWindowLost: () => void;
25+
}
26+
27+
export default function ClassroomBanners({
28+
asrDegraded,
29+
windowLost,
30+
frameStalledSecs,
31+
onDismissWindowLost,
32+
}: Props) {
33+
return (
34+
<>
35+
{asrDegraded && (
36+
<div style={{ padding: "6px 14px", background: "#fef2f2", borderBottom: "1px solid #fecaca", fontSize: 11, color: "#b91c1c" }}>
37+
⚠ {asrDegraded}
38+
</div>
39+
)}
40+
41+
{/* TD-2026-08-20-I 清偿:目标窗口丢失横幅(画面采集中断提示;恢复/停止后清除) */}
42+
{windowLost && (
43+
<div style={{ padding: "6px 14px", background: "#fffbeb", borderBottom: "1px solid #fcd34d", fontSize: 11, color: "#b45309", display: "flex", alignItems: "center", gap: 8 }}>
44+
⚠ 目标窗口已关闭或不可见——画面采集中断(音频继续;请恢复窗口或重新选择)
45+
<button
46+
onClick={onDismissWindowLost}
47+
style={{ marginLeft: "auto", border: "none", background: "none", color: "#b45309", cursor: "pointer", fontSize: 11, fontWeight: 600 }}
48+
>
49+
知道了
50+
</button>
51+
</div>
52+
)}
53+
54+
{/* REQ-281(v0.19.6):画面源停更轻提示(区别于窗口丢失;恢复帧自动消失) */}
55+
{frameStalledSecs != null && (
56+
<div style={{ padding: "6px 14px", background: "#eff6ff", borderBottom: "1px solid #bfdbfe", fontSize: 11, color: "#1d4ed8", display: "flex", alignItems: "center", gap: 8 }}>
57+
🖼 画面源已 {frameStalledSecs}s 无新帧——可能播放器暂停渲染或窗口被遮挡(已自动重试;画面恢复即消失)
58+
</div>
59+
)}
60+
61+
{/* 批 2b:原 REQ-291 随播随停横幅(mediaPaused)删除——暂停原因单一来源
62+
pausedReason,横幅语义并入采集卡内状态行(pausedCardText,见下) */}
63+
</>
64+
);
65+
}

‎app/src/pages/ClassroomPage.tsx‎

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ import { SystemStatusBadge } from "../components/SystemStatusBadge";
2828
import ClassroomRightPane from "../components/ClassroomRightPane";
2929
// 批 0-C2 Task 4:左栏实时捕获卡整体抽出(纯展示适配器——采集/模型状态由本页注入)
3030
import ClassroomCapturePanel from "../components/ClassroomCapturePanel";
31+
// 批 0-C2 Task 4 步 3:三条页面级提示横幅整体抽出(ASR 降级/窗口丢失/画面停更)
32+
import ClassroomBanners from "../components/ClassroomBanners";
3133
import MaterialInputPanel from "../components/MaterialInputPanel";
3234
import ColumnResizer from "../components/ColumnResizer";
3335
import ColumnBar from "../components/ColumnBar";
@@ -297,34 +299,13 @@ export default function ClassroomPage({ onOpenSessions }: { onOpenSessions?: (se
297299
</div>
298300
</div>
299301

300-
{asrDegraded && (
301-
<div style={{ padding: "6px 14px", background: "#fef2f2", borderBottom: "1px solid #fecaca", fontSize: 11, color: "#b91c1c" }}>
302-
⚠ {asrDegraded}
303-
</div>
304-
)}
305-
306-
{/* TD-2026-08-20-I 清偿:目标窗口丢失横幅(画面采集中断提示;恢复/停止后清除) */}
307-
{windowLost && (
308-
<div style={{ padding: "6px 14px", background: "#fffbeb", borderBottom: "1px solid #fcd34d", fontSize: 11, color: "#b45309", display: "flex", alignItems: "center", gap: 8 }}>
309-
⚠ 目标窗口已关闭或不可见——画面采集中断(音频继续;请恢复窗口或重新选择)
310-
<button
311-
onClick={dismissWindowLost}
312-
style={{ marginLeft: "auto", border: "none", background: "none", color: "#b45309", cursor: "pointer", fontSize: 11, fontWeight: 600 }}
313-
>
314-
知道了
315-
</button>
316-
</div>
317-
)}
318-
319-
{/* REQ-281(v0.19.6):画面源停更轻提示(区别于窗口丢失;恢复帧自动消失) */}
320-
{frameStalledSecs != null && (
321-
<div style={{ padding: "6px 14px", background: "#eff6ff", borderBottom: "1px solid #bfdbfe", fontSize: 11, color: "#1d4ed8", display: "flex", alignItems: "center", gap: 8 }}>
322-
🖼 画面源已 {frameStalledSecs}s 无新帧——可能播放器暂停渲染或窗口被遮挡(已自动重试;画面恢复即消失)
323-
</div>
324-
)}
325-
326-
{/* 批 2b:原 REQ-291 随播随停横幅(mediaPaused)删除——暂停原因单一来源
327-
pausedReason,横幅语义并入采集卡内状态行(pausedCardText,见下) */}
302+
{/* 批 0-C2 Task 4 步 3:三条页面级横幅整体抽出(含"为什么没有第四条"注释) */}
303+
<ClassroomBanners
304+
asrDegraded={asrDegraded}
305+
windowLost={windowLost}
306+
frameStalledSecs={frameStalledSecs}
307+
onDismissWindowLost={dismissWindowLost}
308+
/>
328309

329310
<div style={{ flex: 1, minHeight: 0, padding: 12, overflowY: "auto", display: "flex", flexDirection: "column", gap: 12 }}>
330311
{/* 2026-08 C1:引擎与模型就绪清单(开始前准备流——缺什么一目了然) */}

0 commit comments

Comments
 (0)