优化: 所有剩余UI/UX待办一批完成(持久化+AuditLog+解耦+total+原12大改+P2)
持久化(P1-c):新建 usePersistedRef composable,Tasks/AuditLog/ProjectDetail 等接入 localStorage
AuditLog(P1-d):后端 list_tool_executions 加 WHERE 筛选+返 {items,total,has_more},前端对接+长列折叠+筛选持久化
数据源解耦(P1-g):ProjectDetail projectTasks 按 project_id 独立加载 + ChatInput @项目联想独立加载(不读 store.tasks 当前页)
GitChanges(12a):后端 get_module_commits 加 git rev-list --count 返 total,前端显真实总数
原12大改:Dashboard 统计卡压底行(1)/Projects 列表卡片视图(2)/project_event 埋点排序(3)/TaskDetail 重设计(4)/IdeaDetail 重设计(5)/KnowledgeDetail 重设计(6)/界面持久化+侧栏Ctrl+B+审批数字键(7)/ProjectDetail 三栏改两栏(10)
P2打磨:文件浏览器(FileTree去重/FilePreview行号.md Diff/selectedFilePath归位)/settings反馈(假保存/端口校验)/AI会话(try-catch/scrollIntoView)/后端计数(move_queue事件/timeline total/workflow分页/import_batch分块)/杂项(TopBar/ConfirmDialog键盘/CIStatus i18n/ToolResultBody/ModuleNode/ApprovalDialog全选)
This commit is contained in:
@@ -53,8 +53,14 @@
|
||||
<button class="ai-btn-icon" @click="emit('new-conversation')" :title="$t('aiChat.newConversation')">
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
|
||||
</button>
|
||||
<!-- 清空对话(真删 DB messages,带二次确认防误删)。高频常用,常驻。 -->
|
||||
<button class="ai-btn-icon" @click="emit('clear-chat')" :title="$t('aiChat.clearChat')">
|
||||
<!-- 清空对话(真删 DB messages,带二次确认防误删)。高频常用,常驻。
|
||||
disabled:无活跃消息(空会话)或流式中(避免并发删/写),对齐 clear-context 项语义。 -->
|
||||
<button
|
||||
class="ai-btn-icon"
|
||||
:disabled="!hasActiveMessages || store.state.streaming"
|
||||
:title="$t('aiChat.clearChat')"
|
||||
@click="emit('clear-chat')"
|
||||
>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 01-2 2H8a2 2 0 01-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 011-1h4a1 1 0 011 1v2"/></svg>
|
||||
</button>
|
||||
|
||||
@@ -391,8 +397,22 @@ const historyExpanded = ref(false)
|
||||
/** 点击历史消息项 → 滚动定位到对应的消息气泡 */
|
||||
function scrollToMessage(msgId: string) {
|
||||
historyExpanded.value = false
|
||||
// 消息列表已有 data-msg-id 属性,直接 DOM 查询定位
|
||||
const el = document.querySelector(`[data-msg-id="${msgId}"]`)
|
||||
// 消息列表已有 data-msg-id 属性,直接 DOM 查询定位。
|
||||
// BUG-260802:msgId 由后端生成,可能含 CSS 选择器元字符(: . [ ] / 空格 等),
|
||||
// 模板拼 selector 会被选择器解析器当伪类/类名异常 → querySelector 抛错或返回 null。
|
||||
// 用 CSS.escape 转义 msgId,确保任意字符串安全嵌入属性选择器。
|
||||
// 旧浏览器无 CSS.escape 的兜底:encodeURIComponent + attr*= 模糊匹配(非精确,降级路径)。
|
||||
let el: Element | null = null
|
||||
const escaped = typeof CSS !== 'undefined' && typeof CSS.escape === 'function'
|
||||
? CSS.escape(msgId)
|
||||
: encodeURIComponent(msgId)
|
||||
try {
|
||||
el = document.querySelector(`[data-msg-id="${escaped}"]`)
|
||||
} catch {
|
||||
// 转义后仍异常(理论不会)→ 退化为遍历查找
|
||||
const all = document.querySelectorAll('[data-msg-id]')
|
||||
el = Array.from(all).find(n => n.getAttribute('data-msg-id') === msgId) ?? null
|
||||
}
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: 'smooth', block: 'center' })
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user