P0 修复:
- B-260615-37: shell.rs 补 Stdio::piped() 修复 run_command stdout/stderr 恒空
(tokio 默认 inherit 导致 wait_with_output 读不到 pipe)
P1 功能:
- B-260615-36: 路由加 /ideas/:id + Ideas.vue 接 route.params.id + watch
(修复项目详情点「来源灵感」跳空白页)
- F-260615-08: 新增 file_info 工具(元信息: exists/size/lines/binary/dir)
- F-260615-09: 新增 append_file 工具(追加写入, RiskLevel::Medium)
- F-260615-12: 新增 search_files 工具(文件名 glob 搜索,递归,限50条)
+ search_files_recursive 辅助函数 + i18n zh/en 3工具×2命名空间
DRY/重构:
- CR-260615-09: .ai-md 样式5份→全局 src/styles/ai-md.css(75行)
AiChat.vue 删71行重复 + main.ts 引入 + typo修正(.a-md→.ai-md)
- 全量 import 路径统一为 @/ 别名(stores/composables/views ~28文件)
vite.config.ts 加 resolve.alias.{ '@': '/src' }
- i18n 批量改进: store error fallback 11处中文→t() / ToolCard ARG_LABEL
/ useAiSend queue文案 / Dashboard 空态 / Ideas.vue null守卫
- cargo check 0 error / vue-tsc 0 error
112 lines
3.5 KiB
TypeScript
112 lines
3.5 KiB
TypeScript
import { projectApi } from '@/api'
|
|
import type { ImportProjectInput } from '@/api/project'
|
|
import i18n from '@/i18n'
|
|
import { state, clearError } from './state'
|
|
|
|
// composable 外全局 i18n 实例(非 setup 上下文)
|
|
const t = ((i18n as any).global.t as (k: string) => string).bind((i18n as any).global)
|
|
|
|
/** 项目 CRUD 子 store(共享全局 state) */
|
|
export function createProjectsStore() {
|
|
async function loadProjects() {
|
|
state.loading = true
|
|
state.error = null
|
|
try {
|
|
state.projects = await projectApi.list()
|
|
} catch (e: any) {
|
|
state.error = e?.toString() ?? t('projects.err.loadFailed')
|
|
} finally {
|
|
state.loading = false
|
|
}
|
|
}
|
|
|
|
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() ?? t('projects.err.createFailed')
|
|
return null
|
|
}
|
|
}
|
|
|
|
/** 导入历史项目(选已存在目录,后端创建+绑定+探测栈+读 README 首段一步完成) */
|
|
async function importProject(input: ImportProjectInput) {
|
|
try {
|
|
const record = await projectApi.importProject(input)
|
|
await loadProjects() // 刷新列表(后端已 insert,统一走 load 避免本地数组与后端不一致)
|
|
return record
|
|
} catch (e: any) {
|
|
state.error = e?.toString() ?? t('projects.err.importFailed')
|
|
return 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) {
|
|
try {
|
|
await projectApi.delete(id) // 软删 → 回收站(可恢复)
|
|
state.projects = state.projects.filter(p => p.id !== id)
|
|
} catch (e: any) {
|
|
state.error = e?.toString() ?? t('projects.err.deleteFailed')
|
|
}
|
|
}
|
|
|
|
async function loadDeletedProjects() {
|
|
try {
|
|
state.deletedProjects = await projectApi.listDeleted()
|
|
} catch (e: any) {
|
|
state.error = e?.toString() ?? t('projects.err.loadTrashFailed')
|
|
}
|
|
}
|
|
|
|
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')
|
|
}
|
|
}
|
|
|
|
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,
|
|
// clearError 来自 state(供 barrel re-export)
|
|
clearError,
|
|
}
|
|
}
|