jimmylee 1 месяц назад
Родитель
Сommit
ff95b56105

+ 2 - 0
openspec/changes/topic-discussion-preview/.openspec.yaml

@@ -0,0 +1,2 @@
+schema: spec-driven
+created: 2026-04-03

+ 78 - 0
openspec/changes/topic-discussion-preview/design.md

@@ -0,0 +1,78 @@
+## Context
+
+PPT 编辑器采用三栏布局:左侧 CollapsibleToolbar(配置面板)、中间 Canvas(画布)、右侧 Toolbar(目前隐藏)。english-speaking 功能已完成教师配置流程(Layer 1-3),教师点击"应用配置"后触发 `parentWindow.addTool(77)` 向画布添加一个 `PPTFrameElement`。
+
+画布中的 `BaseFrameElement.vue` 负责渲染 `PPTFrameElement`,按 `toolType` 分支:
+- toolType 74 → `<video>` 标签
+- toolType 75 → `<iframe>` (bilibili)
+- 其他 → `<iframe :src="url">` 或 `<iframe :srcdoc="url">`
+
+当前 toolType 77 走的是通用 iframe 分支。现在要改为直接渲染 Vue 组件,不再使用 iframe。
+
+enspeak demo 项目中的 `TopicDiscussionPreview` 组件提供了完整的学生视角预览,包含三个阶段:准备页(Ready)→ 对话过程(Chatting)→ 完成报告(Completed),需要迁移到 PPT 项目中。
+
+demo 组件依赖树:
+```
+TopicDiscussionPreview.tsx
+├── StudentPreview.tsx        — 16:9 PPT 页面容器
+├── DialogueChatView.tsx      — 对话交互(语音条、即时反馈、提示、徽章)
+├── OverallReport.tsx         — 整体报告(评分、四维能力、AI 点评、统计)
+└── DetailedReport.tsx        — 详细报告(按轮次分组、单句评价卡片)
+```
+
+## Goals / Non-Goals
+
+**Goals:**
+- 将 TopicDiscussionPreview 从 React + Tailwind 迁移为 Vue 3 + SCSS
+- 保持 demo 的完整 UI 和交互逻辑(三阶段切换、模拟对话脚本、模拟评估数据)
+- 组件放在 `src/views/Editor/EnglishSpeaking/preview/` 目录下
+- 在 `BaseFrameElement.vue` 中 toolType 77 时直接渲染 Vue 组件(替代 iframe)
+- 在现有 `src/types/englishSpeaking.ts` 中追加预览相关类型
+
+**Non-Goals:**
+- 不实现真实的语音识别/AI 对话(使用模拟脚本)
+- 不实现真实的音频播放(静态波形展示)
+- 不修改编辑器主布局(index3.vue)
+- 不处理与后端 API 的对接
+
+## Decisions
+
+### 1. 集成方式:Vue 组件直接渲染 vs iframe
+**选择**: 在 `BaseFrameElement.vue` 的 v-if/v-else-if 链中新增 toolType 77 分支,直接渲染 `<TopicDiscussionPreview>` Vue 组件。
+**理由**: 与 iframe 方式相比,Vue 组件可以直接访问 Pinia store 和父组件状态,便于后续配置联动;同时避免了 iframe 通信的复杂性。类似 toolType 74 渲染 `<video>` 的模式。
+**实现**: 
+```vue
+<!-- BaseFrameElement.vue 第 26 行后插入 -->
+<TopicDiscussionPreview
+  v-else-if="elementInfo.toolType === 77 && !isThumbnail && isVisible"
+  :style="{ width: width + 'px', height: height + 'px' }"
+/>
+```
+
+### 2. 组件架构:平铺式组件 vs 嵌套式组件
+**选择**: 平铺式组件(每个子组件独立文件),保持与 demo 一致的层级结构。
+**理由**: 每个组件职责明确、代码量大(DialogueChatView 700+ 行),拆分有利于维护。
+
+### 3. 状态管理:组件内 ref vs Pinia store
+**选择**: 组件内 ref 管理预览状态(dialogueState、messages 等)。
+**理由**: 预览状态是纯 UI 状态,不需要跨组件共享或持久化,使用 store 过度设计。
+
+### 4. 样式方案:Tailwind 转换策略
+**选择**: 手动转换为 scoped SCSS,与 PPT 项目其他组件保持一致。
+**理由**: PPT 项目不使用 Tailwind,保持技术栈统一。
+
+### 5. 图标方案:SVG 内联
+**选择**: 所有图标(MicIcon、VolumeIcon、LightbulbIcon、RefreshIcon、XIcon、ChevronDownIcon、PlayIcon、CheckIcon)使用 SVG 内联方式直接写在模板中。
+**理由**: PPT 项目没有统一的图标组件库,内联 SVG 最简单直接,不引入额外依赖。从 enspeak demo 的 `@/components/icons` 中提取 SVG 路径数据。
+
+### 6. 类型文件:扩展现有文件
+**选择**: 在现有 `src/types/englishSpeaking.ts` 中追加预览相关类型(`OverallEvaluation`、`SentenceEvaluation`、`AIRole` 等)。
+**理由**: 该文件已存在且包含配置侧类型(`TopicDiscussionConfig`、`Role` 等),预览类型与其紧密关联,保持集中管理。
+
+## Risks / Trade-offs
+
+- **[代码量大]** DialogueChatView 有 700+ 行 React 代码,迁移工作量较大 → 分步迁移,先骨架后细节
+- **[模拟数据硬编码]** 对话脚本和评分数据硬编码在组件中 → 后续可提取为配置,当前阶段可接受
+- **[无真实音频]** 语音条是纯静态的 → 与 demo 行为一致,后续集成真实语音时再改
+- **[画布缩放]** BaseFrameElement 内的 Vue 组件需要适配画布的缩放比例 → 组件使用 100% 宽高填充父容器,缩放由 BaseFrameElement 外层处理
+- **[SVG 内联冗余]** 多个组件可能重复相同的 SVG 代码 → 当前可接受,后续如果图标增多可抽取为公共组件

+ 28 - 0
openspec/changes/topic-discussion-preview/proposal.md

@@ -0,0 +1,28 @@
+## Why
+
+英语口语配置面板(english-speaking)已完成教师侧的配置流程,但目前缺少学生侧的预览能力。教师完成配置后无法直观看到学生将会看到的界面效果。需要从 enspeak demo 项目迁移 `TopicDiscussionPreview` 组件到 PPT 项目中,让教师在画布上直接看到学生视角的话题讨论交互界面(包含准备页、对话过程、完成报告三个阶段)。
+
+## What Changes
+
+- 新增学生预览容器组件 `StudentPreview.vue`,模拟 16:9 PPT 页面布局
+- 新增对话聊天视图组件 `DialogueChatView.vue`,含语音条、即时反馈、提示弹窗等
+- 新增整体报告组件 `OverallReport.vue`,展示综合评分、四维能力分析、AI 点评
+- 新增详细报告组件 `DetailedReport.vue`,展示按轮次分组的单句评价
+- 新增主预览组件 `TopicDiscussionPreview.vue`,管理三阶段状态切换
+- 新增相关 TypeScript 类型定义(`OverallEvaluation`、`SentenceEvaluation`、`AIRole` 等)
+- 修改 `BaseFrameElement.vue`,在 toolType === 77 时渲染 Vue 组件替代 iframe
+
+## Capabilities
+
+### New Capabilities
+- `topic-discussion-preview`: 话题讨论学生预览组件,涵盖三个阶段(准备页 → 对话过程 → 完成报告),从 React demo 迁移为 Vue 3 + SCSS 实现
+
+### Modified Capabilities
+(无)
+
+## Impact
+
+- **新增文件**: `src/views/Editor/EnglishSpeaking/preview/` 目录下 5 个 Vue 组件
+- **类型扩展**: 新增预览相关类型定义
+- **修改文件**: `BaseFrameElement.vue` 新增 toolType 77 的 Vue 组件分支(替代 iframe)
+- **依赖**: 无新外部依赖,全部用 Vue 3 + SCSS 实现

+ 117 - 0
openspec/changes/topic-discussion-preview/specs/topic-discussion-preview/spec.md

@@ -0,0 +1,117 @@
+## ADDED Requirements
+
+### Requirement: Canvas Integration
+系统 SHALL 在 `BaseFrameElement.vue` 中,当 `toolType === 77` 时直接渲染 `TopicDiscussionPreview` Vue 组件,替代 iframe 渲染方式。
+
+#### Scenario: Render preview component on canvas
+- **WHEN** 画布中存在 toolType 为 77 的 PPTFrameElement,且非缩略图模式、元素可见
+- **THEN** 渲染 TopicDiscussionPreview Vue 组件,填满元素容器
+
+#### Scenario: Show placeholder when not visible
+- **WHEN** toolType 为 77 的元素不可见(如被滚出视口)
+- **THEN** 显示占位符(🌐 + "英语口语"类型标签),与其他工具类型行为一致
+
+#### Scenario: Show thumbnail mode
+- **WHEN** toolType 为 77 的元素处于缩略图模式
+- **THEN** 显示简化占位符,与其他工具类型的缩略图行为一致
+
+---
+
+### Requirement: Student Preview Container
+系统 SHALL 提供一个 `StudentPreview.vue` 容器组件,模拟 16:9 PPT 页面布局,包含标题区(slot)、内容区(default slot)、操作区(slot)。
+
+#### Scenario: Render with title and action area
+- **WHEN** 组件传入 title、subtitle、titleIcon 和 actionArea slot
+- **THEN** 显示带标题区和操作区的 16:9 白色卡片容器,内容区居中显示 default slot
+
+#### Scenario: Render without title
+- **WHEN** 组件未传入 title 相关 props
+- **THEN** 不渲染标题区,内容区占满容器
+
+---
+
+### Requirement: Dialogue State Management
+系统 SHALL 管理话题讨论预览的三个阶段:ready(准备)、chatting(对话中)、completed(完成)。
+
+#### Scenario: Initial state is ready
+- **WHEN** TopicDiscussionPreview 组件挂载
+- **THEN** 显示准备页,包含话题图标、话题名称和"开始对话"按钮
+
+#### Scenario: Transition from ready to chatting
+- **WHEN** 用户点击"开始对话"按钮
+- **THEN** 切换到 DialogueChatView 对话界面,显示 AI 第一条消息
+
+#### Scenario: Transition from chatting to completed
+- **WHEN** 对话轮次完成(达到 totalRounds 或脚本结束)
+- **THEN** 切换到报告界面,显示 OverallReport 和 DetailedReport
+
+#### Scenario: Reset preview
+- **WHEN** 用户在 chatting 或 completed 阶段点击"重置预览"按钮
+- **THEN** 回到 ready 阶段
+
+---
+
+### Requirement: Dialogue Chat View
+系统 SHALL 提供 DialogueChatView.vue 组件,实现模拟对话交互界面。
+
+#### Scenario: Display chat messages with voice bars
+- **WHEN** 对话消息存在
+- **THEN** AI 消息显示白色语音条(左对齐),学生消息显示橙色语音条(右对齐),每条消息下方显示英文文本
+
+#### Scenario: Recording toggle
+- **WHEN** 用户点击录音按钮
+- **THEN** 按钮变为红色录音状态,显示录音时长计数;再次点击停止录音,自动生成模拟学生回复和评估数据
+
+#### Scenario: Instant feedback display (L1)
+- **WHEN** 学生消息生成后
+- **THEN** 在消息下方显示四维度评估(准确/流畅/完整/节奏)和一句话建议,可展开查看详情
+
+#### Scenario: Feedback detail expansion (L2)
+- **WHEN** 用户点击 L1 反馈的"详情"按钮
+- **THEN** 展开显示 better expression 和 suggested words
+
+#### Scenario: Smart hint dialog
+- **WHEN** 用户点击"提示"按钮
+- **THEN** 弹出提示弹窗,包含任务提示、句子提示(含关键词高亮)和词汇提示(含音标和释义)
+
+#### Scenario: Badge achievement animation
+- **WHEN** 学生连续 3 句流畅度优秀 / 连续 5 句发音准确 / 单轮四维度全优
+- **THEN** 右上角显示对应徽章动画(流畅达人/发音专家/完美一轮),2.5 秒后消失
+
+---
+
+### Requirement: Overall Report
+系统 SHALL 提供 OverallReport.vue 组件,展示对话完成后的整体评价报告。
+
+#### Scenario: Display score and level
+- **WHEN** 报告渲染时
+- **THEN** 显示综合评分(数字/字母/仅评语,取决于 scoreDisplayMode)、评分等级标签、超过同学百分比
+
+#### Scenario: Display ability analysis
+- **WHEN** 报告渲染时
+- **THEN** 显示四维能力(流利度/互动性/词汇量/语法)的横向柱状图
+
+#### Scenario: Display AI comment and highlights
+- **WHEN** 报告渲染时
+- **THEN** 显示 AI 角色头像和点评文本、亮点列表和建议列表
+
+#### Scenario: Action buttons
+- **WHEN** 报告渲染时
+- **THEN** 底部显示"再来一次"和"完成"按钮
+
+---
+
+### Requirement: Detailed Report
+系统 SHALL 提供 DetailedReport.vue 组件,展示按轮次分组的单句评价。
+
+#### Scenario: Display sentence cards by round
+- **WHEN** 报告渲染时
+- **THEN** 按轮次分组显示对话卡片,每张卡片包含语音条、文本内容,学生卡片可展开查看发音评分和反馈
+
+#### Scenario: Expand/collapse individual cards
+- **WHEN** 用户点击有评价数据的学生消息卡片
+- **THEN** 展开/收起该卡片的发音评估和反馈详情
+
+#### Scenario: Toggle all cards
+- **WHEN** 用户点击"展开全部/收起全部"按钮
+- **THEN** 所有学生消息卡片同时展开或收起

+ 48 - 0
openspec/changes/topic-discussion-preview/tasks.md

@@ -0,0 +1,48 @@
+## 1. 类型定义
+
+- [ ] 1.1 在 `src/types/englishSpeaking.ts` 中追加预览相关类型:`SentenceEvaluation`、`ScoreLevel`、`OverallEvaluation`、`DialogueStatistics`、`AIRole`(预览用)、`ChatMessage`、`BadgeAchievement`
+
+## 2. StudentPreview 容器组件
+
+- [ ] 2.1 创建 `src/views/Editor/EnglishSpeaking/preview/StudentPreview.vue`,实现 16:9 PPT 页面容器布局(标题区 slot、内容区 default slot、操作区 slot),使用 scoped SCSS
+
+## 3. DialogueChatView 对话组件
+
+- [ ] 3.1 创建 `src/views/Editor/EnglishSpeaking/preview/DialogueChatView.vue` 基础骨架:顶部状态栏、消息列表区、底部录音控制区
+- [ ] 3.2 实现消息渲染:AI 语音条(白色左对齐)、学生语音条(橙色右对齐)、英文文本、图标使用 SVG 内联
+- [ ] 3.3 实现录音交互:点击录音按钮切换状态、模拟生成学生回复和评估数据、AI 自动回复
+- [ ] 3.4 实现 L1 即时反馈:四维度评估(准确/流畅/完整/节奏)+ 一句话建议
+- [ ] 3.5 实现 L2 展开详情:better expression + suggested words
+- [ ] 3.6 实现单词高亮:可发音改进单词标记波浪下划线,点击弹出 L3 音素详情弹窗
+- [ ] 3.7 实现提示弹窗:任务提示、句子提示(关键词高亮)、词汇提示(音标+释义)
+- [ ] 3.8 实现徽章动画:流畅达人 / 发音专家 / 完美一轮,右上角弹出 2.5s 消失
+
+## 4. OverallReport 整体报告组件
+
+- [ ] 4.1 创建 `src/views/Editor/EnglishSpeaking/preview/OverallReport.vue`:综合评分展示(数字/字母/仅评语三种模式)、评分等级标签
+- [ ] 4.2 实现四维能力分析横向柱状图(流利度/互动性/词汇量/语法)
+- [ ] 4.3 实现 AI 点评区(角色头像 + 评语)、亮点列表、建议列表、统计数据
+- [ ] 4.4 实现操作按钮:"再来一次" + "完成"
+
+## 5. DetailedReport 详细报告组件
+
+- [ ] 5.1 创建 `src/views/Editor/EnglishSpeaking/preview/DetailedReport.vue`:按轮次分组的对话卡片列表
+- [ ] 5.2 实现 SentenceCard 子组件:语音条 + 文本 + 可展开的发音评分和反馈详情
+- [ ] 5.3 实现展开/收起全部切换
+
+## 6. TopicDiscussionPreview 主预览组件
+
+- [ ] 6.1 创建 `src/views/Editor/EnglishSpeaking/preview/TopicDiscussionPreview.vue`:管理三阶段状态(ready → chatting → completed)
+- [ ] 6.2 实现 ready 阶段:StudentPreview 容器 + 话题图标 + "开始对话"按钮
+- [ ] 6.3 实现 chatting 阶段:DialogueChatView + "重置预览"按钮
+- [ ] 6.4 实现 completed 阶段:OverallReport + DetailedReport + "重置预览"按钮
+- [ ] 6.5 添加模拟评估数据(mockOverallEvaluation)
+
+## 7. 画布集成
+
+- [ ] 7.1 修改 `BaseFrameElement.vue`:在 v-if 链中新增 `toolType === 77` 分支,渲染 `<TopicDiscussionPreview>` 组件替代 iframe
+
+## 8. 验证
+
+- [ ] 8.1 编译验证:确保无 TypeScript 和模板编译错误
+- [ ] 8.2 端到端验证:配置面板应用配置 → 画布显示预览组件 → 三阶段交互正常