新增: 初始化 DevFlow 项目仓库
Tauri 2 + Vue 3 + Vite 6 桌面应用,Rust workspace 含 13 个 crate (df-ai / df-storage / df-workflow / df-core / df-execute 等)。 核心能力:AI 聊天 agentic 循环(工具调用+人工审批)、工作流引擎、 任务/想法/项目/阶段管理、可追溯性,及配套前端组件。
This commit is contained in:
205
src/stores/project.ts
Normal file
205
src/stores/project.ts
Normal file
@@ -0,0 +1,205 @@
|
||||
import { reactive, computed } from 'vue'
|
||||
import { invoke } from '@tauri-apps/api/core'
|
||||
import { projectApi, taskApi, ideaApi, workflowApi } from '../api'
|
||||
import type { ProjectRecord, TaskRecord, IdeaRecord, WorkflowRecord, WorkflowEventPayload } from '../api/types'
|
||||
|
||||
// ── 全局响应式状态(单例) ──
|
||||
|
||||
const state = reactive({
|
||||
projects: [] as ProjectRecord[],
|
||||
tasks: [] as TaskRecord[],
|
||||
ideas: [] as IdeaRecord[],
|
||||
workflowExecutions: [] as WorkflowRecord[],
|
||||
liveEvents: [] as WorkflowEventPayload[],
|
||||
pendingApproval: null as {
|
||||
execution_id: string
|
||||
node_id: string
|
||||
title: string
|
||||
description: string
|
||||
options: string[]
|
||||
} | null,
|
||||
loading: false,
|
||||
error: null as string | null,
|
||||
})
|
||||
|
||||
let _eventUnlisten: (() => void) | null = null
|
||||
|
||||
export function useProjectStore() {
|
||||
// ── 项目 CRUD ──
|
||||
async function loadProjects() {
|
||||
state.loading = true
|
||||
state.error = null
|
||||
try {
|
||||
state.projects = await projectApi.list()
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '加载项目失败'
|
||||
} finally {
|
||||
state.loading = false
|
||||
}
|
||||
}
|
||||
|
||||
async function createProject(name: string, description = '', ideaId?: string) {
|
||||
const record = await projectApi.create({ name, description, idea_id: ideaId })
|
||||
state.projects.push(record)
|
||||
return record
|
||||
}
|
||||
|
||||
async function updateProject(id: string, field: string, value: string) {
|
||||
await projectApi.update(id, field, value)
|
||||
const idx = state.projects.findIndex(p => p.id === id)
|
||||
if (idx >= 0) {
|
||||
(state.projects[idx] as any)[field] = value
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteProject(id: string) {
|
||||
await projectApi.delete(id)
|
||||
state.projects = state.projects.filter(p => p.id !== id)
|
||||
}
|
||||
|
||||
// ── 任务 CRUD ──
|
||||
async function loadTasks(projectId?: string) {
|
||||
try {
|
||||
state.tasks = await taskApi.list(projectId)
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '加载任务失败'
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
async function updateTask(id: string, field: string, value: string) {
|
||||
await taskApi.update(id, field, value)
|
||||
const idx = state.tasks.findIndex(t => t.id === id)
|
||||
if (idx >= 0) {
|
||||
(state.tasks[idx] as any)[field] = value
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteTask(id: string) {
|
||||
await taskApi.delete(id)
|
||||
state.tasks = state.tasks.filter(t => t.id !== id)
|
||||
}
|
||||
|
||||
// ── 想法 CRUD ──
|
||||
async function loadIdeas() {
|
||||
try {
|
||||
state.ideas = await ideaApi.list()
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '加载想法失败'
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
async function updateIdea(id: string, field: string, value: string) {
|
||||
await ideaApi.update(id, field, value)
|
||||
const idx = state.ideas.findIndex(i => i.id === id)
|
||||
if (idx >= 0) {
|
||||
(state.ideas[idx] as any)[field] = value
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteIdea(id: string) {
|
||||
await ideaApi.delete(id)
|
||||
state.ideas = state.ideas.filter(i => i.id !== id)
|
||||
}
|
||||
|
||||
// ── 工作流 ──
|
||||
async function runWorkflow(name: string, dag: unknown, config?: Record<string, unknown>) {
|
||||
return await workflowApi.run(name, dag, config)
|
||||
}
|
||||
|
||||
async function loadWorkflowExecutions() {
|
||||
try {
|
||||
state.workflowExecutions = await workflowApi.listExecutions()
|
||||
} catch (e: any) {
|
||||
state.error = e?.toString() ?? '加载工作流记录失败'
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
return _eventUnlisten
|
||||
}
|
||||
|
||||
function clearLiveEvents() {
|
||||
state.liveEvents = []
|
||||
}
|
||||
|
||||
async function approveHumanApproval(decision: string, comment?: string) {
|
||||
if (!state.pendingApproval) return
|
||||
|
||||
try {
|
||||
// 调用 IPC 命令发送审批响应
|
||||
await invoke('approve_human_approval', {
|
||||
execution_id: state.pendingApproval.execution_id,
|
||||
node_id: state.pendingApproval.node_id,
|
||||
decision,
|
||||
comment
|
||||
})
|
||||
|
||||
// 清除待审批状态
|
||||
state.pendingApproval = null
|
||||
} catch (error) {
|
||||
console.error('审批失败:', error)
|
||||
}
|
||||
}
|
||||
|
||||
function stopEventListener() {
|
||||
if (_eventUnlisten) {
|
||||
try {
|
||||
_eventUnlisten()
|
||||
} catch (e) {
|
||||
console.error('停止事件监听失败:', e)
|
||||
}
|
||||
_eventUnlisten = null
|
||||
}
|
||||
}
|
||||
|
||||
// ── 统计 ──
|
||||
const stats = computed(() => ({
|
||||
ideas: state.ideas.length,
|
||||
projects: state.projects.length,
|
||||
activeTasks: state.tasks.filter(t => t.status === 'in_progress').length,
|
||||
drafts: state.ideas.filter(i => i.status === 'draft').length,
|
||||
}))
|
||||
|
||||
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,
|
||||
// project actions
|
||||
loadProjects, createProject, updateProject, deleteProject,
|
||||
// task actions
|
||||
loadTasks, createTask, updateTask, deleteTask,
|
||||
// idea actions
|
||||
loadIdeas, createIdea, updateIdea, deleteIdea,
|
||||
// workflow actions
|
||||
runWorkflow, loadWorkflowExecutions, startEventListener, stopEventListener, clearLiveEvents,
|
||||
approveHumanApproval, pendingApproval: computed(() => state.pendingApproval),
|
||||
// computed
|
||||
stats,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user