- 修复 vue-tsc 3 阻断: i18n 重复 err key 删除 + store 补 relateIdeas - G1: extract_pinned_goal 单测 10 条(mention剥离/截断/空输入/全角冒号) - G2: is_empty_tool_result 单测 11 条(JSON标记/中文/英文/非空判定) - 归档: todo.md/docs/todo.md/待决策.md/待审查.md 已完成项迁入归档
165 lines
7.3 KiB
TypeScript
165 lines
7.3 KiB
TypeScript
import { reactive, computed } from 'vue'
|
||
import { listen } from '@tauri-apps/api/event'
|
||
import { createProjectsStore } from './project/projects'
|
||
import { createTasksStore } from './project/tasks'
|
||
import { createIdeasStore } from './project/ideas'
|
||
import { createWorkflowStore } from './project/workflow'
|
||
import { state, clearError } from './project/state'
|
||
import type { DfDataChangedPayload, TaskQuery } from '@/api/types'
|
||
|
||
// ── barrel 组合器(零行为变更,纯重构) ──
|
||
//
|
||
// 原 project.ts 是上帝 store(项目/任务/灵感/工作流多领域 + 越层 invoke 审批 IPC)。
|
||
// 已拆为 src/stores/project/{projects,tasks,ideas,workflow}.ts 四子 store,
|
||
// 共享 src/stores/project/state.ts 单例 state。
|
||
//
|
||
// 本文件改为组合器:内部实例化四子 store + re-export 所有成员,
|
||
// 使现有 import { useProjectStore } 的 view 零改动。
|
||
// 越层 invoke(approve_human_approval / cancel_human_node) 已下沉到 src/api/workflow.ts。
|
||
function createStore() {
|
||
const projectsStore = createProjectsStore()
|
||
const tasksStore = createTasksStore()
|
||
const ideasStore = createIdeasStore()
|
||
const workflowStore = createWorkflowStore()
|
||
|
||
// ── AR-11(方案A):数据变更联动刷新 ──
|
||
// 后端 AI 工具(create/update/delete/restore/purge/bind_directory)执行成功后 emit
|
||
// "df-data-changed" { entity, action },前端按 entity 调对应 load 刷新列表,
|
||
// 取代工具执行后需手动刷新。
|
||
//
|
||
// CR-260615-26(R-1): task 分支不再无参 loadTasks(会把 store.tasks 冲成全量,破坏
|
||
// B-260615-29「store.tasks 反映当前筛选」契约)。改为读 _activeTaskProject:
|
||
// - undefined: Tasks 视图未挂载/从未设过筛选 → 不触发 task load(避免破坏筛选,
|
||
// 让 B-29 watch/handle 主导;此时改动由用户下次进 Tasks 自然刷新)
|
||
// - 'all' : 全量拉取
|
||
// - 具体 id : 按项目拉取
|
||
// 由 Tasks.vue 经 setActiveTaskProject 在 onMounted/watch 更新本变量。
|
||
//
|
||
// F-260621-02(P1 status 下沉):新增 _activeTaskStatus 追踪当前 status 筛选,数据变更
|
||
// 联动刷新时一并下沉到后端 query(保 B-29「store.tasks 反映当前筛选」契约,
|
||
// 避免刷新把已选 status 冲掉)。
|
||
let _activeTaskProject: string | undefined = undefined
|
||
let _activeTaskStatus: string | undefined = undefined
|
||
function setActiveTaskProject(projectKey: string | undefined) {
|
||
_activeTaskProject = projectKey
|
||
}
|
||
function setActiveTaskStatus(statusKey: string | undefined) {
|
||
_activeTaskStatus = statusKey
|
||
}
|
||
// 构造当前 task 视图筛选对应的 query(供数据变更 listener 复用同一筛选拉取)
|
||
function buildActiveTaskQuery(): TaskQuery | undefined {
|
||
if (_activeTaskProject === undefined) return undefined // 视图未挂载,不触发
|
||
const query: TaskQuery = {}
|
||
if (_activeTaskProject !== 'all') query.project_id = _activeTaskProject
|
||
if (_activeTaskStatus && _activeTaskStatus !== 'all') query.status = _activeTaskStatus
|
||
return query
|
||
}
|
||
|
||
let _dataChangedUnlisten: (() => void) | null = null
|
||
|
||
async function startDataChangedListener() {
|
||
if (_dataChangedUnlisten) return _dataChangedUnlisten
|
||
_dataChangedUnlisten = await listen<DfDataChangedPayload>('df-data-changed', (event) => {
|
||
const { entity } = event.payload
|
||
// 按 entity 调对应 load 刷新(CR-260615-19:action 当前未消费,为未来 delete 本地移除等差异化刷新预留,统一 load 全量拉取)
|
||
if (entity === 'project') {
|
||
void projectsStore.loadProjects()
|
||
} else if (entity === 'task') {
|
||
// 无筛选状态(_activeTaskProject undefined)时不触发,保 B-29 筛选契约;
|
||
// 有筛选则按当前 activeProject + activeStatus 构造 query 下沉后端拉取
|
||
const q = buildActiveTaskQuery()
|
||
if (q !== undefined) {
|
||
void tasksStore.loadTasks(q)
|
||
}
|
||
} else if (entity === 'idea') {
|
||
void ideasStore.loadIdeas()
|
||
}
|
||
})
|
||
return _dataChangedUnlisten
|
||
}
|
||
|
||
function stopDataChangedListener() {
|
||
if (_dataChangedUnlisten) {
|
||
try {
|
||
_dataChangedUnlisten()
|
||
} catch (e) {
|
||
console.error('停止数据变更监听失败:', e)
|
||
}
|
||
_dataChangedUnlisten = 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({
|
||
// 状态用 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 },
|
||
get deletedProjects() { return state.deletedProjects },
|
||
clearError,
|
||
// project actions
|
||
loadProjects: projectsStore.loadProjects,
|
||
createProject: projectsStore.createProject,
|
||
importProject: projectsStore.importProject,
|
||
updateProject: projectsStore.updateProject,
|
||
deleteProject: projectsStore.deleteProject,
|
||
relocateProjectPath: projectsStore.relocateProjectPath,
|
||
loadDeletedProjects: projectsStore.loadDeletedProjects,
|
||
restoreProject: projectsStore.restoreProject,
|
||
purgeProject: projectsStore.purgeProject,
|
||
// task actions
|
||
loadTasks: tasksStore.loadTasks,
|
||
createTask: tasksStore.createTask,
|
||
updateTask: tasksStore.updateTask,
|
||
deleteTask: tasksStore.deleteTask,
|
||
// idea actions
|
||
loadIdeas: ideasStore.loadIdeas,
|
||
createIdea: ideasStore.createIdea,
|
||
updateIdea: ideasStore.updateIdea,
|
||
deleteIdea: ideasStore.deleteIdea,
|
||
evaluateIdea: ideasStore.evaluateIdea,
|
||
promoteIdea: ideasStore.promoteIdea,
|
||
relateIdeas: ideasStore.relateIdeas,
|
||
// workflow actions
|
||
runWorkflow: workflowStore.runWorkflow,
|
||
loadWorkflowExecutions: workflowStore.loadWorkflowExecutions,
|
||
startEventListener: workflowStore.startEventListener,
|
||
stopEventListener: workflowStore.stopEventListener,
|
||
clearLiveEvents: workflowStore.clearLiveEvents,
|
||
approveHumanApproval: workflowStore.approveHumanApproval,
|
||
cancelHumanApproval: workflowStore.cancelHumanApproval,
|
||
// AR-11(方案A):数据变更联动刷新监听(后端工具执行后 emit df-data-changed)
|
||
startDataChangedListener,
|
||
stopDataChangedListener,
|
||
// CR-260615-26(R-1): Tasks 视图登记当前 activeProject 筛选,供 listener 按筛选拉取
|
||
setActiveTaskProject,
|
||
// F-260621-02(P1 status 下沉):Tasks 视图登记当前 status 筛选,供 listener 复用同一筛选拉取
|
||
setActiveTaskStatus,
|
||
pendingApproval: computed(() => state.pendingApproval),
|
||
// computed
|
||
stats,
|
||
})
|
||
}
|
||
|
||
type ProjectStore = ReturnType<typeof createStore>
|
||
let _storeInstance: ProjectStore | null = null
|
||
|
||
/** 项目/任务/灵感/工作流 全局状态(单例,多组件复用同一 reactive 包装) */
|
||
export function useProjectStore(): ProjectStore {
|
||
if (_storeInstance) return _storeInstance
|
||
_storeInstance = createStore()
|
||
return _storeInstance
|
||
}
|