import { projectApi } from '@/api' import type { ImportProjectInput, ProjectQuery } from '@/api/project' import { t } from '@/i18n/i18n-helpers' import { runWithCatch } from '@/composables/useStoreAction' import { state, clearError } from './state' /** 项目 CRUD 子 store(共享全局 state) */ export function createProjectsStore() { /** * 加载未删除项目。 * 可选 query 透传(关键词/排序/分页)。不传 = 当前全量行为(向后兼容)。 */ async function loadProjects(query?: ProjectQuery) { state.loading = true state.error = null await runWithCatch(state, t('projects.err.loadFailed'), async () => { state.projects = await projectApi.list(query) }) state.loading = false } async function createProject(name: string, description = '', ideaId?: string, path?: string, stack?: string) { const record = await runWithCatch(state, t('projects.err.createFailed'), async () => { const r = await projectApi.create({ name, description, idea_id: ideaId, path, stack }) state.projects.push(r) return r }) return record ?? null } /** 导入历史项目(选已存在目录,后端创建+绑定+探测栈+读 README 首段一步完成) */ async function importProject(input: ImportProjectInput) { const record = await runWithCatch(state, t('projects.err.importFailed'), async () => { const r = await projectApi.importProject(input) await loadProjects() // 刷新列表(后端已 insert,统一走 load 避免本地数组与后端不一致) return r }) return record ?? null } 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 } } /** 重定位项目目录(后端重探测 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): Promise { // 返成功布尔(失败时 runWithCatch 已置 state.error),详情页删除据此阻断失败后的误跳转 const ok = await runWithCatch(state, t('projects.err.deleteFailed'), async () => { await projectApi.delete(id) // 软删 → 回收站(可恢复) state.projects = state.projects.filter(p => p.id !== id) return true }) return ok === true } async function loadDeletedProjects() { await runWithCatch(state, t('projects.err.loadTrashFailed'), async () => { state.deletedProjects = await projectApi.listDeleted() }) } 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() ?? t('projects.err.restoreFailed') } } // ── 归档功能 P2(V48):归档箱三动作,对标 tasks/ideas 子 store 同款 ── /** 归档/取消归档。归档=退出主列表;取消归档=从归档箱移回主列表(两端各刷一份) */ async function archiveProject(id: string, archived: boolean) { await runWithCatch(state, t('projects.err.archiveFailed'), async () => { await projectApi.archive(id, archived) if (archived) { // 从主列表移出,归档箱按需懒加载(打开归档箱时 loadArchivedProjects) state.projects = state.projects.filter(p => p.id !== id) } else { state.archivedProjects = state.archivedProjects.filter(p => p.id !== id) await loadProjects() // 取消归档回主列表 } }) } /** 加载归档项目(归档箱 Tab 数据源) */ async function loadArchivedProjects() { await runWithCatch(state, t('projects.err.loadArchivedFailed'), async () => { state.archivedProjects = await projectApi.listArchived() }) } /** 归档箱内恢复到主列表(取消归档语义的 UI 别名,动线用词更自然) */ async function unarchiveProject(id: string) { await archiveProject(id, false) } 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() ?? t('projects.err.purgeFailed') } } return { loadProjects, createProject, importProject, updateProject, deleteProject, relocateProjectPath, loadDeletedProjects, restoreProject, purgeProject, archiveProject, loadArchivedProjects, unarchiveProject, // clearError 来自 state(供 barrel re-export) clearError, } }