新增: Phase2 阶段收尾(Sprint 1-20)
重构:删 5 零引用 crate(df-evolve/plugin/stages/task/traceability)+ 清死模块、ai.rs 拆 11 子 module、ai.ts 拆 6 composable、i18n 拆目录 功能:知识库全栈(df-project/scan + CRUD + 时间线 + 前端)、Settings 拆分、appSettings KV 迁移、模型池、LLM 并发 Semaphore 修复:审批持久化根治、ConditionEngine 默认拒绝、NodeRegistry unimplemented 清除、promote 补偿删除、工具结果截断 50KB、路径校验防 symlink 逃逸 文档:B-03 人工审批设计、决策记录三分档、规格契约自检、经验记录、todo 看板、PROGRESS 更新 详见 PROGRESS.md。src-tauri/儿童每日打卡应用/ 与本项目无关,已排除。
This commit is contained in:
@@ -0,0 +1,107 @@
|
||||
//! 面板与持久化 — togglePanel/toggleMaximize + UI 持久化(restoreUiState/persistUiState)
|
||||
//! + token 开关 + providers/skills/clearChat
|
||||
//!
|
||||
//! 模块级私有:
|
||||
//! - 启动恢复:模块加载时 restoreUiState()(从 appSettings 读上次 UI 布局)
|
||||
//! - watch appSettings.cache['df-ai-ui']:loadAll() 异步填充后再次应用 UI 布局
|
||||
//!
|
||||
//! 耦合:
|
||||
//! - togglePanel/toggleMaximize/toggleArchivedFold/toggleSidebar 调 persistUiState
|
||||
|
||||
import { watch } from 'vue'
|
||||
import { aiApi } from '../../api'
|
||||
import { useAppSettingsStore } from '../../stores/appSettings'
|
||||
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)
|
||||
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
|
||||
}
|
||||
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
|
||||
},
|
||||
)
|
||||
|
||||
/** 持久化 UI 布局到 appSettings(debounced 写 SQLite) */
|
||||
export function persistUiState() {
|
||||
void appSettings.set('df-ai-ui', {
|
||||
panelOpen: state.panelOpen,
|
||||
maximized: state.maximized,
|
||||
sidebarOpen: state.sidebarOpen,
|
||||
archivedCollapsed: state.archivedCollapsed,
|
||||
})
|
||||
}
|
||||
|
||||
/** 切换面板展开/收起(收起时同步退出最大化,避免 v-show 卡死 main 交互) */
|
||||
function togglePanel() {
|
||||
state.panelOpen = !state.panelOpen
|
||||
// 关闭面板时同步退出最大化,避免 <main> 被 v-show 隐藏导致其他页面无法交互
|
||||
if (!state.panelOpen) state.maximized = false
|
||||
persistUiState()
|
||||
}
|
||||
|
||||
/** 最大化/还原侧栏宽度 */
|
||||
function toggleMaximize() {
|
||||
state.maximized = !state.maximized
|
||||
persistUiState()
|
||||
}
|
||||
|
||||
// ── Providers / Skills / 清屏 ──
|
||||
|
||||
/** 拉取 provider 列表(用于顶部 bar 展示与切换) */
|
||||
async function loadProviders() {
|
||||
state.providers = await aiApi.listProviders()
|
||||
}
|
||||
|
||||
/** 拉取本机技能列表(用于 `/` 联想,静默失败) */
|
||||
async function loadSkills() {
|
||||
try {
|
||||
state.skills = await aiApi.listSkills()
|
||||
} catch {
|
||||
// 静默失败,不影响主流程
|
||||
}
|
||||
}
|
||||
|
||||
/** 切换活跃 provider(后端 + 本地 state) */
|
||||
async function setProvider(providerId: string) {
|
||||
await aiApi.setProvider(providerId)
|
||||
state.activeProvider = providerId
|
||||
}
|
||||
|
||||
/** 清空当前会话消息(后端 + 本地 state) */
|
||||
async function clearChat() {
|
||||
await aiApi.clearChat()
|
||||
state.messages = []
|
||||
state.currentText = ''
|
||||
state.pendingApprovals = []
|
||||
state.streaming = false
|
||||
}
|
||||
|
||||
export function useAiPanel() {
|
||||
return {
|
||||
togglePanel,
|
||||
toggleMaximize,
|
||||
loadProviders,
|
||||
loadSkills,
|
||||
setProvider,
|
||||
clearChat,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user