|
|
@@ -45,6 +45,7 @@
|
|
|
2. **对话流畅性优先**:`/speak` 不能等评分;评分后台跑,对话途中**不显示**评分。
|
|
|
3. **教师侧直接访问口语后端**:pbl-teacher-table 通过 sessionId 调 `/report`;CORS 由后端配置解决。
|
|
|
4. **与既有 homework_submitted 广播兼容**:口语的 workPage 写入后同样发 Yjs 广播,教师侧无需新增分支(`homework_submitted` 消费是幂等的,都走 `getWork(true)`)。
|
|
|
+5. **UI 全盘还原 enspeak 原型**:所有可视元素(布局、配色、动效、状态机文案、消息气泡、录音按钮、倒计时、空/错/过渡态、结果页四维分、summary 展示等)**严格对齐** `/Users/buoy/Development/gitrepo/enspeak`。实现方式是**React TSX → Vue 3 移植**:保留行为与视觉 1:1,语法层面由 hooks→composables、JSX→template、useState→ref/reactive、useEffect→watch/watchEffect/onMounted;不得为"Vue 更自然"而改动交互。映射表见 §5.4。
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -205,6 +206,47 @@ type ErrorCode =
|
|
|
- **无 "role / identity / personality / speakingStyle / speed" 字段**(产品明确不需要)
|
|
|
- **无"结束对话"按钮**(MVP 不允许学生主动放弃)
|
|
|
|
|
|
+### 5.4 UI 还原基准(enspeak → Vue 映射)
|
|
|
+
|
|
|
+> 全部 UI 从 enspeak 原型移植,**视觉与交互 1:1**。以下是源文件与目标 Vue 文件的映射。所有 UI 细节(文案、颜色、动效时长、气泡样式、按钮状态切换、空态、提示 modal、倒计时样式、结果页四维分卡片、summary 排版等)以 enspeak 为准,不自行发挥。
|
|
|
+
|
|
|
+| 功能区域 | enspeak 源(React TSX) | PPT 目标(Vue) |
|
|
|
+|---|---|---|
|
|
|
+| 对话主界面(状态机 + 录音按钮 + 消息气泡 + 倒计时显示 + 过渡动画) | `enspeak/src/components/dialogue/DialogueChatView.tsx` (47KB,主干) | `src/views/Editor/EnglishSpeaking/preview/DialogueChatView.vue` |
|
|
|
+| 话题预览(配置面板进入对话前的 landing) | `enspeak/src/components/dialogue/DialoguePreview.tsx` | `src/views/Editor/EnglishSpeaking/preview/TopicDiscussionPreview.vue`(入口部分) |
|
|
|
+| 详细报告页(每轮录音 / transcript / 四维分 / word analysis) | `enspeak/src/components/dialogue/DetailedReport.tsx` (17KB) | `src/views/Editor/EnglishSpeaking/preview/DetailedReport.vue` |
|
|
|
+| 总览报告页(四维分汇总 + summary + 总体评价) | `enspeak/src/components/dialogue/OverallReport.tsx` (8KB) | `src/views/Editor/EnglishSpeaking/preview/OverallReport.vue` |
|
|
|
+| 结果入口(控制详细/总览切换) | `enspeak/src/components/dialogue/DialogueResult.tsx` | 合入 `TopicDiscussionPreview.vue` 的完成态分支或新建 `DialogueResult.vue` |
|
|
|
+| 提示弹窗(沉默提示 / 帮助等) | `enspeak/src/components/dialogue/HintDialog.tsx` | `src/views/Editor/EnglishSpeaking/preview/HintDialog.vue` |
|
|
|
+| 实时反馈条(录音中的声纹/能量指示) | `enspeak/src/components/dialogue/RealtimeFeedback.tsx` | `src/views/Editor/EnglishSpeaking/preview/RealtimeFeedback.vue` |
|
|
|
+| 话题讨论父容器(上下文包装层) | `enspeak/src/components/preview/TopicDiscussionPreview.tsx` | `src/views/Editor/EnglishSpeaking/preview/TopicDiscussionPreview.vue`(包装部分) |
|
|
|
+
|
|
|
+**移植规则(TSX → Vue)**:
|
|
|
+
|
|
|
+| React 原语 | Vue 对应 |
|
|
|
+|---|---|
|
|
|
+| `useState` | `ref` / `reactive` |
|
|
|
+| `useRef` | `ref`(DOM 引用) / `shallowRef`(持有对象引用如 MediaRecorder) |
|
|
|
+| `useEffect(..., [deps])` | `watch(deps, cb)` / `watchEffect` / `onMounted` + `onBeforeUnmount` |
|
|
|
+| `useMemo` | `computed` |
|
|
|
+| `useCallback` | 普通函数即可(Vue 不需要引用稳定性) |
|
|
|
+| Props with optional callbacks | `defineEmits` + 父组件 listener |
|
|
|
+| 条件 render `{cond && <X/>}` | `v-if` / `v-show`(动画场景慎选 `v-show`) |
|
|
|
+| `className={clsx(...)}` | `:class="[...]"` |
|
|
|
+| Tailwind classes | 保留 class 名不动(Tailwind 在 PPT 项目若可用直接沿用;若不可用,按 class 名对照抽 CSS vars) |
|
|
|
+
|
|
|
+**不移植项**(enspeak 独有,PPT 不需要):
|
|
|
+
|
|
|
+- 角色选择器 `RoleSelector.tsx`、话题选择器 `TopicSelector.tsx`(PPT 编辑器侧已有自己的配置面板)
|
|
|
+- 自定义角色/话题 modal `CustomRoleModal.tsx` / `CustomTopicModal.tsx`(同上)
|
|
|
+- `DialogueChat.tsx`(enspeak 的路由容器,PPT 不需要路由层)
|
|
|
+
|
|
|
+**可能的对齐差异**(实现时标注在代码注释):
|
|
|
+
|
|
|
+- 字体:enspeak 可能用 Inter / 系统字体,PPT 沿用项目字体栈
|
|
|
+- 尺寸:enspeak 是独立页面(全屏),PPT 是 slide 内嵌组件,需按 `elementInfo` 的 width/height 缩放;保持相对比例不变
|
|
|
+- 主题色:enspeak 有自己的色板,如与 PPT 冲突以 PPT 为准(最小改动)
|
|
|
+
|
|
|
---
|
|
|
|
|
|
## 6. 会话生命周期
|
|
|
@@ -413,12 +455,12 @@ is_complete = session.current_round > session.total_rounds
|
|
|
|---|---|
|
|
|
| 定义 `SPEAKING_RUNNER_KEY` + `SpeakingRunnerContext` 类型 | `src/views/Editor/EnglishSpeaking/types.ts`(新) |
|
|
|
| `TopicDiscussionPreview.vue` 作为 runner context 注入层:读 workPage → 决定 B1 resume / 新建 / 查看;provide `SPEAKING_RUNNER_KEY` | `src/views/Editor/EnglishSpeaking/preview/TopicDiscussionPreview.vue` |
|
|
|
-| `DialogueChatView.vue` 重写为纯 UI + SSE 消费:inject runner context;Props/Emits 见 §5.3;状态机 §7.3;倒计时 §6.3;B4 `isVisible` 处理 §6.4 | `src/views/Editor/EnglishSpeaking/preview/DialogueChatView.vue` |
|
|
|
+| `DialogueChatView.vue` 重写为纯 UI + SSE 消费:inject runner context;Props/Emits 见 §5.3;状态机 §7.3;倒计时 §6.3;B4 `isVisible` 处理 §6.4。**UI 严格对齐 enspeak**(见 §5.4 映射) | `src/views/Editor/EnglishSpeaking/preview/DialogueChatView.vue` |
|
|
|
| `Student/index.vue` 通过 `provide(SPEAKING_RUNNER_KEY, ...)` 暴露 runner context | `src/views/Student/index.vue` |
|
|
|
| `Student/index.vue::handleHomeworkSubmit` 处理全 toolType=77 slide:toast "对话结束后自动提交" | `src/views/Student/index.vue` (~line 1749-1867) |
|
|
|
-| 报告页(DetailedReport / OverallReport)按 §4.4 结构渲染;轮询逻辑 §8 | `src/views/Editor/EnglishSpeaking/preview/DetailedReport.vue` / `OverallReport.vue` |
|
|
|
+| 详细报告页 / 总览报告页:按 §4.4 数据结构渲染 + 轮询逻辑 §8;**UI 严格对齐 enspeak**(见 §5.4 映射) | `src/views/Editor/EnglishSpeaking/preview/DetailedReport.vue` / `OverallReport.vue` |
|
|
|
+| 提示弹窗、实时反馈条等辅助 UI 按 §5.4 映射移植 | `src/views/Editor/EnglishSpeaking/preview/HintDialog.vue` / `RealtimeFeedback.vue` |
|
|
|
| `types/englishSpeaking.ts`:加 `timeLimitSeconds?: number`;清理 role.identity / personality / speakingStyle / speed 等不需要的字段 | `src/types/englishSpeaking.ts` |
|
|
|
-| 结果页 UI 还原 enspeak 原型(轮次列表 / 录音播放 / transcript / 四维分 / summary) | 实现阶段逐个从 `/Users/buoy/Development/gitrepo/enspeak/src/components/dialogue/DialogueResult.tsx` 对齐 |
|
|
|
|
|
|
### 11.1 teacher-table 侧
|
|
|
|
|
|
@@ -457,9 +499,10 @@ is_complete = session.current_round > session.total_rounds
|
|
|
|
|
|
## 14. 本次未讨论 / 待实现阶段处理
|
|
|
|
|
|
-- 老师侧"口语详情"视图的具体 UI(直接复用 enspeak `DialogueResult.tsx` 还是重写)
|
|
|
+- 老师侧"口语详情"视图:UI 按 §5.4 从 enspeak `DetailedReport.tsx` + `OverallReport.tsx` 移植(布局是否需要压缩为嵌入式等实现阶段决定)
|
|
|
- 编辑器 `mode='preview'` 下的 mock 数据/直通策略
|
|
|
- 单 slide 上多个口语组件的处理(理论上可能,产品价值存疑,MVP 暂不支持)
|
|
|
- `showEnglishText` / `showChineseText` / `showTaskHint` / `showSilenceHint` 几个展示开关的默认值由产品决定
|
|
|
- 生产部署的 `API_BASE` 配置(`llmService.ts:3` 当前是 `http://localhost:8000`,需改环境变量)
|
|
|
- B4 `isVisible` 的具体传递链路(ScreenSlide 已经把 `is-visible` 传给子组件,DialogueChatView 接收方式到实现阶段确认)
|
|
|
+- Tailwind 在 PPT 项目的可用性(enspeak 使用 Tailwind;若 PPT 不开启,需把 class 转为 scoped CSS,保留样式值)
|