Files
DevFlow/src/stores/knowledge.ts
绝尘 cf017f81e2 新增: 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/儿童每日打卡应用/ 与本项目无关,已排除。
2026-06-14 14:08:20 +08:00

157 lines
4.7 KiB
TypeScript

import { reactive, computed } from 'vue'
import { knowledgeApi } from '../api'
import type {
KnowledgeRecord,
KnowledgeDetailPayload,
KnowledgeEventRecord,
CreateKnowledgeInput,
UpdateKnowledgeInput,
KnowledgeConfig,
} from '../api/types'
// ── 全局响应式状态(单例) ──
const state = reactive({
items: [] as KnowledgeRecord[],
candidates: [] as KnowledgeRecord[],
config: null as KnowledgeConfig | null,
loading: false,
error: null as string | null,
})
// 7 种知识类型(snake_case,与后端 KnowledgeKind 对齐)
// 仅存 key + icon;展示文案(label)走 i18n: $t('knowledge.kind.<key>')
export const KNOWLEDGE_KINDS = [
{ key: 'review_rule', icon: '🔍' },
{ key: 'prompt_template', icon: '💬' },
{ key: 'pitfall', icon: '⚠️' },
{ key: 'architecture_pattern', icon: '🏛️' },
{ key: 'diagnosis', icon: '🩺' },
{ key: 'deployment_note', icon: '🚀' },
{ key: 'workflow_optimization', icon: '⚡' },
] as const
/** 解析 tags JSON 字符串为 string[] */
export function parseTags(tags: string | null): string[] {
if (!tags) return []
try {
const arr = JSON.parse(tags)
return Array.isArray(arr) ? arr : []
} catch {
return []
}
}
export function useKnowledgeStore() {
// ── 加载列表(默认排除 archived) ──
async function loadList(status?: string) {
state.loading = true
state.error = null
try {
state.items = await knowledgeApi.list(status ?? null)
} catch (e: any) {
state.error = e?.toString() ?? '加载知识库失败'
} finally {
state.loading = false
}
}
// ── 加载审核收件箱(候选列表) ──
async function loadCandidates() {
try {
state.candidates = await knowledgeApi.listCandidates()
} catch (e: any) {
state.error = e?.toString() ?? '加载收件箱失败'
}
}
async function search(query: string, kind?: string) {
state.loading = true
state.error = null
try {
state.items = await knowledgeApi.search({ query, kind })
} catch (e: any) {
state.error = e?.toString() ?? '检索失败'
} finally {
state.loading = false
}
}
async function create(input: CreateKnowledgeInput) {
const record = await knowledgeApi.create(input)
// 手动录入默认 candidate,刷新收件箱
await loadCandidates()
return record
}
async function updateStatus(id: string, status: string) {
await knowledgeApi.updateStatus(id, status)
// 从 items 和 candidates 中同步移除
state.items = state.items.filter(k => k.id !== id)
state.candidates = state.candidates.filter(k => k.id !== id)
}
async function archive(id: string) {
await knowledgeApi.archive(id)
state.items = state.items.filter(k => k.id !== id)
state.candidates = state.candidates.filter(k => k.id !== id)
}
// ── 配置 ──
async function loadConfig() {
try {
state.config = await knowledgeApi.getConfig()
} catch (e: any) {
state.error = e?.toString() ?? '加载配置失败'
}
}
async function saveConfig(config: KnowledgeConfig) {
await knowledgeApi.saveConfig(config)
state.config = config
}
async function extractNow() {
await knowledgeApi.extractNow()
await loadCandidates()
}
// ── 生命线:详情 / 编辑 / 事件查询(按需调用,不入全局 state) ──
async function getDetail(id: string): Promise<KnowledgeDetailPayload> {
return knowledgeApi.getDetail(id)
}
async function update(id: string, input: UpdateKnowledgeInput): Promise<KnowledgeRecord> {
const updated = await knowledgeApi.update(id, input)
// 同步刷新内存中的列表/收件箱条目
const patch = (arr: KnowledgeRecord[]) => {
const idx = arr.findIndex(k => k.id === id)
if (idx >= 0) arr[idx] = { ...arr[idx], ...updated }
}
patch(state.items)
patch(state.candidates)
return updated
}
async function getEvents(knowledgeId: string, eventType?: string, limit?: number): Promise<KnowledgeEventRecord[]> {
return knowledgeApi.events(knowledgeId, eventType, limit)
}
// 候选数量(供侧栏 badge 用)
const candidateCount = computed(() => state.candidates.length)
return reactive({
// 状态用 getter 实时读 state(防快照不跟随,同 project store 模式)
get items() { return state.items },
get candidates() { return state.candidates },
get config() { return state.config },
get loading() { return state.loading },
get error() { return state.error },
candidateCount,
// actions
loadList, loadCandidates, search, create, updateStatus, archive,
loadConfig, saveConfig, extractNow,
getDetail, update, getEvents,
})
}