新增: 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:
@@ -7,6 +7,7 @@ import type { ProjectRecord, TaskRecord, IdeaRecord, WorkflowRecord, WorkflowEve
|
||||
|
||||
const state = reactive({
|
||||
projects: [] as ProjectRecord[],
|
||||
deletedProjects: [] as ProjectRecord[],
|
||||
tasks: [] as TaskRecord[],
|
||||
ideas: [] as IdeaRecord[],
|
||||
workflowExecutions: [] as WorkflowRecord[],
|
||||
@@ -24,7 +25,7 @@ const state = reactive({
|
||||
|
||||
let _eventUnlisten: (() => void) | null = null
|
||||
|
||||
export function useProjectStore() {
|
||||
function createStore() {
|
||||
// ── 项目 CRUD ──
|
||||
async function loadProjects() {
|
||||
state.loading = true
|
||||
@@ -38,10 +39,18 @@ export function useProjectStore() {
|
||||
}
|
||||
}
|
||||
|
||||
async function createProject(name: string, description = '', ideaId?: string) {
|
||||
const record = await projectApi.create({ name, description, idea_id: ideaId })
|
||||
state.projects.push(record)
|
||||
return record
|
||||
// 清除错误状态(供 toast 显示后重置,允许连续同值错误再次触发 watch)
|
||||
function clearError() { state.error = null }
|
||||
|
||||
async function createProject(name: string, description = '', ideaId?: string, path?: string, stack?: string) {
|
||||
try {
|
||||
const record = await projectApi.create({ name, description, idea_id: ideaId, path, stack })
|
||||
state.projects.push(record)
|
||||
return record
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '创建项目失败'
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function updateProject(id: string, field: string, value: string) {
|
||||
@@ -52,9 +61,48 @@ export function useProjectStore() {
|
||||
}
|
||||
}
|
||||
|
||||
/** 重定位项目目录(后端重探测 stack,返回最新记录并更新本地状态) */
|
||||
async function relocateProjectPath(id: string, newPath: string) {
|
||||
const record = await projectApi.relocatePath(id, newPath)
|
||||
const idx = state.projects.findIndex(p => p.id === id)
|
||||
if (idx >= 0) state.projects[idx] = record
|
||||
return record
|
||||
}
|
||||
|
||||
async function deleteProject(id: string) {
|
||||
await projectApi.delete(id)
|
||||
state.projects = state.projects.filter(p => p.id !== id)
|
||||
try {
|
||||
await projectApi.delete(id) // 软删 → 回收站(可恢复)
|
||||
state.projects = state.projects.filter(p => p.id !== id)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '删除项目失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDeletedProjects() {
|
||||
try {
|
||||
state.deletedProjects = await projectApi.listDeleted()
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '加载回收站失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function restoreProject(id: string) {
|
||||
try {
|
||||
await projectApi.restore(id)
|
||||
state.deletedProjects = state.deletedProjects.filter(p => p.id !== id)
|
||||
await loadProjects() // 恢复后刷新活跃列表
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '恢复项目失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function purgeProject(id: string) {
|
||||
try {
|
||||
await projectApi.purge(id) // 彻底删(级联物理删,不可恢复)
|
||||
state.deletedProjects = state.deletedProjects.filter(p => p.id !== id)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '彻底删除失败'
|
||||
}
|
||||
}
|
||||
|
||||
// ── 任务 CRUD ──
|
||||
@@ -67,9 +115,14 @@ export function useProjectStore() {
|
||||
}
|
||||
|
||||
async function createTask(input: { project_id: string; title: string; description?: string; priority?: number; branch_name?: string; assignee?: string }) {
|
||||
const record = await taskApi.create(input)
|
||||
state.tasks.push(record)
|
||||
return record
|
||||
try {
|
||||
const record = await taskApi.create(input)
|
||||
state.tasks.push(record)
|
||||
return record
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '创建任务失败'
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function updateTask(id: string, field: string, value: string) {
|
||||
@@ -81,8 +134,12 @@ export function useProjectStore() {
|
||||
}
|
||||
|
||||
async function deleteTask(id: string) {
|
||||
await taskApi.delete(id)
|
||||
state.tasks = state.tasks.filter(t => t.id !== id)
|
||||
try {
|
||||
await taskApi.delete(id)
|
||||
state.tasks = state.tasks.filter(t => t.id !== id)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '删除任务失败'
|
||||
}
|
||||
}
|
||||
|
||||
// ── 想法 CRUD ──
|
||||
@@ -95,9 +152,14 @@ export function useProjectStore() {
|
||||
}
|
||||
|
||||
async function createIdea(input: { title: string; description?: string; priority?: number; tags?: string; source?: string }) {
|
||||
const record = await ideaApi.create(input)
|
||||
state.ideas.push(record)
|
||||
return record
|
||||
try {
|
||||
const record = await ideaApi.create(input)
|
||||
state.ideas.push(record)
|
||||
return record
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '创建想法失败'
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
async function updateIdea(id: string, field: string, value: string) {
|
||||
@@ -109,8 +171,25 @@ export function useProjectStore() {
|
||||
}
|
||||
|
||||
async function deleteIdea(id: string) {
|
||||
await ideaApi.delete(id)
|
||||
state.ideas = state.ideas.filter(i => i.id !== id)
|
||||
try {
|
||||
await ideaApi.delete(id)
|
||||
state.ideas = state.ideas.filter(i => i.id !== id)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '删除想法失败'
|
||||
}
|
||||
}
|
||||
|
||||
async function evaluateIdea(id: string) {
|
||||
const record = await ideaApi.evaluate(id)
|
||||
const idx = state.ideas.findIndex(i => i.id === id)
|
||||
if (idx >= 0) state.ideas[idx] = record
|
||||
return record
|
||||
}
|
||||
|
||||
async function promoteIdea(id: string) {
|
||||
const res = await ideaApi.promote(id)
|
||||
await loadIdeas() // 后端已回写 status=promoted/promoted_to,刷新列表
|
||||
return res
|
||||
}
|
||||
|
||||
// ── 工作流 ──
|
||||
@@ -129,11 +208,14 @@ export function useProjectStore() {
|
||||
async function startEventListener() {
|
||||
if (_eventUnlisten) return _eventUnlisten
|
||||
_eventUnlisten = await workflowApi.onEvent((payload) => {
|
||||
state.liveEvents.push(payload)
|
||||
|
||||
// 处理人工审批请求
|
||||
if (payload.event.type === 'HumanApprovalRequest') {
|
||||
state.pendingApproval = payload.event.data as typeof state.pendingApproval
|
||||
try {
|
||||
state.liveEvents.push(payload)
|
||||
// 处理人工审批请求
|
||||
if (payload.event?.type === 'HumanApprovalRequest') {
|
||||
state.pendingApproval = payload.event.data as typeof state.pendingApproval
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('处理工作流事件失败:', e, payload)
|
||||
}
|
||||
})
|
||||
return _eventUnlisten
|
||||
@@ -182,20 +264,24 @@ export function useProjectStore() {
|
||||
}))
|
||||
|
||||
return reactive({
|
||||
// reactive state — 直接引用 state 属性,已经是响应式的
|
||||
projects: state.projects,
|
||||
tasks: state.tasks,
|
||||
ideas: state.ideas,
|
||||
workflowExecutions: state.workflowExecutions,
|
||||
liveEvents: state.liveEvents,
|
||||
loading: state.loading,
|
||||
error: state.error,
|
||||
// 状态用 getter 实时读 state —— 直接 ideas: state.ideas 会快照引用,
|
||||
// loadIdeas 等重新赋值 state.ideas 时返回对象的 ideas 属性不跟随,刷新后视图为空
|
||||
get projects() { return state.projects },
|
||||
get tasks() { return state.tasks },
|
||||
get ideas() { return state.ideas },
|
||||
get workflowExecutions() { return state.workflowExecutions },
|
||||
get liveEvents() { return state.liveEvents },
|
||||
get loading() { return state.loading },
|
||||
get error() { return state.error },
|
||||
clearError,
|
||||
get deletedProjects() { return state.deletedProjects },
|
||||
// project actions
|
||||
loadProjects, createProject, updateProject, deleteProject,
|
||||
loadProjects, createProject, updateProject, deleteProject, relocateProjectPath,
|
||||
loadDeletedProjects, restoreProject, purgeProject,
|
||||
// task actions
|
||||
loadTasks, createTask, updateTask, deleteTask,
|
||||
// idea actions
|
||||
loadIdeas, createIdea, updateIdea, deleteIdea,
|
||||
loadIdeas, createIdea, updateIdea, deleteIdea, evaluateIdea, promoteIdea,
|
||||
// workflow actions
|
||||
runWorkflow, loadWorkflowExecutions, startEventListener, stopEventListener, clearLiveEvents,
|
||||
approveHumanApproval, pendingApproval: computed(() => state.pendingApproval),
|
||||
@@ -203,3 +289,13 @@ export function useProjectStore() {
|
||||
stats,
|
||||
})
|
||||
}
|
||||
|
||||
type ProjectStore = ReturnType<typeof createStore>
|
||||
let _storeInstance: ProjectStore | null = null
|
||||
|
||||
/** 项目/任务/想法/工作流 全局状态(单例,多组件复用同一 reactive 包装) */
|
||||
export function useProjectStore(): ProjectStore {
|
||||
if (_storeInstance) return _storeInstance
|
||||
_storeInstance = createStore()
|
||||
return _storeInstance
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user