新增: aichat前端体验四件与队列残留收口
- R4 代码块语言角标:MessageList decorateCodeHtml 捕获 language-xxx 输出 data-lang+CSS ::before 左上角标,hover 显,无语言裸块不渲染 - R6 工具结果路径可复制:ToolResultBody 五处 file-bar 的 path span→button(read_file/list_directory/search_files/grep/patch_file),点击复制完整路径+✓/✕ 1.2s 反馈+execCommand 降级链 - I6 重新生成 UI 入口:MessageItem user 气泡 hover 补重新生成按钮(canRegenerate=isLastUser&&非流式),复用 handleRetry→store.regenerate 链路 - V4 浮窗审批 High 风险二次确认:useToolApproval 导出 isHighRiskTool/highRiskConfirmText,ApprovalPopup.onApprove 前置 ConfirmDialog,数字键守卫不绕确认 - 9-28#5 两处全局清队列残留:useAiEvents/useAiLifecycleEvents 无 convId 的 AiError 分支改保留队列+console.warn(防误伤其他会话排队消息) - i18n zh/en 补 clickToCopy 键;裸 @ 改 @ 转义(vue-i18n linked-message 前缀吞噬)
This commit is contained in:
@@ -34,11 +34,14 @@ defineProps<{
|
||||
msg: AiMessage
|
||||
/** 是否显示编辑按钮(父合成:末条 user + 非生成中 + 非编辑中) */
|
||||
canEdit?: boolean
|
||||
/** I6:是否显示重新生成按钮(父合成同 canEdit 时机;作用于末条 user 触发的回复) */
|
||||
canRegenerate?: boolean
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'copy', msg: AiMessage): void
|
||||
(e: 'start-edit', msg: AiMessage): void
|
||||
(e: 'regenerate', msg: AiMessage): void
|
||||
}>()
|
||||
|
||||
// ── Input Augmentation: 按 mention 区间切段 ──
|
||||
@@ -122,6 +125,10 @@ function imgAlt(img: ImageContentPart): string {
|
||||
<img v-for="(img, idx) in msgImageParts(msg)" :key="msg.id + '-img-' + idx" :src="imageSrc(img)" :alt="imgAlt(img)" class="ai-msg-image" loading="lazy" />
|
||||
</div>
|
||||
</template>
|
||||
<!-- I6:重新生成按钮(hover,编辑按钮左侧);复用后端 regenerate 链路(弹末尾 AI 回复取触发 user 消息重跑) -->
|
||||
<button v-if="canRegenerate" class="ai-msg-regen-btn" :title="t('aiChat.regenerate')" @click.stop="emit('regenerate', msg)">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/></svg>
|
||||
</button>
|
||||
<!-- UX-09:末条 user 消息编辑按钮(hover 显示),点击经 start-edit 链回填输入框编辑重发 -->
|
||||
<button v-if="canEdit" class="ai-msg-edit-btn" :title="t('aiChat.editMessage')" @click.stop="emit('start-edit', msg)">
|
||||
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 013 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
|
||||
@@ -195,8 +202,9 @@ function imgAlt(img: ImageContentPart): string {
|
||||
max-height: 200px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
/* 复制/编辑按钮(hover 显示,同栏同视觉;编辑按钮仅 canEdit 时渲染) */
|
||||
/* 复制/编辑/重新生成按钮(hover 显示,同栏同视觉;编辑/重新生成仅各自 can* 时渲染) */
|
||||
.ai-copy-btn,
|
||||
.ai-msg-regen-btn,
|
||||
.ai-msg-edit-btn {
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s;
|
||||
@@ -207,7 +215,11 @@ function imgAlt(img: ImageContentPart): string {
|
||||
color: var(--df-text-dim);
|
||||
}
|
||||
.ai-msg-user:hover .ai-copy-btn,
|
||||
.ai-msg-user:hover .ai-msg-regen-btn,
|
||||
.ai-msg-user:hover .ai-msg-edit-btn {
|
||||
opacity: 1;
|
||||
}
|
||||
.ai-msg-regen-btn:hover {
|
||||
color: var(--df-accent);
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user