feat: 实现剧本创作与拆解前端工作台

This commit is contained in:
GouJ
2026-08-27 19:33:51 +08:00
parent edc003443f
commit 2ee6f049f6
56 changed files with 7597 additions and 2 deletions
+30
View File
@@ -0,0 +1,30 @@
import { computed, inject, type InjectionKey } from 'vue'
import { usePolling } from '../../composables/usePolling'
import { projectsApi } from './api'
import type { ProjectDetail } from './types'
import type { Checkpoint } from '../workflows/types'
import type { Ref } from 'vue'
/** 同一项目的两个 graph 共用一份查询,避免每个面板重复请求。 */
export function useProjectData(id: Ref<string>) {
const query = usePolling(id, async (projectId, signal) => {
const [project, checkpoints] = await Promise.all([
projectsApi.detail(projectId, signal),
projectsApi.checkpoints(projectId, signal)
])
return { project, checkpoints }
})
const project = computed<ProjectDetail | null>(() => query.data.value?.project ?? null)
const checkpoints = computed<Checkpoint[]>(() => query.data.value?.checkpoints ?? [])
return { ...query, project, checkpoints }
}
/** 项目布局向子页面提供的类型安全上下文。 */
export const projectContextKey: InjectionKey<ReturnType<typeof useProjectData>> = Symbol('project-context')
/** 读取项目上下文,错误布局在开发阶段立即暴露。 */
export function useProjectContext() {
const context = inject(projectContextKey)
if (!context) throw new Error('项目页面必须位于 ProjectLayout 中')
return context
}