feat: ScriptView 复用 MessageCard 组件

- story-card 使用 MessageCard
- result-chat-list 中的 assistant 消息按内容长度自动切换短消息/完整卡片模式

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-28 09:16:37 +08:00
parent cbf5157dcf
commit c2ed051de0
+34 -73
View File
@@ -169,89 +169,49 @@
</view> </view>
</view> </view>
<view class="story-card" :class="{ collapsed: storyCollapsed, dialogMode: resultHasScriptReplies }"> <MessageCard
<view class="story-head"> :content="displayedResultContent"
<view class="story-title-wrap"> :title="currentResult?.title"
<text class="story-title">{{ currentResult?.title || '我的人生剧本' }}</text> :tags="resultTags"
<view class="tag-row"> :collapsed="storyCollapsed"
<text v-for="tag in resultTags" :key="tag" class="tag">{{ tag }}</text> :content-length="displayedResultContent.length"
</view> :is-short-message="false"
</view> :tts-icon="ttsActionIcon"
<view class="story-head-actions"> :tts-text="ttsActionText"
<button class="collapse-icon" @click="toggleStoryCollapse"> @toggle-collapse="toggleStoryCollapse"
<text class="collapse-icon-text">{{ storyCollapsed ? '展开' : '收起' }}</text> @copy="copyResultContent"
<view class="collapse-chevron" :class="{ down: storyCollapsed }"> @change-direction="changeDirection"
<view></view> @not-like-me="notLikeMe"
<view></view> @continue="continueInChat"
</view> @play-tts="trackTtsClick"
</button> />
<button class="copy-card-btn" @click="copyResultContent">复制</button>
</view>
</view>
<scroll-view
v-if="storyCollapsed"
class="story-body-scroll"
scroll-y
:enhanced="true"
:show-scrollbar="true"
>
<text class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
</scroll-view>
<text v-else class="story-body" :selectable="true" :user-select="true">{{ displayedResultContent }}</text>
<view class="collapse-row" @click="toggleStoryCollapse">
<text class="collapse-row-text">{{ storyCollapsed ? '展开全文' : '收起全文' }}</text>
<view class="collapse-chevron" :class="{ down: storyCollapsed }">
<view></view>
<view></view>
</view>
</view>
<view class="result-actions">
<button class="action-btn" @click="changeDirection">换个方向</button>
<button class="action-btn" @click="notLikeMe">不像我</button>
<button class="action-btn" @click="continueInChat">继续生成</button>
<button class="action-btn primary" @click="trackTtsClick">
<text class="action-icon">{{ ttsActionIcon }}</text>
<text>{{ ttsActionText }}</text>
</button>
</view>
</view>
<view v-if="resultMessages.length" class="result-chat-list"> <view v-if="resultMessages.length" class="result-chat-list">
<view <view
v-for="message in resultMessages" v-for="message in resultMessages"
:key="message.id" :key="message.id"
class="chat-bubble"
:class="{ user: message.role === 'user', system: message.role === 'assistant', pending: message.pending }"
> >
<text selectable user-select>{{ getMessageDisplayContent(message) }}</text> <MessageCard
<view v-if="message.pending" class="thinking-dots">
<view></view>
<view></view>
<view></view>
</view>
<view
v-if="isAssistantMessage(message)" v-if="isAssistantMessage(message)"
class="message-toggle" :content="message.content"
@click.stop="toggleMessageCollapse(message)" :collapsed="isMessageCollapsed(message)"
> :content-length="message.content.length"
<text>{{ isMessageCollapsed(message) ? '展开' : '收起' }}</text> :is-short-message="message.content.length < 100"
<text class="message-toggle-icon" :class="{ open: !isMessageCollapsed(message) }"></text> :tts-icon="ttsPlayer.playing.value ? '' : ''"
</view> :tts-text="ttsPlayer.playing.value ? '暂停' : '播放'"
<view v-if="isAssistantMessage(message)" class="message-actions"> @toggle-collapse="toggleMessageCollapse(message)"
<button class="action-btn" @click="copyMessageContent(message)">复制</button> @copy="copyMessageContent(message)"
<button class="action-btn" @click="changeDirection">换个方向</button> @change-direction="changeDirection"
<button class="action-btn" @click="notLikeMe">不像我</button> @not-like-me="notLikeMe"
<button class="action-btn" @click="continueInChat">继续生成</button> @continue="continueInChat"
<button class="action-btn primary" @click="playMessageTts(message)"> @play-tts="playMessageTts(message)"
<text class="action-icon">{{ ttsPlayer.playing.value ? 'Ⅱ' : '▶' }}</text> />
<text>{{ ttsPlayer.playing.value ? '暂停' : '播放' }}</text> <view v-else class="chat-bubble user">
</button> <text>{{ message.content }}</text>
</view>
<text class="bubble-time">{{ message.time }}</text> <text class="bubble-time">{{ message.time }}</text>
</view> </view>
</view> </view>
</view>
<view v-if="resultChatting" class="generation-loading"> <view v-if="resultChatting" class="generation-loading">
<view class="loading-orbit streaming"> <view class="loading-orbit streaming">
@@ -312,6 +272,7 @@ import { useTtsPlayer } from '../../composables/useTtsPlayer.js'
import { useTypewriterStream } from '../../composables/useTypewriterStream.js' import { useTypewriterStream } from '../../composables/useTypewriterStream.js'
import { transcribeAudio } from '../../services/asr.js' import { transcribeAudio } from '../../services/asr.js'
import { streamAiScene } from '../../services/aiRuntime.js' import { streamAiScene } from '../../services/aiRuntime.js'
import MessageCard from '../../components/MessageCard.vue'
const store = useAppStore() const store = useAppStore()
const pagePath = '/pages/main/ScriptView' const pagePath = '/pages/main/ScriptView'