From 760c1445fefd3a4a85041fd79a6e064ef71f0a11 Mon Sep 17 00:00:00 2001 From: Peanut Date: Tue, 28 Jul 2026 19:32:28 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E6=B7=BB=E5=8A=A0=E5=B0=8F=E8=AF=B4?= =?UTF-8?q?=E6=B6=88=E6=81=AF=E6=93=8D=E4=BD=9C=E6=8C=89=E9=92=AE=E6=81=A2?= =?UTF-8?q?=E5=A4=8D=E8=AE=BE=E8=AE=A1=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...28-novel-message-actions-restore-design.md | 376 ++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 docs/superpowers/specs/2026-07-28-novel-message-actions-restore-design.md diff --git a/docs/superpowers/specs/2026-07-28-novel-message-actions-restore-design.md b/docs/superpowers/specs/2026-07-28-novel-message-actions-restore-design.md new file mode 100644 index 0000000..c723020 --- /dev/null +++ b/docs/superpowers/specs/2026-07-28-novel-message-actions-restore-design.md @@ -0,0 +1,376 @@ +--- +author: AI Assistant +created_at: 2026-07-28 +purpose: 恢复小程序小说生成页和详情页丢失的"复制、播放、折叠/展开"功能 +--- + +# 小说消息操作按钮恢复设计 + +## 问题背景 + +小程序的小说生成页(ScriptView.vue)和详情页(ScriptDetailView.vue)在之前的重构过程中丢失了"复制、播放、折叠/展开"等操作按钮。用户要求完整恢复这些功能,且必须有真实实现,不能有任何 mock 或占位。 + +## 根因分析 + +### 重构历史追溯 + +通过 git 历史分析,发现功能丢失的关键节点: + +1. **commit 9b3006d**(2026-06-27):添加消息卡片功能方法 + - 新增 `copyMessageContent(message)`:复制消息内容 + - 新增 `playMessageTts(message)`:播放 TTS 音频 + - 新增 `toggleMessageCollapse(message)`:折叠/展开消息 + +2. **commit 0db434c**(2026-06-27):在 result-chat-list 中添加功能按钮组 + - 在每条 assistant 消息下方添加 5 个按钮:复制、换个方向、不像我、继续生成、播放 + - 使用 `.message-actions` 样式类 + +3. **commit c2ed051**:ScriptView 复用 MessageCard 组件 + - 将消息卡片提取为独立的 `MessageCard.vue` 组件 + - MessageCard 包含完整功能:折叠、复制、换个方向、不像我、续写、改写、查看历史、删除、播放 + +4. **commit 2c778fa**(2026-07-01):**ScriptView 删除 read 模式 + 兼容旧模式,统一对话流入口** + - 删除了 102 行代码,包括所有使用 MessageCard 的调用 + - 模板中改为裸的 `` 渲染消息 + - **MessageCard 导入保留但不再使用**(行 241) + - **JS 函数保留**:`copyMessageContent`(行 422-438)、`playMessageTts`(行 440-447)、`toggleMessageCollapse`(行 409-420)、`getMessageDisplayContent`(行 402-407)、`isMessageCollapsed`(行 399) + - **`collapsedMessageIds` ref 保留**(行 287) + - **按钮组 UI 丢失** + +5. **ScriptDetailView.vue**:从未使用过 MessageCard,也从未有过这些功能 + +### 当前状态 + +**ScriptView.vue(生成页)**: +- ✅ 所有相关函数已存在(copyMessageContent、playMessageTts、toggleMessageCollapse 等) +- ✅ `collapsedMessageIds` ref 已存在 +- ❌ 模板中按钮组 UI 已丢失 +- ❌ 相关样式可能已删除或无用 + +**ScriptDetailView.vue(详情页)**: +- ❌ 完全没有相关函数 +- ❌ 完全没有 `collapsedMessageIds` ref +- ❌ 完全没有按钮组 UI +- ✅ 底部有全局播放按钮(`ttsPlayer.playSource`) + +## 设计方案 + +### 核心设计决策 + +| 维度 | 决策 | +|------|------| +| **功能范围** | 完整恢复所有按钮功能,但布局采用极简设计 | +| **页面范围** | 生成页(ScriptView)+ 详情页(ScriptDetailView) | +| **应用对象** | 仅 `kind === 'novel'` 的小说正文消息 | +| **按钮布局** | 每条 novel 消息下方:折叠/展开 + 复制 + 播放(3 个按钮)| +| **修订类按钮** | 放在底部操作区(已有),不在每条消息下重复 | + +### 设计原则 + +1. **极简设计**:每条 novel 消息下方只放 3 个核心功能按钮(折叠/展开、复制、播放) +2. **功能就近**:内容操作类按钮(复制、播放、折叠)贴近消息,用户操作直观 +3. **修订集中**:方向修订类按钮(换个方向、不像我、继续生成)集中在底部操作区,避免重复 +4. **样式统一**:两个页面使用相同的按钮组样式,保持视觉一致性 +5. **代码复用**:ScriptView 已有函数直接复用,ScriptDetailView 新增相同逻辑 + +### 功能实现细节 + +#### 1. 折叠/展开 + +**状态管理**: +```javascript +const collapsedMessageIds = ref({}) +``` + +**核心函数**: +```javascript +// 判断消息是否折叠 +const isMessageCollapsed = (message) => { + return Boolean(collapsedMessageIds.value[message.id]) +} + +// 获取消息显示内容(折叠时截断) +const getMessageDisplayContent = (message) => { + const content = String(message?.content || '') + if (!isMessageCollapsed(message)) return content + if (content.length <= 200) return content + return `${content.slice(0, 200)}...` +} + +// 切换折叠状态 +const toggleMessageCollapse = (message) => { + collapsedMessageIds.value = { + ...collapsedMessageIds.value, + [message.id]: !isMessageCollapsed(message) + } + analytics.track('script_message_collapse_toggle', { + message_id: message?.id || '', + collapsed: collapsedMessageIds.value[message.id] + }, { eventType: 'script', pagePath }) +} +``` + +**UI 交互**: +- 折叠时:显示前 200 字符 + "展开全文"按钮 +- 展开时:显示完整内容 + "收起全文"按钮 +- 折叠/展开按钮放在消息内容下方,按钮组上方 + +#### 2. 复制 + +**核心函数**: +```javascript +const copyMessageContent = (message) => { + const content = String(message?.content || '') + if (!content.trim()) { + uni.showToast({ title: '暂无可复制内容', icon: 'none' }) + return + } + uni.setClipboardData({ + data: content, + success: () => { + uni.showToast({ title: '已复制', icon: 'success' }) + } + }) + analytics.track('script_message_copy_click', { + message_id: message?.id || '', + content_length: content.length + }, { eventType: 'script', pagePath }) +} +``` + +**UI 交互**: +- 点击"复制"按钮,调用 `uni.setClipboardData` +- 成功复制后显示 Toast 提示"已复制" +- 内容为空时显示"暂无可复制内容" + +#### 3. 播放 + +**核心函数**: +```javascript +const playMessageTts = (message) => { + const scriptId = currentResult.value?.id || '' // ScriptView + // 或 script.value?.id || '' // ScriptDetailView + ttsPlayer.playSource(scriptId) + analytics.track('script_message_tts_click', { + message_id: message?.id || '', + script_id: scriptId + }, { eventType: 'script', pagePath }) +} +``` + +**UI 交互**: +- 播放图标动态显示:`▶`(未播放)/ `Ⅱ`(播放中) +- 播放文本动态显示:`播放`(未播放)/ `暂停`(播放中) +- 点击按钮调用 `ttsPlayer.playSource(scriptId)` 播放整个小说的 TTS 音频 + +### UI 设计 + +**每条 novel 消息下方按钮组**: +``` +┌─────────────────────────────────────┐ +│ [小说正文内容] │ +│ (折叠时显示前 200 字...) │ +│ │ +│ [▼ 展开全文] ← 折叠/展开按钮 │ +│ │ +│ ┌──────────┬──────────┬──────────┐ │ +│ │ 📋 复制 │ ▶ 播放 │ ⚙ 更多 │ │ ← 操作按钮组 +│ └──────────┴──────────┴──────────┘ │ +└─────────────────────────────────────┘ +``` + +**实际实现(3 个按钮)**: +``` +┌─────────────────────────────────────┐ +│ [小说正文内容] │ +│ │ +│ [▼ 展开全文] │ +│ │ +│ ┌──────────┬──────────┬──────────┐ │ +│ │ 复制 │ ▶ 播放 │ 收起 │ │ +│ └──────────┴──────────┴──────────┘ │ +└─────────────────────────────────────┘ +``` + +**按钮样式**: +- 参考 MessageCard 的 `result-actions` 样式(grid 布局) +- 3 个按钮横向排列,等宽分布 +- 播放按钮为 `primary` 样式(紫色渐变,突出显示) +- 折叠/展开按钮为独立行,放在按钮组上方 +- 按钮高度:72rpx +- 按钮圆角:28rpx +- 按钮背景:`rgba(88, 28, 135, 0.18)` +- 按钮边框:`1rpx solid rgba(192, 132, 252, 0.35)` + +### 页面差异化 + +| 页面 | 现有修订类按钮 | 需新增功能 | +|------|--------------|-----------| +| **生成页(ScriptView)** | 底部输入区已有"换个方向"、"不像我"等按钮 | 每条 novel 消息下加 3 个按钮(复用已有函数) | +| **详情页(ScriptDetailView)** | 底部已有"继续生成"按钮 | 每条 novel 消息下加 3 个按钮 + 新增所有函数 | + +### 应用对象 + +**只在 `kind === 'novel'` 的 assistant 消息上显示按钮组**: +- ✅ `kind === 'novel'`:小说正文,需要复制、播放、折叠/展开 +- ❌ `kind === 'card'`:澄清卡片,有特殊交互(提交按钮),不需要这些按钮 +- ❌ `kind === 'outline'`:大纲,结构化数据,不需要这些按钮 +- ❌ `kind === 'text'`:用户消息,不需要这些按钮 + +## 数据流与代码复用 + +### ScriptView(生成页) + +**已有资源**: +- ✅ `collapsedMessageIds` ref(行 287) +- ✅ `isMessageCollapsed(message)` 函数(行 399) +- ✅ `getMessageDisplayContent(message)` 函数(行 402-407) +- ✅ `toggleMessageCollapse(message)` 函数(行 409-420) +- ✅ `copyMessageContent(message)` 函数(行 422-438) +- ✅ `playMessageTts(message)` 函数(行 440-447) +- ✅ `ttsPlayer` composable(行 320) +- ✅ `ttsActionText` computed(行 986-990) +- ✅ `ttsActionIcon` computed(行 992-994) + +**需要补充**: +- ❌ 模板中按钮组 UI(在 `kind === 'novel'` 的消息下方添加) +- ❌ 按钮组样式(`.message-actions`、`.action-btn` 等) + +### ScriptDetailView(详情页) + +**需要新增**: +- ❌ `collapsedMessageIds` ref +- ❌ `isMessageCollapsed(message)` 函数 +- ❌ `getMessageDisplayContent(message)` 函数 +- ❌ `toggleMessageCollapse(message)` 函数 +- ❌ `copyMessageContent(message)` 函数 +- ❌ `playMessageTts(message)` 函数 +- ❌ 模板中按钮组 UI +- ❌ 按钮组样式 + +**已有资源**: +- ✅ `ttsPlayer` composable(行 110) +- ✅ `detailTtsActionText` computed(行 118-122) +- ✅ `detailTtsIcon` computed(行 124-126) + +## 实现步骤 + +### 步骤 1:ScriptView 恢复按钮组 UI + +1. 打开 `mini-program/src/pages/main/ScriptView.vue` +2. 定位到 `kind === 'novel'` 的消息渲染部分(约行 180-187) +3. 在 `` 内部: + - 将 `` 改为 `` + - 在 Markdown 下方添加折叠/展开按钮 + - 在折叠/展开按钮下方添加操作按钮组(复制、播放) +4. 添加按钮组样式(`.message-actions`、`.action-btn` 等) + +### 步骤 2:ScriptDetailView 新增函数 + +1. 打开 `mini-program/src/pages/main/ScriptDetailView.vue` +2. 在 `