Files
DevFlow/src/api/project.ts
绝尘 c9b6e28433 新增: 三实体列表查询维度补全(status/关键词/排序/分页下沉后端)
任务/项目/灵感三实体新增 list_by_query 动态 WHERE(累积式 where_clauses
+params_vec 收口)+ order_by 白名单防注入 + limit/offset 钳制。命令层
list_{tasks,projects,ideas} 吃 Option<XxxQuery> 双参向后兼容(旧无参/单参
路径等价全量)。前端 Tasks/Ideas status/keyword 筛选下沉后端 query。

F-260621-02
2026-06-22 01:03:37 +08:00

148 lines
4.7 KiB
TypeScript

import { invoke } from '@tauri-apps/api/core'
import type { ProjectRecord, CreateProjectInput, AiScanResult } from './types'
/** 导入历史项目入参(选已存在目录,创建实体+绑定+探测栈一步完成) */
export interface ImportProjectInput {
/** 待导入的本地目录绝对路径(已存在) */
path: string
/** 项目名(可选,空=用目录名) */
name?: string
/** 描述(可选,空=自动读 README 首段) */
description?: string
/** 技术栈 JSON 数组字符串(可选,空=自动探测) */
stack?: string
}
/** 扫描发现的候选项目(规则发现,无 LLM)。前端预览表格只读展示。 */
export interface ScannedProjectItem {
path: string
name: string
stack: string[]
is_monorepo: boolean
/** 该目录是否已被某项目绑定(防重复,前端标记禁选) */
already_bound: boolean
}
/** 批量导入单条入参 */
export interface ImportBatchItemInput {
path: string
/** 项目名(可选,空=用目录名) */
name?: string
}
/** 批量导入单条结果 */
export interface ImportBatchItemResult {
path: string
/** 成功:导入的项目名;失败:null */
name: string | null
/** 失败原因(成功为 null) */
error: string | null
}
/** 批量导入结果(前端 toast 汇总) */
export interface ImportBatchResult {
imported: number
skipped: number
items: ImportBatchItemResult[]
}
/**
* 项目列表查询条件(F-260621-02 P2/P3)。
* 全可选;不传(或全 undefined)= 当前全量行为(deleted_at IS NULL + created_at DESC)。
* 对齐后端 df_storage::crud::ProjectQuery。
*/
export interface ProjectQuery {
/** 关键词:name/description LIKE %kw%(trim 后空字符串视为无关键词) */
keyword?: string
/** 排序:格式 "col" / "col asc" / "col desc",默认 created_at desc(列名白名单) */
order_by?: string
/** 返回上限(后端钳制 [0,200],undefined = 不加 LIMIT 全量) */
limit?: number
/** 偏移量(undefined = 0,配合 limit 分页) */
offset?: number
}
export const projectApi = {
/**
* 列出未删除项目。
* F-260621-02:可选 query(关键词/排序/分页)。不传 = 当前全量行为(向后兼容)。
*/
list(query?: ProjectQuery): Promise<ProjectRecord[]> {
return invoke('list_projects', { query })
},
create(input: CreateProjectInput): Promise<ProjectRecord> {
return invoke('create_project', { input })
},
/** 导入历史项目(选已存在目录,创建实体+绑定+探测栈一步完成) */
importProject(input: ImportProjectInput): Promise<ProjectRecord> {
return invoke('import_project', { input })
},
get(id: string): Promise<ProjectRecord | null> {
return invoke('get_project', { id })
},
update(id: string, field: string, value: string): Promise<boolean> {
return invoke('update_project', { id, field, value })
},
delete(id: string): Promise<boolean> {
return invoke('delete_project', { id })
},
listDeleted(): Promise<ProjectRecord[]> {
return invoke('list_deleted_projects')
},
restore(id: string): Promise<boolean> {
return invoke('restore_project', { id })
},
purge(id: string): Promise<boolean> {
return invoke('purge_project', { id })
},
/** 探测目录技术栈(选目录后实时预览) */
scanStack(path: string): Promise<string[]> {
return invoke('scan_project_stack', { path })
},
/** 检查目录是否已被其他项目绑定(防重复,excludeId 排除自身) */
checkBinding(path: string, excludeId?: string): Promise<ProjectRecord | null> {
return invoke('check_path_binding', { path, excludeId })
},
/** 重定位项目目录(校验+重探测 stack,返回最新记录) */
relocatePath(id: string, newPath: string): Promise<ProjectRecord> {
return invoke('relocate_project_path', { id, newPath })
},
/** 检查目录是否存在(详情页"目录是否还在") */
checkPathExists(path: string): Promise<boolean> {
return invoke('check_path_exists', { path })
},
/** AI 扫描目录,自动分析基础信息(description/stack/project_type) */
scanWithAi(path: string): Promise<AiScanResult> {
return invoke('scan_project_with_ai', { path })
},
/**
* 扫描根目录发现候选项目(规则发现,快、不跑 LLM)。
* 返回含 monorepo 子项目展开结果,前端预览表格勾选后调 importProjectsBatch。
*/
scanDirectoryForProjects(rootPath: string): Promise<ScannedProjectItem[]> {
return invoke('scan_directory_for_projects', { rootPath })
},
/**
* 批量导入历史项目 — 对勾选项并发 LLM 抽 description + 入库绑定。
* 每项独立非原子,逐项结果回传。LLM 失败 description 留空(不喂噪音)。
*/
importProjectsBatch(items: ImportBatchItemInput[]): Promise<ImportBatchResult> {
return invoke('import_projects_batch', { items })
},
}