优化: AI模块(provider重试兼容+aichat交互+工具卡片可读化+diff高亮)

This commit is contained in:
lxy
2026-06-16 02:33:16 +08:00
parent d2cb38cdac
commit 10e4945e5a
26 changed files with 2337 additions and 332 deletions
+39 -15
View File
@@ -15,30 +15,40 @@ import { state } from '@/stores/ai'
const appSettings = useAppSettingsStore()
// 启动恢复:从 appSettings(SQLite)读取上次的 UI 布局(模块级单例 state)
// detached/docked 不恢复 — 重启后分离窗口必然不存在,必须回 false
export function restoreUiState() {
const s = appSettings.get<any>('df-ai-ui', null)
/** 侧栏宽度可拖拽范围(UX-2025-16)。120=窄屏友好,280=宽屏舒适 */
export const SIDEBAR_WIDTH_MIN = 120
export const SIDEBAR_WIDTH_MAX = 280
export const SIDEBAR_WIDTH_DEFAULT = 200
/** clamp 侧栏宽度到合法区间;非法/缺省值回默认(防 NaN/0/负数污染 state) */
function clampSidebarWidth(v: any): number {
const n = typeof v === 'number' && Number.isFinite(v) ? v : SIDEBAR_WIDTH_DEFAULT
return Math.min(SIDEBAR_WIDTH_MAX, Math.max(SIDEBAR_WIDTH_MIN, n))
}
/**
* 将缓存的 UI 布局对象安全应用到模块级 state(仅 boolean 字段覆盖,其余忽略)。
* restoreUiState 与 watch 回调共用,消除重复赋值。
* detached/docked 不恢复 — 重启后分离窗口必然不存在,必须回 false
*/
function applyUiState(s: any) {
if (!s) return
if (typeof s.panelOpen === 'boolean') state.panelOpen = s.panelOpen
if (typeof s.maximized === 'boolean') state.maximized = s.maximized
if (typeof s.sidebarOpen === 'boolean') state.sidebarOpen = s.sidebarOpen
if (typeof s.archivedCollapsed === 'boolean') state.archivedCollapsed = s.archivedCollapsed
// 侧栏宽度(UX-2025-16):数值字段,clamp 后写入(与上方 boolean 同级兜底)
state.sidebarWidth = clampSidebarWidth(s.sidebarWidth)
}
// 启动恢复:从 appSettings(SQLite)读取上次的 UI 布局(模块级单例 state)
export function restoreUiState() {
applyUiState(appSettings.get<any>('df-ai-ui', null))
}
restoreUiState()
// loadAll() 异步填充缓存后,再次应用 UI 布局(模块级 state,watch 仅触发一次)
watch(
() => appSettings.cache['df-ai-ui'],
(v) => {
if (!v) return
const s = v as any
if (typeof s.panelOpen === 'boolean') state.panelOpen = s.panelOpen
if (typeof s.maximized === 'boolean') state.maximized = s.maximized
if (typeof s.sidebarOpen === 'boolean') state.sidebarOpen = s.sidebarOpen
if (typeof s.archivedCollapsed === 'boolean') state.archivedCollapsed = s.archivedCollapsed
},
)
watch(() => appSettings.cache['df-ai-ui'], (v) => applyUiState(v as any))
/** 持久化 UI 布局到 appSettings(debounced 写 SQLite) */
export function persistUiState() {
@@ -47,9 +57,20 @@ export function persistUiState() {
maximized: state.maximized,
sidebarOpen: state.sidebarOpen,
archivedCollapsed: state.archivedCollapsed,
// 侧栏宽度(UX-2025-16):拖拽 mouseup 时由 AiChat 调 persistUiState 落盘
sidebarWidth: state.sidebarWidth,
})
}
/**
* 设置侧栏宽度(clamp 后写 state,不持久化)。
* 拖拽 mousemove 高频调用,持久化由调用方在 mouseup 时一次 persistUiState() 完成,
* 避免每像素触发 debounced SQLite 写。
*/
export function setSidebarWidth(px: number) {
state.sidebarWidth = clampSidebarWidth(px)
}
/** 切换面板展开/收起(收起时同步退出最大化,避免 v-show 卡死 main 交互) */
function togglePanel() {
state.panelOpen = !state.panelOpen
@@ -103,5 +124,8 @@ export function useAiPanel() {
loadSkills,
setProvider,
clearChat,
// UX-2025-16:侧栏宽度拖拽
setSidebarWidth,
persistUiState,
}
}