docs:新增 MessageCard 组件统一设计文档
- 提取 MessageCard.vue 独立组件 - 按 100 字阈值自动切换短消息/完整卡片模式 - story-card 和 result-chat-list 复用同一组件
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
---
|
||||
author: claude
|
||||
created_at: 2026-06-27
|
||||
purpose: 提取 MessageCard 组件,统一所有 AI 消息卡片样式,按内容长度阈值(100 字)决定是否显示完整功能按钮
|
||||
---
|
||||
|
||||
# MessageCard 组件统一设计
|
||||
|
||||
## 背景
|
||||
|
||||
在上一轮实现中,result-chat-list 中的 assistant 消息使用了 `.chat-bubble.system` 气泡样式,与 `story-card` 的卡片样式不一致。用户要求:
|
||||
|
||||
1. 所有 AI 回复消息卡片的样式、功能、布局、按钮等,都与第一次生成剧本的 `story-card` 完全一致
|
||||
2. 内容 < 100 字的 assistant 消息:只显示消息内容,无功能按钮
|
||||
3. 内容 ≥ 100 字的 assistant 消息:必须与 `story-card` 完全一致
|
||||
|
||||
## 目标
|
||||
|
||||
- 提取独立的 `MessageCard.vue` 组件
|
||||
- story-card 和 result-chat-list 都复用该组件
|
||||
- 按 100 字阈值自动切换显示模式
|
||||
|
||||
## 方案选择
|
||||
|
||||
采用 **方案 B:提取独立 MessageCard.vue 组件**
|
||||
|
||||
- 代码复用,维护性好
|
||||
- 改动范围:新建 1 个组件 + 修改 ScriptView.vue
|
||||
|
||||
## 详细设计
|
||||
|
||||
### 1. 组件接口
|
||||
|
||||
**文件**:`mini-program/src/components/MessageCard.vue`
|
||||
|
||||
**Props:**
|
||||
|
||||
| Prop | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `content` | String | 是 | 消息/故事正文内容 |
|
||||
| `title` | String | 否 | 卡片标题,默认 `'我的人生剧本'` |
|
||||
| `tags` | Array | 否 | 标签列表 |
|
||||
| `collapsed` | Boolean | 是 | 当前折叠状态 |
|
||||
| `contentLength` | Number | 是 | 内容字数(用于阈值判断) |
|
||||
| `isShortMessage` | Boolean | 是 | `contentLength < 100` 时为 true |
|
||||
| `ttsIcon` | String | 否 | TTS 按钮图标(`▶` 或 `Ⅱ`) |
|
||||
| `ttsText` | String | 否 | TTS 按钮文字(`播放` 或 `暂停`) |
|
||||
|
||||
**Events:**
|
||||
|
||||
| 事件 | 说明 |
|
||||
|---|---|
|
||||
| `toggle-collapse` | 展开/收起 |
|
||||
| `copy` | 复制内容 |
|
||||
| `change-direction` | 换个方向 |
|
||||
| `not-like-me` | 不像我 |
|
||||
| `continue` | 继续生成 |
|
||||
| `play-tts` | 播放 TTS |
|
||||
|
||||
### 2. 组件内部结构
|
||||
|
||||
**短消息(`isShortMessage = true`)**:
|
||||
|
||||
```vue
|
||||
<view class="chat-bubble system">
|
||||
<text>{{ content }}</text>
|
||||
</view>
|
||||
```
|
||||
|
||||
只显示纯文本气泡,无标题、无标签、无按钮。
|
||||
|
||||
**长消息(`isShortMessage = false`)**:
|
||||
|
||||
完整复用现有 `story-card` 的 HTML 结构:
|
||||
|
||||
- 标题(`.story-title`)+ 标签(`.tag-row`)
|
||||
- 头部操作区:展开/收起按钮 + 复制按钮
|
||||
- 正文:展开时用 scroll-view,收起时用 text
|
||||
- 底部:展开全文/收起全文按钮
|
||||
- 功能按钮组(2 列网格):换个方向、不像我、继续生成、播放
|
||||
|
||||
### 3. ScriptView.vue 中的使用
|
||||
|
||||
**替换现有 story-card**:
|
||||
|
||||
```vue
|
||||
<MessageCard
|
||||
:content="displayedResultContent"
|
||||
:title="currentResult?.title"
|
||||
:tags="resultTags"
|
||||
:collapsed="storyCollapsed"
|
||||
:content-length="displayedResultContent.length"
|
||||
:is-short-message="false"
|
||||
:tts-icon="ttsActionIcon"
|
||||
:tts-text="ttsActionText"
|
||||
@toggle-collapse="toggleStoryCollapse"
|
||||
@copy="copyResultContent"
|
||||
@change-direction="changeDirection"
|
||||
@not-like-me="notLikeMe"
|
||||
@continue="continueInChat"
|
||||
@play-tts="trackTtsClick"
|
||||
/>
|
||||
```
|
||||
|
||||
**替换 result-chat-list 中的 assistant 消息**:
|
||||
|
||||
```vue
|
||||
<view v-for="message in resultMessages" :key="message.id">
|
||||
<MessageCard
|
||||
v-if="isAssistantMessage(message)"
|
||||
:content="message.content"
|
||||
:collapsed="isMessageCollapsed(message)"
|
||||
:content-length="message.content.length"
|
||||
:is-short-message="message.content.length < 100"
|
||||
:tts-icon="ttsPlayer.playing.value ? 'Ⅱ' : '▶'"
|
||||
:tts-text="ttsPlayer.playing.value ? '暂停' : '播放'"
|
||||
@toggle-collapse="toggleMessageCollapse(message)"
|
||||
@copy="copyMessageContent(message)"
|
||||
@change-direction="changeDirection"
|
||||
@not-like-me="notLikeMe"
|
||||
@continue="continueInChat"
|
||||
@play-tts="playMessageTts(message)"
|
||||
/>
|
||||
<view v-else class="chat-bubble user">
|
||||
<text>{{ message.content }}</text>
|
||||
<text class="bubble-time">{{ message.time }}</text>
|
||||
</view>
|
||||
</view>
|
||||
```
|
||||
|
||||
### 4. 样式迁移
|
||||
|
||||
将以下 CSS 类从 `ScriptView.vue` 迁移到 `MessageCard.vue` 的 `<style scoped>` 中:
|
||||
|
||||
- `.story-card`、`.story-card.collapsed`
|
||||
- `.story-head`、`.story-head-actions`、`.story-title-wrap`
|
||||
- `.story-title`、`.tag-row`、`.tag`
|
||||
- `.collapse-icon`、`.copy-card-btn`、`.collapse-row`
|
||||
- `.collapse-chevron`、`.story-body`、`.story-body-scroll`
|
||||
- `.result-actions`、`.action-btn`
|
||||
|
||||
`ScriptView.vue` 中删除这些已迁移的样式。
|
||||
|
||||
### 5. 边界情况
|
||||
|
||||
| 场景 | 行为 |
|
||||
|---|---|
|
||||
| content 刚好 100 字 | `isShortMessage = false`,显示完整卡片 |
|
||||
| content 为空 | 显示空卡片(与 story-card 现有行为一致) |
|
||||
| pending 中的消息 | 不使用 MessageCard,保持 thinking-dots 渲染 |
|
||||
| user 消息 | 不使用 MessageCard,保持 `.chat-bubble.user` 气泡 |
|
||||
|
||||
## 修改范围
|
||||
|
||||
| 文件 | 操作 |
|
||||
|---|---|
|
||||
| `mini-program/src/components/MessageCard.vue` | 新建 |
|
||||
| `mini-program/src/pages/main/ScriptView.vue` | 修改(模板 + 脚本 + 样式) |
|
||||
Reference in New Issue
Block a user