实现消息级操作栏

本次更新

支持:

  • 复制单条消息
  • 删除单条消息
  • 重新生成上一条 AI 回复

1)改 web/src/App.vue

新增方法

javascript 复制代码
const copyMessage = async content => {
  try {
    await navigator.clipboard.writeText(content || '')
    window.alert('消息已复制')
  } catch (e) {
    console.error(e)
    window.alert('复制失败')
  }
}

const handleDeleteMessage = index => {
  if (!currentSession.value) return

  const nextMessages = currentSession.value.messages.filter((_, i) => i !== index)

  sessions.value = sortSessions(
    sessions.value.map(item =>
      item.id === currentSessionId.value
        ? {
            ...item,
            updatedAt: Date.now(),
            messages: nextMessages,
          }
        : item
    )
  )
}

const handleRegenerate = async index => {
  if (!currentSession.value || loading.value) return

  const messages = [...currentSession.value.messages]
  const current = messages[index]
  const prev = messages[index - 1]

  if (!current || current.role !== 'assistant') return
  if (!prev || prev.role !== 'user') {
    window.alert('只能重新生成上一条 AI 回复')
    return
  }

  const nextMessages = messages.slice(0, index)

  sessions.value = sortSessions(
    sessions.value.map(item =>
      item.id === currentSessionId.value
        ? {
            ...item,
            updatedAt: Date.now(),
            messages: nextMessages,
          }
        : item
    )
  )

  loading.value = true
  try {
    await sendMessageStream(nextMessages)
  } catch (error) {
    updateCurrentSession(session => ({
      ...session,
      updatedAt: Date.now(),
      messages: [
        ...session.messages,
        {
          role: 'assistant',
          content: '重新生成失败,请稍后再试。',
        },
      ],
    }))
    console.error(error)
  } finally {
    loading.value = false
    abortController.value = null
  }
}

改消息模板

ini 复制代码
<div
  v-for="(item, index) in currentMessages"
  :key="index"
  :class="['msg', item.role]"
>
  <div class="role-row">
    <div class="role">
      {{
        item.role === 'user'
          ? '我'
          : item.role === 'assistant'
          ? 'AI'
          : 'system'
      }}
    </div>

    <div v-if="item.role !== 'system'" class="msg-actions">
      <span class="msg-action-btn" @click="copyMessage(item.content)">复制</span>
      <span class="msg-action-btn delete" @click="handleDeleteMessage(index)">删除</span>
      <span
        v-if="item.role === 'assistant'"
        class="msg-action-btn"
        @click="handleRegenerate(index)"
      >
        重新生成
      </span>
    </div>
  </div>

  <div
    v-if="item.role === 'assistant'"
    class="content markdown-body"
    v-html="renderMarkdown(item.content)"
  />
  <div v-else class="content">{{ item.content }}</div>
</div>

新增样式

css 复制代码
.role-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 6px;
}

.msg-actions {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}

.msg-action-btn {
  font-size: 12px;
  color: #6b7280;
  cursor: pointer;
  user-select: none;
}

.msg-action-btn:hover {
  color: #111827;
}

.msg-action-btn.delete:hover {
  color: #dc2626;
}

2)验证

复制消息

点任意一条消息右侧的 复制

删除消息

删除 后,这条消息会从当前会话里移除

重新生成

找一条 AI 回复,点 重新生成

它会:

  1. 删除当前这条 AI 回复
  2. 保留前一条用户消息
  3. 重新走流式生成

nice 这一节非常简单

本节仓库提交地址

github.com/fhj414/ai-c...

相关推荐
渔阳节度使几秒前
SpringAi 1.1更新
人工智能·ai编程
测试_AI_一辰2 分钟前
AI测试工程师的统计学课:如何构建“反脆弱“的评估体系
人工智能·深度学习·机器学习·ai·ai编程
KaMeidebaby3 分钟前
卡梅德生物技术快报|基因测序技术在 46,XY 性发育障碍变异筛查中的流程与数据分析
服务器·前端·数据库·人工智能·算法·数据挖掘·数据分析
xier_ran7 分钟前
【infra之路】阶段二 · 模块二:CUDA 编程入门(下)— 矩阵乘法、tiling 优化与测量陷阱
人工智能·线性代数·矩阵
一拳一个娘娘腔7 分钟前
【SRC漏洞挖掘系列】第15期:自动化与AI赋能 —— 打造你的专属“漏洞挖掘机”
运维·人工智能·自动化
zhangfeng11337 分钟前
国家超算中心 系统自带模型 和pytorch 和cuda版本
人工智能·pytorch·python
小p8 分钟前
claude code 工程化学习2: 认识技能系统 Skill
人工智能
wgc2k8 分钟前
Nest.js基础-6:关于Claude Code
人工智能·docker·node.js
Resistance丶未来10 分钟前
魔芋 AI 企业级大模型落地实战指南
人工智能·api·claude·gemini·deepseek·魔芋ai·魔芋api
AI周红伟11 分钟前
长鑫科技存储之王:存储三强对比:三星、SK海力士 vs 长鑫科技
数据库·人工智能·科技·react.js·架构·langchain